1
0
mirror of https://github.com/json-iterator/go.git synced 2025-06-15 22:50:24 +02:00

1 Commits

Author SHA1 Message Date
787edc95b0 Revert "WIP: Tests to compare against stdlib" 2017-06-12 15:07:52 +08:00
666 changed files with 6754 additions and 53835 deletions

View File

@ -1,3 +0,0 @@
ignore:
- "output_tests/.*"

3
.gitignore vendored
View File

@ -1,3 +0,0 @@
.idea
/coverage.txt
/profile.out

10
.idea/libraries/Go_SDK.xml generated Normal file
View File

@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="Go SDK">
<CLASSES>
<root url="file:///usr/local/go/src" />
</CLASSES>
<SOURCES>
<root url="file:///usr/local/go/src" />
</SOURCES>
</library>
</component>

View File

@ -1,14 +0,0 @@
language: go
go:
- 1.8.x
- 1.x
before_install:
- go get -t -v ./...
script:
- ./test.sh
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@ -1,16 +1,6 @@
[![Sourcegraph](https://sourcegraph.com/github.com/json-iterator/go/-/badge.svg)](https://sourcegraph.com/github.com/json-iterator/go?badge)
[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/json-iterator/go)
[![Build Status](https://travis-ci.org/json-iterator/go.svg?branch=master)](https://travis-ci.org/json-iterator/go)
[![codecov](https://codecov.io/gh/json-iterator/go/branch/master/graph/badge.svg)](https://codecov.io/gh/json-iterator/go)
[![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go) [![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go)
[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/json-iterator/go/master/LICENSE)
[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/json-iterator/Lobby)
A high-performance 100% compatible drop-in replacement of "encoding/json" jsoniter (json-iterator) is fast and flexible JSON parser available in [Java](https://github.com/json-iterator/java) and [Go](https://github.com/json-iterator/go)
```
Go开发者们请加入我们,滴滴出行平台技术部 taowen@didichuxing.com
```
# Benchmark # Benchmark
@ -61,8 +51,6 @@ import "github.com/json-iterator/go"
jsoniter.Unmarshal(input, &data) jsoniter.Unmarshal(input, &data)
``` ```
[More documentation](http://jsoniter.com/migrate-from-go-std.html)
# How to get # How to get
``` ```
@ -71,12 +59,4 @@ go get github.com/json-iterator/go
# Contribution Welcomed ! # Contribution Welcomed !
Contributors
* [thockin](https://github.com/thockin)
* [mattn](https://github.com/mattn)
* [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)

1017
assert/assertions.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,10 @@
package jsoniter package jsoniter_test
import ( import (
"fmt" "fmt"
"os" "os"
"github.com/json-iterator/go"
) )
func ExampleMarshal() { func ExampleMarshal() {
@ -16,7 +18,7 @@ func ExampleMarshal() {
Name: "Reds", Name: "Reds",
Colors: []string{"Crimson", "Red", "Ruby", "Maroon"}, Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
} }
b, err := Marshal(group) b, err := jsoniter.Marshal(group)
if err != nil { if err != nil {
fmt.Println("error:", err) fmt.Println("error:", err)
} }
@ -35,7 +37,7 @@ func ExampleUnmarshal() {
Order string Order string
} }
var animals []Animal var animals []Animal
err := Unmarshal(jsonBlob, &animals) err := jsoniter.Unmarshal(jsonBlob, &animals)
if err != nil { if err != nil {
fmt.Println("error:", err) fmt.Println("error:", err)
} }
@ -43,53 +45,3 @@ func ExampleUnmarshal() {
// Output: // Output:
// [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}] // [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
} }
func ExampleConfigFastest_Marshal() {
type ColorGroup struct {
ID int
Name string
Colors []string
}
group := ColorGroup{
ID: 1,
Name: "Reds",
Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
}
stream := ConfigFastest.BorrowStream(nil)
defer ConfigFastest.ReturnStream(stream)
stream.WriteVal(group)
if stream.Error != nil {
fmt.Println("error:", stream.Error)
}
os.Stdout.Write(stream.Buffer())
// Output:
// {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
}
func ExampleConfigFastest_Unmarshal() {
var jsonBlob = []byte(`[
{"Name": "Platypus", "Order": "Monotremata"},
{"Name": "Quoll", "Order": "Dasyuromorphia"}
]`)
type Animal struct {
Name string
Order string
}
var animals []Animal
iter := ConfigFastest.BorrowIterator(jsonBlob)
defer ConfigFastest.ReturnIterator(iter)
iter.ReadVal(&animals)
if iter.Error != nil {
fmt.Println("error:", iter.Error)
}
fmt.Printf("%+v", animals)
// Output:
// [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
}
func ExampleGet() {
val := []byte(`{"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}`)
fmt.Printf(Get(val, "Colors", 0).ToString())
// Output:
// Crimson
}

View File

@ -1,278 +0,0 @@
package extra
import (
"encoding/json"
"io"
"math"
"reflect"
"strings"
"unsafe"
"github.com/json-iterator/go"
)
const maxUint = ^uint(0)
const maxInt = int(maxUint >> 1)
const minInt = -maxInt - 1
// RegisterFuzzyDecoders decode input from PHP with tolerance.
// It will handle string/number auto conversation, and treat empty [] as empty struct.
func RegisterFuzzyDecoders() {
jsoniter.RegisterExtension(&tolerateEmptyArrayExtension{})
jsoniter.RegisterTypeDecoder("string", &fuzzyStringDecoder{})
jsoniter.RegisterTypeDecoder("float32", &fuzzyFloat32Decoder{})
jsoniter.RegisterTypeDecoder("float64", &fuzzyFloat64Decoder{})
jsoniter.RegisterTypeDecoder("int", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(maxInt) || val < float64(minInt) {
iter.ReportError("fuzzy decode int", "exceed range")
return
}
*((*int)(ptr)) = int(val)
} else {
*((*int)(ptr)) = iter.ReadInt()
}
}})
jsoniter.RegisterTypeDecoder("uint", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(maxUint) || val < 0 {
iter.ReportError("fuzzy decode uint", "exceed range")
return
}
*((*uint)(ptr)) = uint(val)
} else {
*((*uint)(ptr)) = iter.ReadUint()
}
}})
jsoniter.RegisterTypeDecoder("int8", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt8) || val < float64(math.MinInt8) {
iter.ReportError("fuzzy decode int8", "exceed range")
return
}
*((*int8)(ptr)) = int8(val)
} else {
*((*int8)(ptr)) = iter.ReadInt8()
}
}})
jsoniter.RegisterTypeDecoder("uint8", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint8) || val < 0 {
iter.ReportError("fuzzy decode uint8", "exceed range")
return
}
*((*uint8)(ptr)) = uint8(val)
} else {
*((*uint8)(ptr)) = iter.ReadUint8()
}
}})
jsoniter.RegisterTypeDecoder("int16", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt16) || val < float64(math.MinInt16) {
iter.ReportError("fuzzy decode int16", "exceed range")
return
}
*((*int16)(ptr)) = int16(val)
} else {
*((*int16)(ptr)) = iter.ReadInt16()
}
}})
jsoniter.RegisterTypeDecoder("uint16", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint16) || val < 0 {
iter.ReportError("fuzzy decode uint16", "exceed range")
return
}
*((*uint16)(ptr)) = uint16(val)
} else {
*((*uint16)(ptr)) = iter.ReadUint16()
}
}})
jsoniter.RegisterTypeDecoder("int32", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt32) || val < float64(math.MinInt32) {
iter.ReportError("fuzzy decode int32", "exceed range")
return
}
*((*int32)(ptr)) = int32(val)
} else {
*((*int32)(ptr)) = iter.ReadInt32()
}
}})
jsoniter.RegisterTypeDecoder("uint32", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint32) || val < 0 {
iter.ReportError("fuzzy decode uint32", "exceed range")
return
}
*((*uint32)(ptr)) = uint32(val)
} else {
*((*uint32)(ptr)) = iter.ReadUint32()
}
}})
jsoniter.RegisterTypeDecoder("int64", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt64) || val < float64(math.MinInt64) {
iter.ReportError("fuzzy decode int64", "exceed range")
return
}
*((*int64)(ptr)) = int64(val)
} else {
*((*int64)(ptr)) = iter.ReadInt64()
}
}})
jsoniter.RegisterTypeDecoder("uint64", &fuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint64) || val < 0 {
iter.ReportError("fuzzy decode uint64", "exceed range")
return
}
*((*uint64)(ptr)) = uint64(val)
} else {
*((*uint64)(ptr)) = iter.ReadUint64()
}
}})
}
type tolerateEmptyArrayExtension struct {
jsoniter.DummyExtension
}
func (extension *tolerateEmptyArrayExtension) DecorateDecoder(typ reflect.Type, decoder jsoniter.ValDecoder) jsoniter.ValDecoder {
if typ.Kind() == reflect.Struct || typ.Kind() == reflect.Map {
return &tolerateEmptyArrayDecoder{decoder}
}
return decoder
}
type tolerateEmptyArrayDecoder struct {
valDecoder jsoniter.ValDecoder
}
func (decoder *tolerateEmptyArrayDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if iter.WhatIsNext() == jsoniter.ArrayValue {
iter.Skip()
newIter := iter.Pool().BorrowIterator([]byte("{}"))
defer iter.Pool().ReturnIterator(newIter)
decoder.valDecoder.Decode(ptr, newIter)
} else {
decoder.valDecoder.Decode(ptr, iter)
}
}
type fuzzyStringDecoder struct {
}
func (decoder *fuzzyStringDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
switch valueType {
case jsoniter.NumberValue:
var number json.Number
iter.ReadVal(&number)
*((*string)(ptr)) = string(number)
case jsoniter.StringValue:
*((*string)(ptr)) = iter.ReadString()
default:
iter.ReportError("fuzzyStringDecoder", "not number or string")
}
}
type fuzzyIntegerDecoder struct {
fun func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator)
}
func (decoder *fuzzyIntegerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
var str string
switch valueType {
case jsoniter.NumberValue:
var number json.Number
iter.ReadVal(&number)
str = string(number)
case jsoniter.StringValue:
str = iter.ReadString()
case jsoniter.BoolValue:
if iter.ReadBool() {
str = "1"
} else {
str = "0"
}
default:
iter.ReportError("fuzzyIntegerDecoder", "not number or string")
}
newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Pool().ReturnIterator(newIter)
isFloat := strings.IndexByte(str, '.') != -1
decoder.fun(isFloat, ptr, newIter)
if newIter.Error != nil && newIter.Error != io.EOF {
iter.Error = newIter.Error
}
}
type fuzzyFloat32Decoder struct {
}
func (decoder *fuzzyFloat32Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
var str string
switch valueType {
case jsoniter.NumberValue:
*((*float32)(ptr)) = iter.ReadFloat32()
case jsoniter.StringValue:
str = iter.ReadString()
newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Pool().ReturnIterator(newIter)
*((*float32)(ptr)) = newIter.ReadFloat32()
if newIter.Error != nil && newIter.Error != io.EOF {
iter.Error = newIter.Error
}
case jsoniter.BoolValue:
// support bool to float32
if iter.ReadBool() {
*((*float32)(ptr)) = 1
} else {
*((*float32)(ptr)) = 0
}
default:
iter.ReportError("fuzzyFloat32Decoder", "not number or string")
}
}
type fuzzyFloat64Decoder struct {
}
func (decoder *fuzzyFloat64Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
var str string
switch valueType {
case jsoniter.NumberValue:
*((*float64)(ptr)) = iter.ReadFloat64()
case jsoniter.StringValue:
str = iter.ReadString()
newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Pool().ReturnIterator(newIter)
*((*float64)(ptr)) = newIter.ReadFloat64()
if newIter.Error != nil && newIter.Error != io.EOF {
iter.Error = newIter.Error
}
case jsoniter.BoolValue:
// support bool to float64
if iter.ReadBool() {
*((*float64)(ptr)) = 1
} else {
*((*float64)(ptr)) = 0
}
default:
iter.ReportError("fuzzyFloat32Decoder", "not number or string")
}
}

View File

@ -1,359 +0,0 @@
package extra
import (
"testing"
"github.com/json-iterator/go"
"github.com/stretchr/testify/require"
)
func init() {
RegisterFuzzyDecoders()
}
func Test_any_to_string(t *testing.T) {
should := require.New(t)
var val string
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal("100", val)
should.Nil(jsoniter.UnmarshalFromString("10", &val))
should.Equal("10", val)
should.Nil(jsoniter.UnmarshalFromString("10.1", &val))
should.Equal("10.1", val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal("10.1", val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
}
func Test_any_to_int64(t *testing.T) {
should := require.New(t)
var val int64
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(int64(100), val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(int64(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(int64(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(int64(10), val)
// bool part
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(int64(0), val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(int64(1), val)
should.Nil(jsoniter.UnmarshalFromString(`-10`, &val))
should.Equal(int64(-10), val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
// large float to int
should.NotNil(jsoniter.UnmarshalFromString(`1234512345123451234512345.0`, &val))
}
func Test_any_to_int(t *testing.T) {
should := require.New(t)
var val int
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(100, val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(10, val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(10, val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(10, val)
// bool part
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(0, val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(1, val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
// large float to int
should.NotNil(jsoniter.UnmarshalFromString(`1234512345123451234512345.0`, &val))
}
func Test_any_to_int16(t *testing.T) {
should := require.New(t)
var val int16
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(int16(100), val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(int16(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(int16(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(int16(10), val)
// bool part
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(int16(0), val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(int16(1), val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
// large float to int
should.NotNil(jsoniter.UnmarshalFromString(`1234512345123451234512345.0`, &val))
}
func Test_any_to_int32(t *testing.T) {
should := require.New(t)
var val int32
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(int32(100), val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(int32(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(int32(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(int32(10), val)
// bool part
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(int32(0), val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(int32(1), val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
// large float to int
should.NotNil(jsoniter.UnmarshalFromString(`1234512345123451234512345.0`, &val))
}
func Test_any_to_int8(t *testing.T) {
should := require.New(t)
var val int8
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(int8(100), val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(int8(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(int8(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(int8(10), val)
// bool part
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(int8(0), val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(int8(1), val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
// large float to int
should.NotNil(jsoniter.UnmarshalFromString(`1234512345123451234512345.0`, &val))
}
func Test_any_to_uint8(t *testing.T) {
should := require.New(t)
var val uint8
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(uint8(100), val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(uint8(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(uint8(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(uint8(10), val)
// bool part
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(uint8(0), val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(uint8(1), val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
// large float to int
should.NotNil(jsoniter.UnmarshalFromString(`1234512345123451234512345.0`, &val))
}
func Test_any_to_uint64(t *testing.T) {
should := require.New(t)
var val uint64
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(uint64(100), val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(uint64(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(uint64(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(uint64(10), val)
// bool part
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(uint64(0), val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(uint64(1), val)
// TODO fix?
should.NotNil(jsoniter.UnmarshalFromString(`-10`, &val))
should.Equal(uint64(0), val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
// large float to int
should.NotNil(jsoniter.UnmarshalFromString(`1234512345123451234512345.0`, &val))
}
func Test_any_to_uint32(t *testing.T) {
should := require.New(t)
var val uint32
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(uint32(100), val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(uint32(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(uint32(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(uint32(10), val)
// bool part
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(uint32(0), val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(uint32(1), val)
// TODO fix?
should.NotNil(jsoniter.UnmarshalFromString(`-10`, &val))
should.Equal(uint32(0), val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
// large float to int
should.NotNil(jsoniter.UnmarshalFromString(`1234512345123451234512345.0`, &val))
}
func Test_any_to_uint16(t *testing.T) {
should := require.New(t)
var val uint16
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(uint16(100), val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(uint16(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(uint16(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(uint16(10), val)
// bool part
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(uint16(0), val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(uint16(1), val)
// TODO fix?
should.NotNil(jsoniter.UnmarshalFromString(`-10`, &val))
should.Equal(uint16(0), val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
// large float to int
should.NotNil(jsoniter.UnmarshalFromString(`1234512345123451234512345.0`, &val))
}
func Test_any_to_uint(t *testing.T) {
should := require.New(t)
var val uint
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(uint(100), val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(uint(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(uint(10), val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(uint(10), val)
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(uint(0), val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(uint(1), val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
// large float to int
should.NotNil(jsoniter.UnmarshalFromString(`1234512345123451234512345.0`, &val))
}
func Test_any_to_float32(t *testing.T) {
should := require.New(t)
var val float32
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(float32(100), val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(float32(10.1), val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(float32(10.1), val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(float32(10), val)
// bool part
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(float32(0), val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(float32(1), val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
}
func Test_any_to_float64(t *testing.T) {
should := require.New(t)
var val float64
should.Nil(jsoniter.UnmarshalFromString(`"100"`, &val))
should.Equal(float64(100), val)
should.Nil(jsoniter.UnmarshalFromString(`"10.1"`, &val))
should.Equal(float64(10.1), val)
should.Nil(jsoniter.UnmarshalFromString(`10.1`, &val))
should.Equal(float64(10.1), val)
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
should.Equal(float64(10), val)
// bool part
should.Nil(jsoniter.UnmarshalFromString(`false`, &val))
should.Equal(float64(0), val)
should.Nil(jsoniter.UnmarshalFromString(`true`, &val))
should.Equal(float64(1), val)
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
}
func Test_empty_array_as_map(t *testing.T) {
should := require.New(t)
var val map[string]interface{}
should.Nil(jsoniter.UnmarshalFromString(`[]`, &val))
should.Equal(map[string]interface{}{}, val)
}
func Test_empty_array_as_object(t *testing.T) {
should := require.New(t)
var val struct{}
should.Nil(jsoniter.UnmarshalFromString(`[]`, &val))
should.Equal(struct{}{}, val)
}
func Test_bad_case(t *testing.T) {
var jsonstr = `
{
"extra_type": 181760,
"combo_type": 0,
"trigger_time_ms": 1498800398000,
"_create_time": "2017-06-16 11:21:39",
"_msg_type": 41000
}
`
type OrderEventRequestParams struct {
ExtraType uint64 `json:"extra_type"`
}
var a OrderEventRequestParams
err := jsoniter.UnmarshalFromString(jsonstr, &a)
should := require.New(t)
should.Nil(err)
}

View File

@ -1,41 +0,0 @@
package extra
import (
"github.com/json-iterator/go"
"unicode"
)
// SetNamingStrategy rename struct fields uniformly
func SetNamingStrategy(translate func(string) string) {
jsoniter.RegisterExtension(&namingStrategyExtension{jsoniter.DummyExtension{}, translate})
}
type namingStrategyExtension struct {
jsoniter.DummyExtension
translate func(string) string
}
func (extension *namingStrategyExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
for _, binding := range structDescriptor.Fields {
binding.ToNames = []string{extension.translate(binding.Field.Name)}
binding.FromNames = []string{extension.translate(binding.Field.Name)}
}
}
// LowerCaseWithUnderscores one strategy to SetNamingStrategy for. It will change HelloWorld to hello_world.
func LowerCaseWithUnderscores(name string) string {
newName := []rune{}
for i, c := range name {
if i == 0 {
newName = append(newName, unicode.ToLower(c))
} else {
if unicode.IsUpper(c) {
newName = append(newName, '_')
newName = append(newName, unicode.ToLower(c))
} else {
newName = append(newName, c)
}
}
}
return string(newName)
}

View File

@ -1,23 +0,0 @@
package extra
import (
"github.com/json-iterator/go"
"github.com/stretchr/testify/require"
"testing"
)
func Test_lower_case_with_underscores(t *testing.T) {
should := require.New(t)
should.Equal("hello_world", LowerCaseWithUnderscores("helloWorld"))
should.Equal("hello_world", LowerCaseWithUnderscores("HelloWorld"))
SetNamingStrategy(LowerCaseWithUnderscores)
output, err := jsoniter.Marshal(struct {
UserName string
FirstLanguage string
}{
UserName: "taowen",
FirstLanguage: "Chinese",
})
should.Nil(err)
should.Equal(`{"user_name":"taowen","first_language":"Chinese"}`, string(output))
}

View File

@ -1,25 +0,0 @@
package extra
import (
"github.com/json-iterator/go"
"unicode"
)
// SupportPrivateFields include private fields when encoding/decoding
func SupportPrivateFields() {
jsoniter.RegisterExtension(&privateFieldsExtension{})
}
type privateFieldsExtension struct {
jsoniter.DummyExtension
}
func (extension *privateFieldsExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
for _, binding := range structDescriptor.Fields {
isPrivate := unicode.IsLower(rune(binding.Field.Name[0]))
if isPrivate {
binding.FromNames = []string{binding.Field.Name}
binding.ToNames = []string{binding.Field.Name}
}
}
}

View File

@ -1,18 +0,0 @@
package extra
import (
"github.com/json-iterator/go"
"github.com/stretchr/testify/require"
"testing"
)
func Test_private_fields(t *testing.T) {
type TestObject struct {
field1 string
}
SupportPrivateFields()
should := require.New(t)
obj := TestObject{}
should.Nil(jsoniter.UnmarshalFromString(`{"field1":"Hello"}`, &obj))
should.Equal("Hello", obj.field1)
}

View File

@ -1,34 +0,0 @@
package extra
import (
"github.com/json-iterator/go"
"time"
"unsafe"
)
// RegisterTimeAsInt64Codec encode/decode time since number of unit since epoch. the precision is the unit.
func RegisterTimeAsInt64Codec(precision time.Duration) {
jsoniter.RegisterTypeEncoder("time.Time", &timeAsInt64Codec{precision})
jsoniter.RegisterTypeDecoder("time.Time", &timeAsInt64Codec{precision})
}
type timeAsInt64Codec struct {
precision time.Duration
}
func (codec *timeAsInt64Codec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
nanoseconds := iter.ReadInt64() * codec.precision.Nanoseconds()
*((*time.Time)(ptr)) = time.Unix(0, nanoseconds)
}
func (codec *timeAsInt64Codec) IsEmpty(ptr unsafe.Pointer) bool {
ts := *((*time.Time)(ptr))
return ts.UnixNano() == 0
}
func (codec *timeAsInt64Codec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
ts := *((*time.Time)(ptr))
stream.WriteInt64(ts.UnixNano() / codec.precision.Nanoseconds())
}
func (codec *timeAsInt64Codec) EncodeInterface(val interface{}, stream *jsoniter.Stream) {
jsoniter.WriteToStream(val, stream, codec)
}

View File

@ -1,31 +0,0 @@
package extra
import (
"github.com/json-iterator/go"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func Test_time_as_int64(t *testing.T) {
should := require.New(t)
RegisterTimeAsInt64Codec(time.Nanosecond)
output, err := jsoniter.Marshal(time.Unix(1497952257, 1002))
should.Nil(err)
should.Equal("1497952257000001002", string(output))
var val time.Time
should.Nil(jsoniter.Unmarshal(output, &val))
should.Equal(int64(1497952257000001002), val.UnixNano())
}
func Test_time_as_int64_keep_microsecond(t *testing.T) {
t.Skip("conflict")
should := require.New(t)
RegisterTimeAsInt64Codec(time.Microsecond)
output, err := jsoniter.Marshal(time.Unix(1, 1002))
should.Nil(err)
should.Equal("1000001", string(output))
var val time.Time
should.Nil(jsoniter.Unmarshal(output, &val))
should.Equal(int64(1000001000), val.UnixNano())
}

View File

@ -1,19 +1,65 @@
// Package jsoniter implements encoding and decoding of JSON as defined in
// RFC 4627 and provides interfaces with identical syntax of standard lib encoding/json.
// Converting from encoding/json to jsoniter is no more than replacing the package with jsoniter
// and variable type declarations (if any).
// jsoniter interfaces gives 100% compatibility with code using standard lib.
//
// "JSON and Go"
// (https://golang.org/doc/articles/json_and_go.html)
// gives a description of how Marshal/Unmarshal operate
// between arbitrary or predefined json objects and bytes,
// and it applies to jsoniter.Marshal/Unmarshal as well.
package jsoniter package jsoniter
import ( import (
"bytes" "bytes"
"encoding/json"
"errors"
"io" "io"
"reflect"
"unsafe"
) )
// RawMessage to make replace json with jsoniter
type RawMessage []byte
// Unmarshal adapts to json/encoding Unmarshal API // Unmarshal adapts to json/encoding Unmarshal API
// //
// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. // Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v.
// Refer to https://godoc.org/encoding/json#Unmarshal for more information // Refer to https://godoc.org/encoding/json#Unmarshal for more information
func Unmarshal(data []byte, v interface{}) error { func Unmarshal(data []byte, v interface{}) error {
return ConfigDefault.Unmarshal(data, v) data = data[:lastNotSpacePos(data)]
iter := ParseBytes(data)
typ := reflect.TypeOf(v)
if typ.Kind() != reflect.Ptr {
// return non-pointer error
return errors.New("the second param must be ptr type")
}
iter.ReadVal(v)
if iter.head == iter.tail {
iter.loadMore()
}
if iter.Error == io.EOF {
return nil
}
if iter.Error == nil {
iter.reportError("Unmarshal", "there are bytes left after unmarshal")
}
return iter.Error
}
// UnmarshalAny adapts to
func UnmarshalAny(data []byte) (Any, error) {
data = data[:lastNotSpacePos(data)]
iter := ParseBytes(data)
any := iter.ReadAny()
if iter.head == iter.tail {
iter.loadMore()
}
if iter.Error == io.EOF {
return any, nil
}
if iter.Error == nil {
iter.reportError("UnmarshalAny", "there are bytes left after unmarshal")
}
return any, iter.Error
} }
func lastNotSpacePos(data []byte) int { func lastNotSpacePos(data []byte) int {
@ -25,14 +71,38 @@ func lastNotSpacePos(data []byte) int {
return 0 return 0
} }
// UnmarshalFromString convenient method to read from string instead of []byte
func UnmarshalFromString(str string, v interface{}) error { func UnmarshalFromString(str string, v interface{}) error {
return ConfigDefault.UnmarshalFromString(str, v) data := []byte(str)
data = data[:lastNotSpacePos(data)]
iter := ParseBytes(data)
iter.ReadVal(v)
if iter.head == iter.tail {
iter.loadMore()
}
if iter.Error == io.EOF {
return nil
}
if iter.Error == nil {
iter.reportError("UnmarshalFromString", "there are bytes left after unmarshal")
}
return iter.Error
} }
// Get quick method to get value from deeply nested JSON structure func UnmarshalAnyFromString(str string) (Any, error) {
func Get(data []byte, path ...interface{}) Any { data := []byte(str)
return ConfigDefault.Get(data, path...) data = data[:lastNotSpacePos(data)]
iter := ParseBytes(data)
any := iter.ReadAny()
if iter.head == iter.tail {
iter.loadMore()
}
if iter.Error == io.EOF {
return any, nil
}
if iter.Error == nil {
iter.reportError("UnmarshalAnyFromString", "there are bytes left after unmarshal")
}
return nil, iter.Error
} }
// Marshal adapts to json/encoding Marshal API // Marshal adapts to json/encoding Marshal API
@ -40,37 +110,40 @@ func Get(data []byte, path ...interface{}) Any {
// Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API // Marshal returns the JSON encoding of v, adapts to json/encoding Marshal API
// Refer to https://godoc.org/encoding/json#Marshal for more information // Refer to https://godoc.org/encoding/json#Marshal for more information
func Marshal(v interface{}) ([]byte, error) { func Marshal(v interface{}) ([]byte, error) {
return ConfigDefault.Marshal(v) stream := NewStream(nil, 256)
stream.WriteVal(v)
if stream.Error != nil {
return nil, stream.Error
}
return stream.Buffer(), nil
} }
// MarshalIndent same as json.MarshalIndent. Prefix is not supported.
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
return ConfigDefault.MarshalIndent(v, prefix, indent)
}
// MarshalToString convenient method to write as string instead of []byte
func MarshalToString(v interface{}) (string, error) { func MarshalToString(v interface{}) (string, error) {
return ConfigDefault.MarshalToString(v) buf, err := Marshal(v)
if err != nil {
return "", err
}
return string(buf), nil
} }
// NewDecoder adapts to json/stream NewDecoder API. // NewDecoder adapts to json/stream NewDecoder API.
// //
// NewDecoder returns a new decoder that reads from r. // NewDecoder returns a new decoder that reads from r.
// //
// Instead of a json/encoding Decoder, an Decoder is returned // Instead of a json/encoding Decoder, an AdaptedDecoder is returned
// Refer to https://godoc.org/encoding/json#NewDecoder for more information // Refer to https://godoc.org/encoding/json#NewDecoder for more information
func NewDecoder(reader io.Reader) *Decoder { func NewDecoder(reader io.Reader) *AdaptedDecoder {
return ConfigDefault.NewDecoder(reader) iter := Parse(reader, 512)
return &AdaptedDecoder{iter}
} }
// Decoder reads and decodes JSON values from an input stream. // AdaptedDecoder reads and decodes JSON values from an input stream.
// Decoder provides identical APIs with json/stream Decoder (Token() and UseNumber() are in progress) // AdaptedDecoder provides identical APIs with json/stream Decoder (Token() and UseNumber() are in progress)
type Decoder struct { type AdaptedDecoder struct {
iter *Iterator iter *Iterator
} }
// Decode decode JSON into interface{} func (adapter *AdaptedDecoder) Decode(obj interface{}) error {
func (adapter *Decoder) Decode(obj interface{}) error {
adapter.iter.ReadVal(obj) adapter.iter.ReadVal(obj)
err := adapter.iter.Error err := adapter.iter.Error
if err == io.EOF { if err == io.EOF {
@ -79,49 +152,40 @@ func (adapter *Decoder) Decode(obj interface{}) error {
return adapter.iter.Error return adapter.iter.Error
} }
// More is there more? func (adapter *AdaptedDecoder) More() bool {
func (adapter *Decoder) More() bool {
return adapter.iter.head != adapter.iter.tail return adapter.iter.head != adapter.iter.tail
} }
// Buffered remaining buffer func (adapter *AdaptedDecoder) Buffered() io.Reader {
func (adapter *Decoder) Buffered() io.Reader {
remaining := adapter.iter.buf[adapter.iter.head:adapter.iter.tail] remaining := adapter.iter.buf[adapter.iter.head:adapter.iter.tail]
return bytes.NewReader(remaining) return bytes.NewReader(remaining)
} }
// UseNumber for number JSON element, use float64 or json.NumberValue (alias of string) func (decoder *AdaptedDecoder) UseNumber() {
func (adapter *Decoder) UseNumber() { RegisterTypeDecoder("interface {}", func(ptr unsafe.Pointer, iter *Iterator) {
origCfg := adapter.iter.cfg.configBeforeFrozen if iter.WhatIsNext() == Number {
origCfg.UseNumber = true *((*interface{})(ptr)) = json.Number(iter.readNumberAsString())
adapter.iter.cfg = origCfg.Froze().(*frozenConfig) } else {
*((*interface{})(ptr)) = iter.Read()
}
})
} }
// NewEncoder same as json.NewEncoder func NewEncoder(writer io.Writer) *AdaptedEncoder {
func NewEncoder(writer io.Writer) *Encoder { stream := NewStream(writer, 512)
return ConfigDefault.NewEncoder(writer) return &AdaptedEncoder{stream}
} }
// Encoder same as json.Encoder type AdaptedEncoder struct {
type Encoder struct {
stream *Stream stream *Stream
} }
// Encode encode interface{} as JSON to io.Writer func (adapter *AdaptedEncoder) Encode(val interface{}) error {
func (adapter *Encoder) Encode(val interface{}) error {
adapter.stream.WriteVal(val) adapter.stream.WriteVal(val)
adapter.stream.Flush() adapter.stream.Flush()
return adapter.stream.Error return adapter.stream.Error
} }
// SetIndent set the indention. Prefix is not supported func (adapter *AdaptedEncoder) SetIndent(prefix, indent string) {
func (adapter *Encoder) SetIndent(prefix, indent string) { adapter.stream.IndentionStep = len(indent)
adapter.stream.cfg.indentionStep = len(indent)
}
// SetEscapeHTML escape html by default, set to false to disable
func (adapter *Encoder) SetEscapeHTML(escapeHTML bool) {
config := adapter.stream.cfg.configBeforeFrozen
config.EscapeHTML = escapeHTML
adapter.stream.cfg = config.Froze().(*frozenConfig)
} }

View File

@ -2,16 +2,12 @@ package jsoniter
import ( import (
"fmt" "fmt"
"io"
"reflect" "reflect"
) )
// Any generic object representation.
// The lazy json implementation holds []byte and parse lazily.
type Any interface { type Any interface {
LastError() error LastError() error
ValueType() ValueType ValueType() ValueType
MustBeValid() Any
ToBool() bool ToBool() bool
ToInt() int ToInt() int
ToInt32() int32 ToInt32() int32
@ -22,13 +18,18 @@ type Any interface {
ToFloat32() float32 ToFloat32() float32
ToFloat64() float64 ToFloat64() float64
ToString() string ToString() string
ToVal(val interface{})
Get(path ...interface{}) Any Get(path ...interface{}) Any
// TODO: add Set
Size() int Size() int
Keys() []string Keys() []string
IterateObject() (func() (string, Any, bool), bool)
IterateArray() (func() (Any, bool), bool)
GetArray() []Any
SetArray(newList []Any) bool
GetObject() map[string]Any
SetObject(map[string]Any) bool
GetInterface() interface{} GetInterface() interface{}
WriteTo(stream *Stream) WriteTo(stream *Stream)
Parse() *Iterator
} }
type baseAny struct{} type baseAny struct{}
@ -45,41 +46,54 @@ func (any *baseAny) Keys() []string {
return []string{} return []string{}
} }
func (any *baseAny) ToVal(obj interface{}) { func (any *baseAny) IterateObject() (func() (string, Any, bool), bool) {
panic("not implemented") return nil, false
}
func (any *baseAny) IterateArray() (func() (Any, bool), bool) {
return nil, false
}
func (any *baseAny) GetArray() []Any {
return []Any{}
}
func (any *baseAny) SetArray(newList []Any) bool {
return false
}
func (any *baseAny) GetObject() map[string]Any {
return map[string]Any{}
}
func (any *baseAny) SetObject(map[string]Any) bool {
return false
} }
// WrapInt32 turn int32 into Any interface
func WrapInt32(val int32) Any { func WrapInt32(val int32) Any {
return &int32Any{baseAny{}, val} return &int32Any{baseAny{}, val}
} }
// WrapInt64 turn int64 into Any interface
func WrapInt64(val int64) Any { func WrapInt64(val int64) Any {
return &int64Any{baseAny{}, val} return &int64Any{baseAny{}, val}
} }
// WrapUint32 turn uint32 into Any interface
func WrapUint32(val uint32) Any { func WrapUint32(val uint32) Any {
return &uint32Any{baseAny{}, val} return &uint32Any{baseAny{}, val}
} }
// WrapUint64 turn uint64 into Any interface
func WrapUint64(val uint64) Any { func WrapUint64(val uint64) Any {
return &uint64Any{baseAny{}, val} return &uint64Any{baseAny{}, val}
} }
// WrapFloat64 turn float64 into Any interface
func WrapFloat64(val float64) Any { func WrapFloat64(val float64) Any {
return &floatAny{baseAny{}, val} return &floatAny{baseAny{}, val}
} }
// WrapString turn string into Any interface
func WrapString(val string) Any { func WrapString(val string) Any {
return &stringAny{baseAny{}, val} return &stringAny{baseAny{}, nil, val}
} }
// Wrap turn a go object into Any interface
func Wrap(val interface{}) Any { func Wrap(val interface{}) Any {
if val == nil { if val == nil {
return &nilAny{} return &nilAny{}
@ -88,8 +102,8 @@ func Wrap(val interface{}) Any {
if isAny { if isAny {
return asAny return asAny
} }
typ := reflect.TypeOf(val) type_ := reflect.TypeOf(val)
switch typ.Kind() { switch type_.Kind() {
case reflect.Slice: case reflect.Slice:
return wrapArray(val) return wrapArray(val)
case reflect.Struct: case reflect.Struct:
@ -125,118 +139,166 @@ func Wrap(val interface{}) Any {
case reflect.Bool: case reflect.Bool:
if val.(bool) == true { if val.(bool) == true {
return &trueAny{} return &trueAny{}
} else {
return &falseAny{}
} }
return &falseAny{}
} }
return &invalidAny{baseAny{}, fmt.Errorf("unsupported type: %v", typ)} return &invalidAny{baseAny{}, fmt.Errorf("unsupported type: %v", type_)}
} }
// ReadAny read next JSON element as an Any object. It is a better json.RawMessage.
func (iter *Iterator) ReadAny() Any { func (iter *Iterator) ReadAny() Any {
return iter.readAny() return iter.readAny(nil)
} }
func (iter *Iterator) readAny() Any { func (iter *Iterator) readAny(reusableIter *Iterator) Any {
c := iter.nextToken() c := iter.nextToken()
switch c { switch c {
case '"': case '"':
iter.unreadByte() return iter.readStringAny(reusableIter)
return &stringAny{baseAny{}, iter.ReadString()}
case 'n': case 'n':
iter.skipThreeBytes('u', 'l', 'l') // null iter.skipFixedBytes(3) // null
return &nilAny{} return &nilAny{}
case 't': case 't':
iter.skipThreeBytes('r', 'u', 'e') // true iter.skipFixedBytes(3) // true
return &trueAny{} return &trueAny{}
case 'f': case 'f':
iter.skipFourBytes('a', 'l', 's', 'e') // false iter.skipFixedBytes(4) // false
return &falseAny{} return &falseAny{}
case '{': case '{':
return iter.readObjectAny() return iter.readObjectAny(reusableIter)
case '[': case '[':
return iter.readArrayAny() return iter.readArrayAny(reusableIter)
case '-':
return iter.readNumberAny(false)
default: default:
return iter.readNumberAny(true) return iter.readNumberAny(reusableIter, c)
} }
} }
func (iter *Iterator) readNumberAny(positive bool) Any { func (iter *Iterator) readNumberAny(reusableIter *Iterator, firstByte byte) Any {
iter.startCapture(iter.head - 1) dotFound := false
iter.skipNumber() lazyBuf := make([]byte, 1, 8)
lazyBuf := iter.stopCapture() lazyBuf[0] = firstByte
return &numberLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} for {
} for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
func (iter *Iterator) readObjectAny() Any { if c == '.' {
iter.startCapture(iter.head - 1) dotFound = true
iter.skipObject() continue
lazyBuf := iter.stopCapture() }
return &objectLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} switch c {
} case ' ', '\n', '\r', '\t', ',', '}', ']':
lazyBuf = append(lazyBuf, iter.buf[iter.head:i]...)
func (iter *Iterator) readArrayAny() Any { iter.head = i
iter.startCapture(iter.head - 1) if dotFound {
iter.skipArray() return &float64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
lazyBuf := iter.stopCapture() } else {
return &arrayLazyAny{baseAny{}, iter.cfg, lazyBuf, nil} if firstByte == '-' {
} return &int64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
} else {
func locateObjectField(iter *Iterator, target string) []byte { return &uint64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
var found []byte }
iter.ReadObjectCB(func(iter *Iterator, field string) bool { }
if field == target { }
found = iter.SkipAndReturnBytes()
return false
} }
iter.Skip() lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
return true if !iter.loadMore() {
}) iter.head = iter.tail
return found if dotFound {
} return &float64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
} else {
func locateArrayElement(iter *Iterator, target int) []byte { if firstByte == '-' {
var found []byte return &int64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
n := 0 } else {
iter.ReadArrayCB(func(iter *Iterator) bool { return &uint64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
if n == target { }
found = iter.SkipAndReturnBytes()
return false
}
iter.Skip()
n++
return true
})
return found
}
func locatePath(iter *Iterator, path []interface{}) Any {
for i, pathKeyObj := range path {
switch pathKey := pathKeyObj.(type) {
case string:
valueBytes := locateObjectField(iter, pathKey)
if valueBytes == nil {
return newInvalidAny(path[i:])
} }
iter.ResetBytes(valueBytes)
case int:
valueBytes := locateArrayElement(iter, pathKey)
if valueBytes == nil {
return newInvalidAny(path[i:])
}
iter.ResetBytes(valueBytes)
case int32:
if '*' == pathKey {
return iter.readAny().Get(path[i:]...)
}
return newInvalidAny(path[i:])
default:
return newInvalidAny(path[i:])
} }
} }
if iter.Error != nil && iter.Error != io.EOF { }
return &invalidAny{baseAny{}, iter.Error}
} func (iter *Iterator) readStringAny(reusableIter *Iterator) Any {
return iter.readAny() lazyBuf := make([]byte, 1, 8)
lazyBuf[0] = '"'
for {
end, escaped := iter.findStringEnd()
if end == -1 {
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.reportError("readStringAny", "incomplete string")
return &invalidAny{}
}
if escaped {
iter.head = 1 // skip the first char as last char read is \
}
} else {
lazyBuf = append(lazyBuf, iter.buf[iter.head:end]...)
iter.head = end
return &stringLazyAny{baseAny{}, lazyBuf, reusableIter, nil, ""}
}
}
}
func (iter *Iterator) readObjectAny(reusableIter *Iterator) Any {
level := 1
lazyBuf := make([]byte, 1, 32)
lazyBuf[0] = '{'
for {
start := iter.head
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '{': // If open symbol, increase level
level++
case '}': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
lazyBuf = append(lazyBuf, iter.buf[start:iter.head]...)
return &objectLazyAny{baseAny{}, lazyBuf, reusableIter, nil, nil, lazyBuf}
}
}
}
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.reportError("skipObject", "incomplete object")
return &invalidAny{}
}
}
}
func (iter *Iterator) readArrayAny(reusableIter *Iterator) Any {
level := 1
lazyBuf := make([]byte, 1, 32)
lazyBuf[0] = '['
for {
start := iter.head
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '[': // If open symbol, increase level
level++
case ']': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
lazyBuf = append(lazyBuf, iter.buf[start:iter.head]...)
return &arrayLazyAny{baseAny{}, lazyBuf, reusableIter, nil, nil, lazyBuf}
}
}
}
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.reportError("skipArray", "incomplete array")
return &invalidAny{}
}
}
} }

View File

@ -1,23 +1,108 @@
package jsoniter package jsoniter
import ( import (
"fmt"
"reflect" "reflect"
"unsafe" "unsafe"
) )
type arrayLazyAny struct { type arrayLazyAny struct {
baseAny baseAny
cfg *frozenConfig buf []byte
buf []byte iter *Iterator
err error err error
cache []Any
remaining []byte
} }
func (any *arrayLazyAny) ValueType() ValueType { func (any *arrayLazyAny) ValueType() ValueType {
return ArrayValue return Array
} }
func (any *arrayLazyAny) MustBeValid() Any { func (any *arrayLazyAny) Parse() *Iterator {
return any iter := any.iter
if iter == nil {
iter = NewIterator()
any.iter = iter
}
iter.ResetBytes(any.remaining)
return iter
}
func (any *arrayLazyAny) fillCacheUntil(target int) Any {
if any.remaining == nil {
if target >= len(any.cache) {
return nil
}
return any.cache[target]
}
if any.cache == nil {
any.cache = make([]Any, 0, 8)
}
i := len(any.cache)
if target < i {
return any.cache[target]
}
iter := any.Parse()
if len(any.remaining) == len(any.buf) {
iter.head++
c := iter.nextToken()
if c != ']' {
iter.unreadByte()
element := iter.readAny(iter)
any.cache = append(any.cache, element)
if target == 0 {
any.remaining = iter.buf[iter.head:]
any.err = iter.Error
return element
}
i = 1
} else {
any.remaining = nil
any.err = iter.Error
return nil
}
}
for iter.nextToken() == ',' {
element := iter.readAny(iter)
any.cache = append(any.cache, element)
if i == target {
any.remaining = iter.buf[iter.head:]
any.err = iter.Error
return element
}
i++
}
any.remaining = nil
any.err = iter.Error
return nil
}
func (any *arrayLazyAny) fillCache() {
if any.remaining == nil {
return
}
if any.cache == nil {
any.cache = make([]Any, 0, 8)
}
iter := any.Parse()
if len(any.remaining) == len(any.buf) {
iter.head++
c := iter.nextToken()
if c != ']' {
iter.unreadByte()
any.cache = append(any.cache, iter.readAny(iter))
} else {
any.remaining = nil
any.err = iter.Error
return
}
}
for iter.nextToken() == ',' {
any.cache = append(any.cache, iter.readAny(iter))
}
any.remaining = nil
any.err = iter.Error
} }
func (any *arrayLazyAny) LastError() error { func (any *arrayLazyAny) LastError() error {
@ -25,152 +110,252 @@ func (any *arrayLazyAny) LastError() error {
} }
func (any *arrayLazyAny) ToBool() bool { func (any *arrayLazyAny) ToBool() bool {
iter := any.cfg.BorrowIterator(any.buf) if any.cache == nil {
defer any.cfg.ReturnIterator(iter) any.IterateArray() // trigger first element read
return iter.ReadArray() }
return len(any.cache) != 0
} }
func (any *arrayLazyAny) ToInt() int { func (any *arrayLazyAny) ToInt() int {
if any.ToBool() { if any.cache == nil {
return 1 any.IterateArray() // trigger first element read
} }
return 0 if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *arrayLazyAny) ToInt32() int32 { func (any *arrayLazyAny) ToInt32() int32 {
if any.ToBool() { if any.cache == nil {
return 1 any.IterateArray() // trigger first element read
} }
return 0 if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *arrayLazyAny) ToInt64() int64 { func (any *arrayLazyAny) ToInt64() int64 {
if any.ToBool() { if any.cache == nil {
return 1 any.IterateArray() // trigger first element read
} }
return 0 if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *arrayLazyAny) ToUint() uint { func (any *arrayLazyAny) ToUint() uint {
if any.ToBool() { if any.cache == nil {
return 1 any.IterateArray() // trigger first element read
} }
return 0 if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *arrayLazyAny) ToUint32() uint32 { func (any *arrayLazyAny) ToUint32() uint32 {
if any.ToBool() { if any.cache == nil {
return 1 any.IterateArray() // trigger first element read
} }
return 0 if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *arrayLazyAny) ToUint64() uint64 { func (any *arrayLazyAny) ToUint64() uint64 {
if any.ToBool() { if any.cache == nil {
return 1 any.IterateArray() // trigger first element read
} }
return 0 if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *arrayLazyAny) ToFloat32() float32 { func (any *arrayLazyAny) ToFloat32() float32 {
if any.ToBool() { if any.cache == nil {
return 1 any.IterateArray() // trigger first element read
} }
return 0 if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *arrayLazyAny) ToFloat64() float64 { func (any *arrayLazyAny) ToFloat64() float64 {
if any.ToBool() { if any.cache == nil {
return 1 any.IterateArray() // trigger first element read
} }
return 0 if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *arrayLazyAny) ToString() string { func (any *arrayLazyAny) ToString() string {
return *(*string)(unsafe.Pointer(&any.buf)) if len(any.remaining) == len(any.buf) {
} // nothing has been parsed yet
return *(*string)(unsafe.Pointer(&any.buf))
func (any *arrayLazyAny) ToVal(val interface{}) { } else {
iter := any.cfg.BorrowIterator(any.buf) any.fillCache()
defer any.cfg.ReturnIterator(iter) str, err := MarshalToString(any.cache)
iter.ReadVal(val) any.err = err
return str
}
} }
func (any *arrayLazyAny) Get(path ...interface{}) Any { func (any *arrayLazyAny) Get(path ...interface{}) Any {
if len(path) == 0 { if len(path) == 0 {
return any return any
} }
var element Any
switch firstPath := path[0].(type) { switch firstPath := path[0].(type) {
case int: case int:
iter := any.cfg.BorrowIterator(any.buf) element = any.fillCacheUntil(firstPath)
defer any.cfg.ReturnIterator(iter) if element == nil {
valueBytes := locateArrayElement(iter, firstPath) element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)}
if valueBytes == nil {
return newInvalidAny(path)
} }
iter.ResetBytes(valueBytes)
return locatePath(iter, path[1:])
case int32: case int32:
if '*' == firstPath { if '*' == firstPath {
iter := any.cfg.BorrowIterator(any.buf) any.fillCache()
defer any.cfg.ReturnIterator(iter) arr := make([]Any, 0, len(any.cache))
arr := make([]Any, 0) for _, element := range any.cache {
iter.ReadArrayCB(func(iter *Iterator) bool { found := element.Get(path[1:]...)
found := iter.readAny().Get(path[1:]...) if found.ValueType() != Invalid {
if found.ValueType() != InvalidValue {
arr = append(arr, found) arr = append(arr, found)
} }
return true }
})
return wrapArray(arr) return wrapArray(arr)
} else {
element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", path[0], any.cache)}
} }
return newInvalidAny(path)
default: default:
return newInvalidAny(path) element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", path[0], any.cache)}
}
if len(path) == 1 {
return element
} else {
return element.Get(path[1:]...)
} }
} }
func (any *arrayLazyAny) Size() int { func (any *arrayLazyAny) Size() int {
size := 0 any.fillCache()
iter := any.cfg.BorrowIterator(any.buf) return len(any.cache)
defer any.cfg.ReturnIterator(iter) }
iter.ReadArrayCB(func(iter *Iterator) bool {
size++ func (any *arrayLazyAny) IterateArray() (func() (Any, bool), bool) {
iter.Skip() if any.cache == nil {
return true any.cache = make([]Any, 0, 8)
}) }
return size remaining := any.remaining
if len(remaining) == len(any.buf) {
iter := any.Parse()
iter.head++
c := iter.nextToken()
if c != ']' {
iter.unreadByte()
v := iter.readAny(iter)
any.cache = append(any.cache, v)
remaining = iter.buf[iter.head:]
any.remaining = remaining
} else {
remaining = nil
any.remaining = nil
any.err = iter.Error
return nil, false
}
}
if len(any.cache) == 0 {
return nil, false
}
arr := any.cache
nextValue := arr[0]
i := 1
return func() (Any, bool) {
value := nextValue
if i < len(arr) {
// read from cache
nextValue = arr[i]
i++
return value, true
} else {
// read from buffer
iter := any.iter
if iter == nil {
iter = NewIterator()
any.iter = iter
}
iter.ResetBytes(remaining)
c := iter.nextToken()
if c == ',' {
nextValue = iter.readAny(iter)
any.cache = append(any.cache, nextValue)
remaining = iter.buf[iter.head:]
any.remaining = remaining
any.err = iter.Error
return value, true
} else {
remaining = nil
any.remaining = nil
any.err = iter.Error
return value, false
}
}
}, true
}
func (any *arrayLazyAny) GetArray() []Any {
any.fillCache()
return any.cache
}
func (any *arrayLazyAny) SetArray(newList []Any) bool {
any.fillCache()
any.cache = newList
return true
} }
func (any *arrayLazyAny) WriteTo(stream *Stream) { func (any *arrayLazyAny) WriteTo(stream *Stream) {
stream.Write(any.buf) if len(any.remaining) == len(any.buf) {
// nothing has been parsed yet
stream.Write(any.buf)
} else {
any.fillCache()
stream.WriteVal(any.cache)
}
} }
func (any *arrayLazyAny) GetInterface() interface{} { func (any *arrayLazyAny) GetInterface() interface{} {
iter := any.cfg.BorrowIterator(any.buf) any.fillCache()
defer any.cfg.ReturnIterator(iter) return any.cache
return iter.Read()
} }
type arrayAny struct { type arrayAny struct {
baseAny baseAny
val reflect.Value err error
cache []Any
val reflect.Value
} }
func wrapArray(val interface{}) *arrayAny { func wrapArray(val interface{}) *arrayAny {
return &arrayAny{baseAny{}, reflect.ValueOf(val)} return &arrayAny{baseAny{}, nil, nil, reflect.ValueOf(val)}
} }
func (any *arrayAny) ValueType() ValueType { func (any *arrayAny) ValueType() ValueType {
return ArrayValue return Array
} }
func (any *arrayAny) MustBeValid() Any { func (any *arrayAny) Parse() *Iterator {
return any return nil
} }
func (any *arrayAny) LastError() error { func (any *arrayAny) LastError() error {
return nil return any.err
} }
func (any *arrayAny) ToBool() bool { func (any *arrayAny) ToBool() bool {
@ -234,45 +419,121 @@ func (any *arrayAny) ToFloat64() float64 {
} }
func (any *arrayAny) ToString() string { func (any *arrayAny) ToString() string {
str, _ := MarshalToString(any.val.Interface()) if len(any.cache) == 0 {
return str // nothing has been parsed yet
str, err := MarshalToString(any.val.Interface())
any.err = err
return str
} else {
any.fillCache()
str, err := MarshalToString(any.cache)
any.err = err
return str
}
}
func (any *arrayAny) fillCacheUntil(idx int) Any {
if idx < len(any.cache) {
return any.cache[idx]
} else {
for i := len(any.cache); i < any.val.Len(); i++ {
element := Wrap(any.val.Index(i).Interface())
any.cache = append(any.cache, element)
if idx == i {
return element
}
}
return nil
}
}
func (any *arrayAny) fillCache() {
any.cache = make([]Any, any.val.Len())
for i := 0; i < any.val.Len(); i++ {
any.cache[i] = Wrap(any.val.Index(i).Interface())
}
} }
func (any *arrayAny) Get(path ...interface{}) Any { func (any *arrayAny) Get(path ...interface{}) Any {
if len(path) == 0 { if len(path) == 0 {
return any return any
} }
var element Any
switch firstPath := path[0].(type) { switch firstPath := path[0].(type) {
case int: case int:
if firstPath < 0 || firstPath >= any.val.Len() { element = any.fillCacheUntil(firstPath)
return newInvalidAny(path) if element == nil {
element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)}
} }
return Wrap(any.val.Index(firstPath).Interface())
case int32: case int32:
if '*' == firstPath { if '*' == firstPath {
mappedAll := make([]Any, 0) any.fillCache()
for i := 0; i < any.val.Len(); i++ { mappedAll := make([]Any, 0, len(any.cache))
mapped := Wrap(any.val.Index(i).Interface()).Get(path[1:]...) for _, element := range any.cache {
if mapped.ValueType() != InvalidValue { mapped := element.Get(path[1:]...)
if mapped.ValueType() != Invalid {
mappedAll = append(mappedAll, mapped) mappedAll = append(mappedAll, mapped)
} }
} }
return wrapArray(mappedAll) return wrapArray(mappedAll)
} else {
element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", path[0], any.cache)}
} }
return newInvalidAny(path)
default: default:
return newInvalidAny(path) element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", path[0], any.cache)}
}
if len(path) == 1 {
return element
} else {
return element.Get(path[1:]...)
} }
} }
func (any *arrayAny) Size() int { func (any *arrayAny) Size() int {
return any.val.Len() any.fillCache()
return len(any.cache)
}
func (any *arrayAny) IterateArray() (func() (Any, bool), bool) {
if any.val.Len() == 0 {
return nil, false
}
i := 0
return func() (Any, bool) {
if i == any.val.Len() {
return nil, false
}
if i == len(any.cache) {
any.cache = append(any.cache, Wrap(any.val.Index(i).Interface()))
}
val := any.cache[i]
i++
return val, i != any.val.Len()
}, true
}
func (any *arrayAny) GetArray() []Any {
any.fillCache()
return any.cache
}
func (any *arrayAny) SetArray(newList []Any) bool {
any.fillCache()
any.cache = newList
return true
} }
func (any *arrayAny) WriteTo(stream *Stream) { func (any *arrayAny) WriteTo(stream *Stream) {
stream.WriteVal(any.val) if len(any.cache) == 0 {
// nothing has been parsed yet
stream.WriteVal(any.val)
} else {
any.fillCache()
stream.WriteVal(any.cache)
}
} }
func (any *arrayAny) GetInterface() interface{} { func (any *arrayAny) GetInterface() interface{} {
return any.val.Interface() any.fillCache()
return any.cache
} }

View File

@ -61,11 +61,7 @@ func (any *trueAny) GetInterface() interface{} {
} }
func (any *trueAny) ValueType() ValueType { func (any *trueAny) ValueType() ValueType {
return BoolValue return Bool
}
func (any *trueAny) MustBeValid() Any {
return any
} }
type falseAny struct { type falseAny struct {
@ -129,9 +125,5 @@ func (any *falseAny) GetInterface() interface{} {
} }
func (any *falseAny) ValueType() ValueType { func (any *falseAny) ValueType() ValueType {
return BoolValue return Bool
}
func (any *falseAny) MustBeValid() Any {
return any
} }

View File

@ -1,9 +1,105 @@
package jsoniter package jsoniter
import ( import (
"io"
"strconv" "strconv"
"unsafe"
) )
type float64LazyAny struct {
baseAny
buf []byte
iter *Iterator
err error
cache float64
}
func (any *float64LazyAny) Parse() *Iterator {
iter := any.iter
if iter == nil {
iter = NewIterator()
}
iter.ResetBytes(any.buf)
return iter
}
func (any *float64LazyAny) ValueType() ValueType {
return Number
}
func (any *float64LazyAny) fillCache() {
if any.err != nil {
return
}
iter := any.Parse()
any.cache = iter.ReadFloat64()
if iter.Error != io.EOF {
iter.reportError("floatLazyAny", "there are bytes left")
}
any.err = iter.Error
}
func (any *float64LazyAny) LastError() error {
return any.err
}
func (any *float64LazyAny) ToBool() bool {
return any.ToFloat64() != 0
}
func (any *float64LazyAny) ToInt() int {
any.fillCache()
return int(any.cache)
}
func (any *float64LazyAny) ToInt32() int32 {
any.fillCache()
return int32(any.cache)
}
func (any *float64LazyAny) ToInt64() int64 {
any.fillCache()
return int64(any.cache)
}
func (any *float64LazyAny) ToUint() uint {
any.fillCache()
return uint(any.cache)
}
func (any *float64LazyAny) ToUint32() uint32 {
any.fillCache()
return uint32(any.cache)
}
func (any *float64LazyAny) ToUint64() uint64 {
any.fillCache()
return uint64(any.cache)
}
func (any *float64LazyAny) ToFloat32() float32 {
any.fillCache()
return float32(any.cache)
}
func (any *float64LazyAny) ToFloat64() float64 {
any.fillCache()
return any.cache
}
func (any *float64LazyAny) ToString() string {
return *(*string)(unsafe.Pointer(&any.buf))
}
func (any *float64LazyAny) WriteTo(stream *Stream) {
stream.Write(any.buf)
}
func (any *float64LazyAny) GetInterface() interface{} {
any.fillCache()
return any.cache
}
type floatAny struct { type floatAny struct {
baseAny baseAny
val float64 val float64
@ -14,11 +110,7 @@ func (any *floatAny) Parse() *Iterator {
} }
func (any *floatAny) ValueType() ValueType { func (any *floatAny) ValueType() ValueType {
return NumberValue return Number
}
func (any *floatAny) MustBeValid() Any {
return any
} }
func (any *floatAny) LastError() error { func (any *floatAny) LastError() error {
@ -42,24 +134,15 @@ func (any *floatAny) ToInt64() int64 {
} }
func (any *floatAny) ToUint() uint { func (any *floatAny) ToUint() uint {
if any.val > 0 { return uint(any.val)
return uint(any.val)
}
return 0
} }
func (any *floatAny) ToUint32() uint32 { func (any *floatAny) ToUint32() uint32 {
if any.val > 0 { return uint32(any.val)
return uint32(any.val)
}
return 0
} }
func (any *floatAny) ToUint64() uint64 { func (any *floatAny) ToUint64() uint64 {
if any.val > 0 { return uint64(any.val)
return uint64(any.val)
}
return 0
} }
func (any *floatAny) ToFloat32() float32 { func (any *floatAny) ToFloat32() float32 {

View File

@ -14,11 +14,7 @@ func (any *int32Any) LastError() error {
} }
func (any *int32Any) ValueType() ValueType { func (any *int32Any) ValueType() ValueType {
return NumberValue return Number
}
func (any *int32Any) MustBeValid() Any {
return any
} }
func (any *int32Any) ToBool() bool { func (any *int32Any) ToBool() bool {

View File

@ -1,9 +1,105 @@
package jsoniter package jsoniter
import ( import (
"io"
"strconv" "strconv"
"unsafe"
) )
type int64LazyAny struct {
baseAny
buf []byte
iter *Iterator
err error
cache int64
}
func (any *int64LazyAny) ValueType() ValueType {
return Number
}
func (any *int64LazyAny) Parse() *Iterator {
iter := any.iter
if iter == nil {
iter = NewIterator()
}
iter.ResetBytes(any.buf)
return iter
}
func (any *int64LazyAny) fillCache() {
if any.err != nil {
return
}
iter := any.Parse()
any.cache = iter.ReadInt64()
if iter.Error != io.EOF {
iter.reportError("intLazyAny", "there are bytes left")
}
any.err = iter.Error
}
func (any *int64LazyAny) LastError() error {
return any.err
}
func (any *int64LazyAny) ToBool() bool {
return any.ToInt64() != 0
}
func (any *int64LazyAny) ToInt() int {
any.fillCache()
return int(any.cache)
}
func (any *int64LazyAny) ToInt32() int32 {
any.fillCache()
return int32(any.cache)
}
func (any *int64LazyAny) ToInt64() int64 {
any.fillCache()
return any.cache
}
func (any *int64LazyAny) ToUint() uint {
any.fillCache()
return uint(any.cache)
}
func (any *int64LazyAny) ToUint32() uint32 {
any.fillCache()
return uint32(any.cache)
}
func (any *int64LazyAny) ToUint64() uint64 {
any.fillCache()
return uint64(any.cache)
}
func (any *int64LazyAny) ToFloat32() float32 {
any.fillCache()
return float32(any.cache)
}
func (any *int64LazyAny) ToFloat64() float64 {
any.fillCache()
return float64(any.cache)
}
func (any *int64LazyAny) ToString() string {
return *(*string)(unsafe.Pointer(&any.buf))
}
func (any *int64LazyAny) WriteTo(stream *Stream) {
stream.Write(any.buf)
}
func (any *int64LazyAny) GetInterface() interface{} {
any.fillCache()
return any.cache
}
type int64Any struct { type int64Any struct {
baseAny baseAny
val int64 val int64
@ -14,11 +110,7 @@ func (any *int64Any) LastError() error {
} }
func (any *int64Any) ValueType() ValueType { func (any *int64Any) ValueType() ValueType {
return NumberValue return Number
}
func (any *int64Any) MustBeValid() Any {
return any
} }
func (any *int64Any) ToBool() bool { func (any *int64Any) ToBool() bool {

View File

@ -7,20 +7,12 @@ type invalidAny struct {
err error err error
} }
func newInvalidAny(path []interface{}) *invalidAny {
return &invalidAny{baseAny{}, fmt.Errorf("%v not found", path)}
}
func (any *invalidAny) LastError() error { func (any *invalidAny) LastError() error {
return any.err return any.err
} }
func (any *invalidAny) ValueType() ValueType { func (any *invalidAny) ValueType() ValueType {
return InvalidValue return Invalid
}
func (any *invalidAny) MustBeValid() Any {
panic(any.err)
} }
func (any *invalidAny) ToBool() bool { func (any *invalidAny) ToBool() bool {
@ -69,8 +61,9 @@ func (any *invalidAny) WriteTo(stream *Stream) {
func (any *invalidAny) Get(path ...interface{}) Any { func (any *invalidAny) Get(path ...interface{}) Any {
if any.err == nil { if any.err == nil {
return &invalidAny{baseAny{}, fmt.Errorf("get %v from invalid", path)} return &invalidAny{baseAny{}, fmt.Errorf("get %v from invalid", path)}
} else {
return &invalidAny{baseAny{}, fmt.Errorf("%v, get %v from invalid", any.err, path)}
} }
return &invalidAny{baseAny{}, fmt.Errorf("%v, get %v from invalid", any.err, path)}
} }
func (any *invalidAny) Parse() *Iterator { func (any *invalidAny) Parse() *Iterator {

View File

@ -9,11 +9,7 @@ func (any *nilAny) LastError() error {
} }
func (any *nilAny) ValueType() ValueType { func (any *nilAny) ValueType() ValueType {
return NilValue return Nil
}
func (any *nilAny) MustBeValid() Any {
return any
} }
func (any *nilAny) ToBool() bool { func (any *nilAny) ToBool() bool {

View File

@ -1,104 +0,0 @@
package jsoniter
import "unsafe"
type numberLazyAny struct {
baseAny
cfg *frozenConfig
buf []byte
err error
}
func (any *numberLazyAny) ValueType() ValueType {
return NumberValue
}
func (any *numberLazyAny) MustBeValid() Any {
return any
}
func (any *numberLazyAny) LastError() error {
return any.err
}
func (any *numberLazyAny) ToBool() bool {
return any.ToFloat64() != 0
}
func (any *numberLazyAny) ToInt() int {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadInt()
any.err = iter.Error
return val
}
func (any *numberLazyAny) ToInt32() int32 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadInt32()
any.err = iter.Error
return val
}
func (any *numberLazyAny) ToInt64() int64 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadInt64()
any.err = iter.Error
return val
}
func (any *numberLazyAny) ToUint() uint {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadUint()
any.err = iter.Error
return val
}
func (any *numberLazyAny) ToUint32() uint32 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadUint32()
any.err = iter.Error
return val
}
func (any *numberLazyAny) ToUint64() uint64 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadUint64()
any.err = iter.Error
return val
}
func (any *numberLazyAny) ToFloat32() float32 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadFloat32()
any.err = iter.Error
return val
}
func (any *numberLazyAny) ToFloat64() float64 {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
val := iter.ReadFloat64()
any.err = iter.Error
return val
}
func (any *numberLazyAny) ToString() string {
return *(*string)(unsafe.Pointer(&any.buf))
}
func (any *numberLazyAny) WriteTo(stream *Stream) {
stream.Write(any.buf)
}
func (any *numberLazyAny) GetInterface() interface{} {
iter := any.cfg.BorrowIterator(any.buf)
defer any.cfg.ReturnIterator(iter)
return iter.Read()
}

View File

@ -1,23 +1,110 @@
package jsoniter package jsoniter
import ( import (
"fmt"
"reflect" "reflect"
"unsafe" "unsafe"
) )
type objectLazyAny struct { type objectLazyAny struct {
baseAny baseAny
cfg *frozenConfig buf []byte
buf []byte iter *Iterator
err error err error
cache map[string]Any
remaining []byte
} }
func (any *objectLazyAny) ValueType() ValueType { func (any *objectLazyAny) ValueType() ValueType {
return ObjectValue return Object
} }
func (any *objectLazyAny) MustBeValid() Any { func (any *objectLazyAny) Parse() *Iterator {
return any iter := any.iter
if iter == nil {
iter = NewIterator()
any.iter = iter
}
iter.ResetBytes(any.remaining)
return iter
}
func (any *objectLazyAny) fillCacheUntil(target string) Any {
if any.remaining == nil {
return any.cache[target]
}
if any.cache == nil {
any.cache = map[string]Any{}
}
val := any.cache[target]
if val != nil {
return val
}
iter := any.Parse()
if len(any.remaining) == len(any.buf) {
iter.head++
c := iter.nextToken()
if c != '}' {
iter.unreadByte()
k := string(iter.readObjectFieldAsBytes())
v := iter.readAny(iter)
any.cache[k] = v
if target == k {
any.remaining = iter.buf[iter.head:]
any.err = iter.Error
return v
}
} else {
any.remaining = nil
any.err = iter.Error
return nil
}
}
for iter.nextToken() == ',' {
k := string(iter.readObjectFieldAsBytes())
v := iter.readAny(iter)
any.cache[k] = v
if target == k {
any.remaining = iter.buf[iter.head:]
any.err = iter.Error
return v
}
}
any.remaining = nil
any.err = iter.Error
return nil
}
func (any *objectLazyAny) fillCache() {
if any.remaining == nil {
return
}
if any.cache == nil {
any.cache = map[string]Any{}
}
iter := any.Parse()
if len(any.remaining) == len(any.buf) {
iter.head++
c := iter.nextToken()
if c != '}' {
iter.unreadByte()
k := string(iter.readObjectFieldAsBytes())
v := iter.readAny(iter)
any.cache[k] = v
} else {
any.remaining = nil
any.err = iter.Error
return
}
}
for iter.nextToken() == ',' {
k := string(iter.readObjectFieldAsBytes())
v := iter.readAny(iter)
any.cache[k] = v
}
any.remaining = nil
any.err = iter.Error
return
} }
func (any *objectLazyAny) LastError() error { func (any *objectLazyAny) LastError() error {
@ -25,141 +112,316 @@ func (any *objectLazyAny) LastError() error {
} }
func (any *objectLazyAny) ToBool() bool { func (any *objectLazyAny) ToBool() bool {
return true if any.cache == nil {
any.IterateObject() // trigger first value read
}
return len(any.cache) != 0
} }
func (any *objectLazyAny) ToInt() int { func (any *objectLazyAny) ToInt() int {
return 0 if any.cache == nil {
any.IterateObject() // trigger first value read
}
if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *objectLazyAny) ToInt32() int32 { func (any *objectLazyAny) ToInt32() int32 {
return 0 if any.cache == nil {
any.IterateObject() // trigger first value read
}
if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *objectLazyAny) ToInt64() int64 { func (any *objectLazyAny) ToInt64() int64 {
return 0 if any.cache == nil {
any.IterateObject() // trigger first value read
}
if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *objectLazyAny) ToUint() uint { func (any *objectLazyAny) ToUint() uint {
return 0 if any.cache == nil {
any.IterateObject() // trigger first value read
}
if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *objectLazyAny) ToUint32() uint32 { func (any *objectLazyAny) ToUint32() uint32 {
return 0 if any.cache == nil {
any.IterateObject() // trigger first value read
}
if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *objectLazyAny) ToUint64() uint64 { func (any *objectLazyAny) ToUint64() uint64 {
return 0 if any.cache == nil {
any.IterateObject() // trigger first value read
}
if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *objectLazyAny) ToFloat32() float32 { func (any *objectLazyAny) ToFloat32() float32 {
return 0 if any.cache == nil {
any.IterateObject() // trigger first value read
}
if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *objectLazyAny) ToFloat64() float64 { func (any *objectLazyAny) ToFloat64() float64 {
return 0 if any.cache == nil {
any.IterateObject() // trigger first value read
}
if len(any.cache) == 0 {
return 0
}
return 1
} }
func (any *objectLazyAny) ToString() string { func (any *objectLazyAny) ToString() string {
return *(*string)(unsafe.Pointer(&any.buf)) if len(any.remaining) == len(any.buf) {
} // nothing has been parsed yet
return *(*string)(unsafe.Pointer(&any.buf))
func (any *objectLazyAny) ToVal(obj interface{}) { } else {
iter := any.cfg.BorrowIterator(any.buf) any.fillCache()
defer any.cfg.ReturnIterator(iter) str, err := MarshalToString(any.cache)
iter.ReadVal(obj) any.err = err
return str
}
} }
func (any *objectLazyAny) Get(path ...interface{}) Any { func (any *objectLazyAny) Get(path ...interface{}) Any {
if len(path) == 0 { if len(path) == 0 {
return any return any
} }
var element Any
switch firstPath := path[0].(type) { switch firstPath := path[0].(type) {
case string: case string:
iter := any.cfg.BorrowIterator(any.buf) element = any.fillCacheUntil(firstPath)
defer any.cfg.ReturnIterator(iter) if element == nil {
valueBytes := locateObjectField(iter, firstPath) element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)}
if valueBytes == nil {
return newInvalidAny(path)
} }
iter.ResetBytes(valueBytes)
return locatePath(iter, path[1:])
case int32: case int32:
if '*' == firstPath { if '*' == firstPath {
any.fillCache()
mappedAll := map[string]Any{} mappedAll := map[string]Any{}
iter := any.cfg.BorrowIterator(any.buf) for key, value := range any.cache {
defer any.cfg.ReturnIterator(iter) mapped := value.Get(path[1:]...)
iter.ReadMapCB(func(iter *Iterator, field string) bool { if mapped.ValueType() != Invalid {
mapped := locatePath(iter, path[1:]) mappedAll[key] = mapped
if mapped.ValueType() != InvalidValue {
mappedAll[field] = mapped
} }
return true }
})
return wrapMap(mappedAll) return wrapMap(mappedAll)
} else {
element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)}
} }
return newInvalidAny(path)
default: default:
return newInvalidAny(path) element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)}
}
if len(path) == 1 {
return element
} else {
return element.Get(path[1:]...)
} }
} }
func (any *objectLazyAny) Keys() []string { func (any *objectLazyAny) Keys() []string {
keys := []string{} any.fillCache()
iter := any.cfg.BorrowIterator(any.buf) keys := make([]string, 0, len(any.cache))
defer any.cfg.ReturnIterator(iter) for key := range any.cache {
iter.ReadMapCB(func(iter *Iterator, field string) bool { keys = append(keys, key)
iter.Skip() }
keys = append(keys, field)
return true
})
return keys return keys
} }
func (any *objectLazyAny) Size() int { func (any *objectLazyAny) Size() int {
size := 0 any.fillCache()
iter := any.cfg.BorrowIterator(any.buf) return len(any.cache)
defer any.cfg.ReturnIterator(iter) }
iter.ReadObjectCB(func(iter *Iterator, field string) bool {
iter.Skip() func (any *objectLazyAny) IterateObject() (func() (string, Any, bool), bool) {
size++ if any.cache == nil {
return true any.cache = map[string]Any{}
}) }
return size remaining := any.remaining
if len(remaining) == len(any.buf) {
iter := any.Parse()
iter.head++
c := iter.nextToken()
if c != '}' {
iter.unreadByte()
k := string(iter.readObjectFieldAsBytes())
v := iter.readAny(iter)
any.cache[k] = v
remaining = iter.buf[iter.head:]
any.remaining = remaining
} else {
remaining = nil
any.remaining = nil
any.err = iter.Error
return nil, false
}
}
if len(any.cache) == 0 {
return nil, false
}
keys := make([]string, 0, len(any.cache))
values := make([]Any, 0, len(any.cache))
for key, value := range any.cache {
keys = append(keys, key)
values = append(values, value)
}
nextKey := keys[0]
nextValue := values[0]
i := 1
return func() (string, Any, bool) {
key := nextKey
value := nextValue
if i < len(keys) {
// read from cache
nextKey = keys[i]
nextValue = values[i]
i++
return key, value, true
} else {
// read from buffer
iter := any.iter
if iter == nil {
iter = NewIterator()
any.iter = iter
}
iter.ResetBytes(remaining)
c := iter.nextToken()
if c == ',' {
nextKey = string(iter.readObjectFieldAsBytes())
nextValue = iter.readAny(iter)
any.cache[nextKey] = nextValue
remaining = iter.buf[iter.head:]
any.remaining = remaining
any.err = iter.Error
return key, value, true
} else {
nextKey = ""
remaining = nil
any.remaining = nil
any.err = iter.Error
return key, value, false
}
}
}, true
}
func (any *objectLazyAny) GetObject() map[string]Any {
any.fillCache()
return any.cache
}
func (any *objectLazyAny) SetObject(val map[string]Any) bool {
any.fillCache()
any.cache = val
return true
} }
func (any *objectLazyAny) WriteTo(stream *Stream) { func (any *objectLazyAny) WriteTo(stream *Stream) {
stream.Write(any.buf) if len(any.remaining) == len(any.buf) {
// nothing has been parsed yet
stream.Write(any.buf)
} else {
any.fillCache()
stream.WriteVal(any.cache)
}
} }
func (any *objectLazyAny) GetInterface() interface{} { func (any *objectLazyAny) GetInterface() interface{} {
iter := any.cfg.BorrowIterator(any.buf) any.fillCache()
defer any.cfg.ReturnIterator(iter) return any.cache
return iter.Read()
} }
type objectAny struct { type objectAny struct {
baseAny baseAny
err error err error
val reflect.Value cache map[string]Any
val reflect.Value
} }
func wrapStruct(val interface{}) *objectAny { func wrapStruct(val interface{}) *objectAny {
return &objectAny{baseAny{}, nil, reflect.ValueOf(val)} return &objectAny{baseAny{}, nil, nil, reflect.ValueOf(val)}
} }
func (any *objectAny) ValueType() ValueType { func (any *objectAny) ValueType() ValueType {
return ObjectValue return Object
}
func (any *objectAny) MustBeValid() Any {
return any
} }
func (any *objectAny) Parse() *Iterator { func (any *objectAny) Parse() *Iterator {
return nil return nil
} }
func (any *objectAny) fillCacheUntil(target string) Any {
if any.cache == nil {
any.cache = map[string]Any{}
}
element, found := any.cache[target]
if found {
return element
}
for i := len(any.cache); i < any.val.NumField(); i++ {
field := any.val.Field(i)
fieldName := any.val.Type().Field(i).Name
var element Any
if field.CanInterface() {
element = Wrap(field.Interface())
} else {
element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", fieldName, any.cache)}
}
any.cache[fieldName] = element
if fieldName == target {
return element
}
}
return nil
}
func (any *objectAny) fillCache() {
if any.cache == nil {
any.cache = map[string]Any{}
}
if len(any.cache) == any.val.NumField() {
return
}
for i := 0; i < any.val.NumField(); i++ {
field := any.val.Field(i)
fieldName := any.val.Type().Field(i).Name
var element Any
if field.CanInterface() {
element = Wrap(field.Interface())
} else {
element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", fieldName, any.cache)}
}
any.cache[fieldName] = element
}
}
func (any *objectAny) LastError() error { func (any *objectAny) LastError() error {
return any.err return any.err
} }
@ -169,206 +431,418 @@ func (any *objectAny) ToBool() bool {
} }
func (any *objectAny) ToInt() int { func (any *objectAny) ToInt() int {
return 0 if any.val.NumField() == 0 {
return 0
}
return 1
} }
func (any *objectAny) ToInt32() int32 { func (any *objectAny) ToInt32() int32 {
return 0 if any.val.NumField() == 0 {
return 0
}
return 1
} }
func (any *objectAny) ToInt64() int64 { func (any *objectAny) ToInt64() int64 {
return 0 if any.val.NumField() == 0 {
return 0
}
return 1
} }
func (any *objectAny) ToUint() uint { func (any *objectAny) ToUint() uint {
return 0 if any.val.NumField() == 0 {
return 0
}
return 1
} }
func (any *objectAny) ToUint32() uint32 { func (any *objectAny) ToUint32() uint32 {
return 0 if any.val.NumField() == 0 {
return 0
}
return 1
} }
func (any *objectAny) ToUint64() uint64 { func (any *objectAny) ToUint64() uint64 {
return 0 if any.val.NumField() == 0 {
return 0
}
return 1
} }
func (any *objectAny) ToFloat32() float32 { func (any *objectAny) ToFloat32() float32 {
return 0 if any.val.NumField() == 0 {
return 0
}
return 1
} }
func (any *objectAny) ToFloat64() float64 { func (any *objectAny) ToFloat64() float64 {
return 0 if any.val.NumField() == 0 {
return 0
}
return 1
} }
func (any *objectAny) ToString() string { func (any *objectAny) ToString() string {
str, err := MarshalToString(any.val.Interface()) if len(any.cache) == 0 {
any.err = err str, err := MarshalToString(any.val.Interface())
return str any.err = err
return str
} else {
any.fillCache()
str, err := MarshalToString(any.cache)
any.err = err
return str
}
} }
func (any *objectAny) Get(path ...interface{}) Any { func (any *objectAny) Get(path ...interface{}) Any {
if len(path) == 0 { if len(path) == 0 {
return any return any
} }
var element Any
switch firstPath := path[0].(type) { switch firstPath := path[0].(type) {
case string: case string:
field := any.val.FieldByName(firstPath) element = any.fillCacheUntil(firstPath)
if !field.IsValid() { if element == nil {
return newInvalidAny(path) element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)}
} }
return Wrap(field.Interface())
case int32: case int32:
if '*' == firstPath { if '*' == firstPath {
any.fillCache()
mappedAll := map[string]Any{} mappedAll := map[string]Any{}
for i := 0; i < any.val.NumField(); i++ { for key, value := range any.cache {
field := any.val.Field(i) mapped := value.Get(path[1:]...)
if field.CanInterface() { if mapped.ValueType() != Invalid {
mapped := Wrap(field.Interface()).Get(path[1:]...) mappedAll[key] = mapped
if mapped.ValueType() != InvalidValue {
mappedAll[any.val.Type().Field(i).Name] = mapped
}
} }
} }
return wrapMap(mappedAll) return wrapMap(mappedAll)
} else {
element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)}
} }
return newInvalidAny(path)
default: default:
return newInvalidAny(path) element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)}
}
if len(path) == 1 {
return element
} else {
return element.Get(path[1:]...)
} }
} }
func (any *objectAny) Keys() []string { func (any *objectAny) Keys() []string {
keys := make([]string, 0, any.val.NumField()) any.fillCache()
for i := 0; i < any.val.NumField(); i++ { keys := make([]string, 0, len(any.cache))
keys = append(keys, any.val.Type().Field(i).Name) for key := range any.cache {
keys = append(keys, key)
} }
return keys return keys
} }
func (any *objectAny) Size() int { func (any *objectAny) Size() int {
return any.val.NumField() any.fillCache()
return len(any.cache)
}
func (any *objectAny) IterateObject() (func() (string, Any, bool), bool) {
if any.cache == nil {
any.cache = map[string]Any{}
}
if any.val.NumField() == 0 {
return nil, false
}
cacheKeys := make([]string, len(any.cache))
i := 0
for key := range any.cache {
cacheKeys[i] = key
i++
}
i = 0
return func() (string, Any, bool) {
if i == any.val.NumField() {
return "", nil, false
}
var fieldName string
var fieldValueAsAny Any
if i == len(cacheKeys) {
fieldName = any.val.Type().Field(i).Name
cacheKeys = append(cacheKeys, fieldName)
fieldValue := any.val.Field(i)
if fieldValue.CanInterface() {
fieldValueAsAny = Wrap(fieldValue.Interface())
any.cache[fieldName] = fieldValueAsAny
} else {
fieldValueAsAny = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", fieldName, any.cache)}
any.cache[fieldName] = fieldValueAsAny
}
} else {
fieldName = cacheKeys[i]
fieldValueAsAny = any.cache[fieldName]
}
i++
return fieldName, fieldValueAsAny, i != any.val.NumField()
}, true
}
func (any *objectAny) GetObject() map[string]Any {
any.fillCache()
return any.cache
}
func (any *objectAny) SetObject(val map[string]Any) bool {
any.fillCache()
any.cache = val
return true
} }
func (any *objectAny) WriteTo(stream *Stream) { func (any *objectAny) WriteTo(stream *Stream) {
stream.WriteVal(any.val) if len(any.cache) == 0 {
// nothing has been parsed yet
stream.WriteVal(any.val)
} else {
any.fillCache()
stream.WriteVal(any.cache)
}
} }
func (any *objectAny) GetInterface() interface{} { func (any *objectAny) GetInterface() interface{} {
return any.val.Interface() any.fillCache()
return any.cache
} }
type mapAny struct { type mapAny struct {
baseAny baseAny
err error err error
val reflect.Value cache map[string]Any
val reflect.Value
} }
func wrapMap(val interface{}) *mapAny { func wrapMap(val interface{}) *mapAny {
return &mapAny{baseAny{}, nil, reflect.ValueOf(val)} return &mapAny{baseAny{}, nil, nil, reflect.ValueOf(val)}
} }
func (any *mapAny) ValueType() ValueType { func (any *mapAny) ValueType() ValueType {
return ObjectValue return Object
}
func (any *mapAny) MustBeValid() Any {
return any
} }
func (any *mapAny) Parse() *Iterator { func (any *mapAny) Parse() *Iterator {
return nil return nil
} }
func (any *mapAny) fillCacheUntil(target string) Any {
if any.cache == nil {
any.cache = map[string]Any{}
}
element, found := any.cache[target]
if found {
return element
}
for _, key := range any.val.MapKeys() {
keyAsStr := key.String()
_, found := any.cache[keyAsStr]
if found {
continue
}
element := Wrap(any.val.MapIndex(key).Interface())
any.cache[keyAsStr] = element
if keyAsStr == target {
return element
}
}
return nil
}
func (any *mapAny) fillCache() {
if any.cache == nil {
any.cache = map[string]Any{}
}
if len(any.cache) == any.val.Len() {
return
}
for _, key := range any.val.MapKeys() {
keyAsStr := key.String()
element := Wrap(any.val.MapIndex(key).Interface())
any.cache[keyAsStr] = element
}
}
func (any *mapAny) LastError() error { func (any *mapAny) LastError() error {
return any.err return any.err
} }
func (any *mapAny) ToBool() bool { func (any *mapAny) ToBool() bool {
return true return any.val.Len() != 0
} }
func (any *mapAny) ToInt() int { func (any *mapAny) ToInt() int {
return 0 if any.val.Len() == 0 {
return 0
}
return 1
} }
func (any *mapAny) ToInt32() int32 { func (any *mapAny) ToInt32() int32 {
return 0 if any.val.Len() == 0 {
return 0
}
return 1
} }
func (any *mapAny) ToInt64() int64 { func (any *mapAny) ToInt64() int64 {
return 0 if any.val.Len() == 0 {
return 0
}
return 1
} }
func (any *mapAny) ToUint() uint { func (any *mapAny) ToUint() uint {
return 0 if any.val.Len() == 0 {
return 0
}
return 1
} }
func (any *mapAny) ToUint32() uint32 { func (any *mapAny) ToUint32() uint32 {
return 0 if any.val.Len() == 0 {
return 0
}
return 1
} }
func (any *mapAny) ToUint64() uint64 { func (any *mapAny) ToUint64() uint64 {
return 0 if any.val.Len() == 0 {
return 0
}
return 1
} }
func (any *mapAny) ToFloat32() float32 { func (any *mapAny) ToFloat32() float32 {
return 0 if any.val.Len() == 0 {
return 0
}
return 1
} }
func (any *mapAny) ToFloat64() float64 { func (any *mapAny) ToFloat64() float64 {
return 0 if any.val.Len() == 0 {
return 0
}
return 1
} }
func (any *mapAny) ToString() string { func (any *mapAny) ToString() string {
str, err := MarshalToString(any.val.Interface()) if len(any.cache) == 0 {
any.err = err str, err := MarshalToString(any.val.Interface())
return str any.err = err
return str
} else {
any.fillCache()
str, err := MarshalToString(any.cache)
any.err = err
return str
}
} }
func (any *mapAny) Get(path ...interface{}) Any { func (any *mapAny) Get(path ...interface{}) Any {
if len(path) == 0 { if len(path) == 0 {
return any return any
} }
var element Any
switch firstPath := path[0].(type) { switch firstPath := path[0].(type) {
case string:
element = any.fillCacheUntil(firstPath)
if element == nil {
element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)}
}
case int32: case int32:
if '*' == firstPath { if '*' == firstPath {
any.fillCache()
mappedAll := map[string]Any{} mappedAll := map[string]Any{}
for _, key := range any.val.MapKeys() { for key, value := range any.cache {
keyAsStr := key.String() mapped := value.Get(path[1:]...)
element := Wrap(any.val.MapIndex(key).Interface()) if mapped.ValueType() != Invalid {
mapped := element.Get(path[1:]...) mappedAll[key] = mapped
if mapped.ValueType() != InvalidValue {
mappedAll[keyAsStr] = mapped
} }
} }
return wrapMap(mappedAll) return wrapMap(mappedAll)
} else {
element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)}
} }
return newInvalidAny(path)
default: default:
value := any.val.MapIndex(reflect.ValueOf(firstPath)) element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", firstPath, any.cache)}
if !value.IsValid() { }
return newInvalidAny(path) if len(path) == 1 {
} return element
return Wrap(value.Interface()) } else {
return element.Get(path[1:]...)
} }
} }
func (any *mapAny) Keys() []string { func (any *mapAny) Keys() []string {
keys := make([]string, 0, any.val.Len()) any.fillCache()
for _, key := range any.val.MapKeys() { keys := make([]string, 0, len(any.cache))
keys = append(keys, key.String()) for key := range any.cache {
keys = append(keys, key)
} }
return keys return keys
} }
func (any *mapAny) Size() int { func (any *mapAny) Size() int {
return any.val.Len() any.fillCache()
return len(any.cache)
}
func (any *mapAny) IterateObject() (func() (string, Any, bool), bool) {
any.fillCache()
if len(any.cache) == 0 {
return nil, false
}
keys := make([]string, len(any.cache))
values := make([]Any, len(any.cache))
i := 0
for k, v := range any.cache {
keys[i] = k
values[i] = v
i++
}
i = 0
return func() (string, Any, bool) {
if i == len(keys) {
return "", nil, false
}
k := keys[i]
v := values[i]
i++
return k, v, i != len(keys)
}, true
}
func (any *mapAny) GetObject() map[string]Any {
any.fillCache()
return any.cache
}
func (any *mapAny) SetObject(val map[string]Any) bool {
any.fillCache()
any.cache = val
return true
} }
func (any *mapAny) WriteTo(stream *Stream) { func (any *mapAny) WriteTo(stream *Stream) {
stream.WriteVal(any.val) if len(any.cache) == 0 {
// nothing has been parsed yet
stream.WriteVal(any.val)
} else {
any.fillCache()
stream.WriteVal(any.cache)
}
} }
func (any *mapAny) GetInterface() interface{} { func (any *mapAny) GetInterface() interface{} {
return any.val.Interface() any.fillCache()
return any.cache
} }

View File

@ -1,20 +1,145 @@
package jsoniter package jsoniter
import ( import (
"fmt" "io"
"strconv" "strconv"
) )
type stringAny struct { type stringLazyAny struct {
baseAny baseAny
val string buf []byte
iter *Iterator
err error
cache string
} }
func (any *stringAny) Get(path ...interface{}) Any { func (any *stringLazyAny) ValueType() ValueType {
if len(path) == 0 { return String
return any }
func (any *stringLazyAny) Parse() *Iterator {
iter := any.iter
if iter == nil {
iter = NewIterator()
any.iter = iter
} }
return &invalidAny{baseAny{}, fmt.Errorf("Get %v from simple value", path)} iter.ResetBytes(any.buf)
return iter
}
func (any *stringLazyAny) fillCache() {
if any.err != nil {
return
}
iter := any.Parse()
any.cache = iter.ReadString()
if iter.Error != io.EOF {
iter.reportError("stringLazyAny", "there are bytes left")
}
any.err = iter.Error
}
func (any *stringLazyAny) LastError() error {
return any.err
}
func (any *stringLazyAny) ToBool() bool {
str := any.ToString()
if str == "false" {
return false
}
for _, c := range str {
switch c {
case ' ', '\n', '\r', '\t':
default:
return true
}
}
return false
}
func (any *stringLazyAny) ToInt() int {
iter := any.Parse()
iter.head++
val := iter.ReadInt()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToInt32() int32 {
iter := any.Parse()
iter.head++
val := iter.ReadInt32()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToInt64() int64 {
iter := any.Parse()
iter.head++
val := iter.ReadInt64()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToUint() uint {
iter := any.Parse()
iter.head++
val := iter.ReadUint()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToUint32() uint32 {
iter := any.Parse()
iter.head++
val := iter.ReadUint32()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToUint64() uint64 {
iter := any.Parse()
iter.head++
val := iter.ReadUint64()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToFloat32() float32 {
iter := any.Parse()
iter.head++
val := iter.ReadFloat32()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToFloat64() float64 {
iter := any.Parse()
iter.head++
val := iter.ReadFloat64()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToString() string {
any.fillCache()
return any.cache
}
func (any *stringLazyAny) WriteTo(stream *Stream) {
stream.Write(any.buf)
}
func (any *stringLazyAny) GetInterface() interface{} {
any.fillCache()
return any.cache
}
type stringAny struct {
baseAny
err error
val string
} }
func (any *stringAny) Parse() *Iterator { func (any *stringAny) Parse() *Iterator {
@ -22,20 +147,16 @@ func (any *stringAny) Parse() *Iterator {
} }
func (any *stringAny) ValueType() ValueType { func (any *stringAny) ValueType() ValueType {
return StringValue return String
}
func (any *stringAny) MustBeValid() Any {
return any
} }
func (any *stringAny) LastError() error { func (any *stringAny) LastError() error {
return nil return any.err
} }
func (any *stringAny) ToBool() bool { func (any *stringAny) ToBool() bool {
str := any.ToString() str := any.ToString()
if str == "0" { if str == "false" {
return false return false
} }
for _, c := range str { for _, c := range str {
@ -49,107 +170,50 @@ func (any *stringAny) ToBool() bool {
} }
func (any *stringAny) ToInt() int { func (any *stringAny) ToInt() int {
return int(any.ToInt64()) parsed, err := strconv.ParseInt(any.val, 10, 64)
any.err = err
return int(parsed)
} }
func (any *stringAny) ToInt32() int32 { func (any *stringAny) ToInt32() int32 {
return int32(any.ToInt64()) parsed, err := strconv.ParseInt(any.val, 10, 32)
any.err = err
return int32(parsed)
} }
func (any *stringAny) ToInt64() int64 { func (any *stringAny) ToInt64() int64 {
if any.val == "" { parsed, err := strconv.ParseInt(any.val, 10, 64)
return 0 any.err = err
} return parsed
flag := 1
startPos := 0
endPos := 0
if any.val[0] == '+' || any.val[0] == '-' {
startPos = 1
}
if any.val[0] == '-' {
flag = -1
}
for i := startPos; i < len(any.val); i++ {
if any.val[i] >= '0' && any.val[i] <= '9' {
endPos = i + 1
} else {
break
}
}
parsed, _ := strconv.ParseInt(any.val[startPos:endPos], 10, 64)
return int64(flag) * parsed
} }
func (any *stringAny) ToUint() uint { func (any *stringAny) ToUint() uint {
return uint(any.ToUint64()) parsed, err := strconv.ParseUint(any.val, 10, 64)
any.err = err
return uint(parsed)
} }
func (any *stringAny) ToUint32() uint32 { func (any *stringAny) ToUint32() uint32 {
return uint32(any.ToUint64()) parsed, err := strconv.ParseUint(any.val, 10, 32)
any.err = err
return uint32(parsed)
} }
func (any *stringAny) ToUint64() uint64 { func (any *stringAny) ToUint64() uint64 {
if any.val == "" { parsed, err := strconv.ParseUint(any.val, 10, 64)
return 0 any.err = err
}
startPos := 0
endPos := 0
if any.val[0] == '-' {
return 0
}
if any.val[0] == '+' {
startPos = 1
}
for i := startPos; i < len(any.val); i++ {
if any.val[i] >= '0' && any.val[i] <= '9' {
endPos = i + 1
} else {
break
}
}
parsed, _ := strconv.ParseUint(any.val[startPos:endPos], 10, 64)
return parsed return parsed
} }
func (any *stringAny) ToFloat32() float32 { func (any *stringAny) ToFloat32() float32 {
return float32(any.ToFloat64()) parsed, err := strconv.ParseFloat(any.val, 32)
any.err = err
return float32(parsed)
} }
func (any *stringAny) ToFloat64() float64 { func (any *stringAny) ToFloat64() float64 {
if len(any.val) == 0 { parsed, err := strconv.ParseFloat(any.val, 64)
return 0 any.err = err
}
// first char invalid
if any.val[0] != '+' && any.val[0] != '-' && (any.val[0] > '9' || any.val[0] < '0') {
return 0
}
// extract valid num expression from string
// eg 123true => 123, -12.12xxa => -12.12
endPos := 1
for i := 1; i < len(any.val); i++ {
if any.val[i] == '.' || any.val[i] == 'e' || any.val[i] == 'E' || any.val[i] == '+' || any.val[i] == '-' {
endPos = i + 1
continue
}
// end position is the first char which is not digit
if any.val[i] >= '0' && any.val[i] <= '9' {
endPos = i + 1
} else {
endPos = i
break
}
}
parsed, _ := strconv.ParseFloat(any.val[:endPos], 64)
return parsed return parsed
} }

View File

@ -14,11 +14,7 @@ func (any *uint32Any) LastError() error {
} }
func (any *uint32Any) ValueType() ValueType { func (any *uint32Any) ValueType() ValueType {
return NumberValue return Number
}
func (any *uint32Any) MustBeValid() Any {
return any
} }
func (any *uint32Any) ToBool() bool { func (any *uint32Any) ToBool() bool {

View File

@ -1,9 +1,105 @@
package jsoniter package jsoniter
import ( import (
"io"
"strconv" "strconv"
"unsafe"
) )
type uint64LazyAny struct {
baseAny
buf []byte
iter *Iterator
err error
cache uint64
}
func (any *uint64LazyAny) ValueType() ValueType {
return Number
}
func (any *uint64LazyAny) Parse() *Iterator {
iter := any.iter
if iter == nil {
iter = NewIterator()
}
iter.ResetBytes(any.buf)
return iter
}
func (any *uint64LazyAny) fillCache() {
if any.err != nil {
return
}
iter := any.Parse()
any.cache = iter.ReadUint64()
if iter.Error != io.EOF {
iter.reportError("intLazyAny", "there are bytes left")
}
any.err = iter.Error
}
func (any *uint64LazyAny) LastError() error {
return any.err
}
func (any *uint64LazyAny) ToBool() bool {
return any.ToInt64() != 0
}
func (any *uint64LazyAny) ToInt() int {
any.fillCache()
return int(any.cache)
}
func (any *uint64LazyAny) ToInt32() int32 {
any.fillCache()
return int32(any.cache)
}
func (any *uint64LazyAny) ToInt64() int64 {
any.fillCache()
return int64(any.cache)
}
func (any *uint64LazyAny) ToUint() uint {
any.fillCache()
return uint(any.cache)
}
func (any *uint64LazyAny) ToUint32() uint32 {
any.fillCache()
return uint32(any.cache)
}
func (any *uint64LazyAny) ToUint64() uint64 {
any.fillCache()
return any.cache
}
func (any *uint64LazyAny) ToFloat32() float32 {
any.fillCache()
return float32(any.cache)
}
func (any *uint64LazyAny) ToFloat64() float64 {
any.fillCache()
return float64(any.cache)
}
func (any *uint64LazyAny) ToString() string {
return *(*string)(unsafe.Pointer(&any.buf))
}
func (any *uint64LazyAny) WriteTo(stream *Stream) {
stream.Write(any.buf)
}
func (any *uint64LazyAny) GetInterface() interface{} {
any.fillCache()
return any.cache
}
type uint64Any struct { type uint64Any struct {
baseAny baseAny
val uint64 val uint64
@ -14,11 +110,7 @@ func (any *uint64Any) LastError() error {
} }
func (any *uint64Any) ValueType() ValueType { func (any *uint64Any) ValueType() ValueType {
return NumberValue return Number
}
func (any *uint64Any) MustBeValid() Any {
return any
} }
func (any *uint64Any) ToBool() bool { func (any *uint64Any) ToBool() bool {

View File

@ -1,335 +0,0 @@
package jsoniter
import (
"encoding/json"
"errors"
"io"
"reflect"
"sync/atomic"
"unsafe"
)
// Config customize how the API should behave.
// The API is created from Config by Froze.
type Config struct {
IndentionStep int
MarshalFloatWith6Digits bool
EscapeHTML bool
SortMapKeys bool
UseNumber bool
TagKey string
ValidateJsonRawMessage bool
}
type frozenConfig struct {
configBeforeFrozen Config
sortMapKeys bool
indentionStep int
decoderCache unsafe.Pointer
encoderCache unsafe.Pointer
extensions []Extension
streamPool chan *Stream
iteratorPool chan *Iterator
}
// API the public interface of this package.
// Primary Marshal and Unmarshal.
type API interface {
IteratorPool
StreamPool
MarshalToString(v interface{}) (string, error)
Marshal(v interface{}) ([]byte, error)
MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
UnmarshalFromString(str string, v interface{}) error
Unmarshal(data []byte, v interface{}) error
Get(data []byte, path ...interface{}) Any
NewEncoder(writer io.Writer) *Encoder
NewDecoder(reader io.Reader) *Decoder
}
// ConfigDefault the default API
var ConfigDefault = Config{
EscapeHTML: true,
}.Froze()
// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior
var ConfigCompatibleWithStandardLibrary = Config{
EscapeHTML: true,
SortMapKeys: true,
ValidateJsonRawMessage: true,
}.Froze()
// ConfigFastest marshals float with only 6 digits precision
var ConfigFastest = Config{
EscapeHTML: false,
MarshalFloatWith6Digits: true,
}.Froze()
// Froze forge API from config
func (cfg Config) Froze() API {
// TODO: cache frozen config
frozenConfig := &frozenConfig{
sortMapKeys: cfg.SortMapKeys,
indentionStep: cfg.IndentionStep,
streamPool: make(chan *Stream, 16),
iteratorPool: make(chan *Iterator, 16),
}
atomic.StorePointer(&frozenConfig.decoderCache, unsafe.Pointer(&map[string]ValDecoder{}))
atomic.StorePointer(&frozenConfig.encoderCache, unsafe.Pointer(&map[string]ValEncoder{}))
if cfg.MarshalFloatWith6Digits {
frozenConfig.marshalFloatWith6Digits()
}
if cfg.EscapeHTML {
frozenConfig.escapeHTML()
}
if cfg.UseNumber {
frozenConfig.useNumber()
}
if cfg.ValidateJsonRawMessage {
frozenConfig.validateJsonRawMessage()
}
frozenConfig.configBeforeFrozen = cfg
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() {
cfg.addDecoderToCache(reflect.TypeOf((*interface{})(nil)).Elem(), &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) {
if iter.WhatIsNext() == NumberValue {
*((*interface{})(ptr)) = json.Number(iter.readNumberAsString())
} else {
*((*interface{})(ptr)) = iter.Read()
}
}})
}
func (cfg *frozenConfig) getTagKey() string {
tagKey := cfg.configBeforeFrozen.TagKey
if tagKey == "" {
return "json"
}
return tagKey
}
func (cfg *frozenConfig) registerExtension(extension Extension) {
cfg.extensions = append(cfg.extensions, extension)
}
type lossyFloat32Encoder struct {
}
func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteFloat32Lossy(*((*float32)(ptr)))
}
func (encoder *lossyFloat32Encoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
}
func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool {
return *((*float32)(ptr)) == 0
}
type lossyFloat64Encoder struct {
}
func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteFloat64Lossy(*((*float64)(ptr)))
}
func (encoder *lossyFloat64Encoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
}
func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool {
return *((*float64)(ptr)) == 0
}
// EnableLossyFloatMarshalling keeps 10**(-6) precision
// for float variables for better performance.
func (cfg *frozenConfig) marshalFloatWith6Digits() {
// for better performance
cfg.addEncoderToCache(reflect.TypeOf((*float32)(nil)).Elem(), &lossyFloat32Encoder{})
cfg.addEncoderToCache(reflect.TypeOf((*float64)(nil)).Elem(), &lossyFloat64Encoder{})
}
type htmlEscapedStringEncoder struct {
}
func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
str := *((*string)(ptr))
stream.WriteStringWithHTMLEscaped(str)
}
func (encoder *htmlEscapedStringEncoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
}
func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return *((*string)(ptr)) == ""
}
func (cfg *frozenConfig) escapeHTML() {
cfg.addEncoderToCache(reflect.TypeOf((*string)(nil)).Elem(), &htmlEscapedStringEncoder{})
}
func (cfg *frozenConfig) addDecoderToCache(cacheKey reflect.Type, decoder ValDecoder) {
done := false
for !done {
ptr := atomic.LoadPointer(&cfg.decoderCache)
cache := *(*map[reflect.Type]ValDecoder)(ptr)
copied := map[reflect.Type]ValDecoder{}
for k, v := range cache {
copied[k] = v
}
copied[cacheKey] = decoder
done = atomic.CompareAndSwapPointer(&cfg.decoderCache, ptr, unsafe.Pointer(&copied))
}
}
func (cfg *frozenConfig) addEncoderToCache(cacheKey reflect.Type, encoder ValEncoder) {
done := false
for !done {
ptr := atomic.LoadPointer(&cfg.encoderCache)
cache := *(*map[reflect.Type]ValEncoder)(ptr)
copied := map[reflect.Type]ValEncoder{}
for k, v := range cache {
copied[k] = v
}
copied[cacheKey] = encoder
done = atomic.CompareAndSwapPointer(&cfg.encoderCache, ptr, unsafe.Pointer(&copied))
}
}
func (cfg *frozenConfig) getDecoderFromCache(cacheKey reflect.Type) ValDecoder {
ptr := atomic.LoadPointer(&cfg.decoderCache)
cache := *(*map[reflect.Type]ValDecoder)(ptr)
return cache[cacheKey]
}
func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) ValEncoder {
ptr := atomic.LoadPointer(&cfg.encoderCache)
cache := *(*map[reflect.Type]ValEncoder)(ptr)
return cache[cacheKey]
}
func (cfg *frozenConfig) cleanDecoders() {
typeDecoders = map[string]ValDecoder{}
fieldDecoders = map[string]ValDecoder{}
*cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
}
func (cfg *frozenConfig) cleanEncoders() {
typeEncoders = map[string]ValEncoder{}
fieldEncoders = map[string]ValEncoder{}
*cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
}
func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) {
stream := cfg.BorrowStream(nil)
defer cfg.ReturnStream(stream)
stream.WriteVal(v)
if stream.Error != nil {
return "", stream.Error
}
return string(stream.Buffer()), nil
}
func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) {
stream := cfg.BorrowStream(nil)
defer cfg.ReturnStream(stream)
stream.WriteVal(v)
if stream.Error != nil {
return nil, stream.Error
}
result := stream.Buffer()
copied := make([]byte, len(result))
copy(copied, result)
return copied, nil
}
func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
if prefix != "" {
panic("prefix is not supported")
}
for _, r := range indent {
if r != ' ' {
panic("indent can only be space")
}
}
newCfg := cfg.configBeforeFrozen
newCfg.IndentionStep = len(indent)
return newCfg.Froze().Marshal(v)
}
func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error {
data := []byte(str)
data = data[:lastNotSpacePos(data)]
iter := cfg.BorrowIterator(data)
defer cfg.ReturnIterator(iter)
iter.ReadVal(v)
if iter.head == iter.tail {
iter.loadMore()
}
if iter.Error == io.EOF {
return nil
}
if iter.Error == nil {
iter.ReportError("UnmarshalFromString", "there are bytes left after unmarshal")
}
return iter.Error
}
func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any {
iter := cfg.BorrowIterator(data)
defer cfg.ReturnIterator(iter)
return locatePath(iter, path)
}
func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error {
data = data[:lastNotSpacePos(data)]
iter := cfg.BorrowIterator(data)
defer cfg.ReturnIterator(iter)
typ := reflect.TypeOf(v)
if typ.Kind() != reflect.Ptr {
// return non-pointer error
return errors.New("the second param must be ptr type")
}
iter.ReadVal(v)
if iter.head == iter.tail {
iter.loadMore()
}
if iter.Error == io.EOF {
return nil
}
if iter.Error == nil {
iter.ReportError("Unmarshal", "there are bytes left after unmarshal")
}
return iter.Error
}
func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder {
stream := NewStream(cfg, writer, 512)
return &Encoder{stream}
}
func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder {
iter := Parse(cfg, reader, 512)
return &Decoder{iter}
}

View File

@ -1,29 +1,27 @@
//
// Besides, jsoniter.Iterator provides a different set of interfaces
// iterating given bytes/string/reader
// and yielding parsed elements one by one.
// This set of interfaces reads input as required and gives
// better performance.
package jsoniter package jsoniter
import ( import (
"encoding/json" "encoding/base64"
"fmt" "fmt"
"io" "io"
) )
// ValueType the type for JSON element
type ValueType int type ValueType int
const ( const (
// InvalidValue invalid JSON element Invalid ValueType = iota
InvalidValue ValueType = iota String
// StringValue JSON element "string" Number
StringValue Nil
// NumberValue JSON element 100 or 0.10 Bool
NumberValue Array
// NilValue JSON element null Object
NilValue
// BoolValue JSON element true or false
BoolValue
// ArrayValue JSON element []
ArrayValue
// ObjectValue JSON element {}
ObjectValue
) )
var hexDigits []byte var hexDigits []byte
@ -45,44 +43,39 @@ func init() {
} }
valueTypes = make([]ValueType, 256) valueTypes = make([]ValueType, 256)
for i := 0; i < len(valueTypes); i++ { for i := 0; i < len(valueTypes); i++ {
valueTypes[i] = InvalidValue valueTypes[i] = Invalid
} }
valueTypes['"'] = StringValue valueTypes['"'] = String
valueTypes['-'] = NumberValue valueTypes['-'] = Number
valueTypes['0'] = NumberValue valueTypes['0'] = Number
valueTypes['1'] = NumberValue valueTypes['1'] = Number
valueTypes['2'] = NumberValue valueTypes['2'] = Number
valueTypes['3'] = NumberValue valueTypes['3'] = Number
valueTypes['4'] = NumberValue valueTypes['4'] = Number
valueTypes['5'] = NumberValue valueTypes['5'] = Number
valueTypes['6'] = NumberValue valueTypes['6'] = Number
valueTypes['7'] = NumberValue valueTypes['7'] = Number
valueTypes['8'] = NumberValue valueTypes['8'] = Number
valueTypes['9'] = NumberValue valueTypes['9'] = Number
valueTypes['t'] = BoolValue valueTypes['t'] = Bool
valueTypes['f'] = BoolValue valueTypes['f'] = Bool
valueTypes['n'] = NilValue valueTypes['n'] = Nil
valueTypes['['] = ArrayValue valueTypes['['] = Array
valueTypes['{'] = ObjectValue valueTypes['{'] = Object
} }
// Iterator is a io.Reader like object, with JSON specific read functions. // Iterator is a fast and flexible JSON parser
// Error is not returned as return value, but stored as Error member on this iterator instance.
type Iterator struct { type Iterator struct {
cfg *frozenConfig reader io.Reader
reader io.Reader buf []byte
buf []byte head int
head int tail int
tail int Error error
captureStartedAt int
captured []byte
Error error
} }
// NewIterator creates an empty Iterator instance // Create creates an empty Iterator instance
func NewIterator(cfg API) *Iterator { func NewIterator() *Iterator {
return &Iterator{ return &Iterator{
cfg: cfg.(*frozenConfig),
reader: nil, reader: nil,
buf: nil, buf: nil,
head: 0, head: 0,
@ -90,10 +83,9 @@ func NewIterator(cfg API) *Iterator {
} }
} }
// Parse creates an Iterator instance from io.Reader // Parse parses a json buffer in io.Reader into an Iterator instance
func Parse(cfg API, reader io.Reader, bufSize int) *Iterator { func Parse(reader io.Reader, bufSize int) *Iterator {
return &Iterator{ return &Iterator{
cfg: cfg.(*frozenConfig),
reader: reader, reader: reader,
buf: make([]byte, bufSize), buf: make([]byte, bufSize),
head: 0, head: 0,
@ -101,10 +93,9 @@ func Parse(cfg API, reader io.Reader, bufSize int) *Iterator {
} }
} }
// ParseBytes creates an Iterator instance from byte array // ParseBytes parses a json byte slice into an Iterator instance
func ParseBytes(cfg API, input []byte) *Iterator { func ParseBytes(input []byte) *Iterator {
return &Iterator{ return &Iterator{
cfg: cfg.(*frozenConfig),
reader: nil, reader: nil,
buf: input, buf: input,
head: 0, head: 0,
@ -112,17 +103,12 @@ func ParseBytes(cfg API, input []byte) *Iterator {
} }
} }
// ParseString creates an Iterator instance from string // ParseString parses a json string into an Iterator instance
func ParseString(cfg API, input string) *Iterator { func ParseString(input string) *Iterator {
return ParseBytes(cfg, []byte(input)) return ParseBytes([]byte(input))
} }
// Pool returns a pool can provide more iterator with same configuration // Reset can reset an Iterator instance for another json buffer in io.Reader
func (iter *Iterator) Pool() IteratorPool {
return iter.cfg
}
// Reset reuse iterator instance by specifying another reader
func (iter *Iterator) Reset(reader io.Reader) *Iterator { func (iter *Iterator) Reset(reader io.Reader) *Iterator {
iter.reader = reader iter.reader = reader
iter.head = 0 iter.head = 0
@ -130,16 +116,17 @@ func (iter *Iterator) Reset(reader io.Reader) *Iterator {
return iter return iter
} }
// ResetBytes reuse iterator instance by specifying another byte array as input // ResetBytes can reset an Iterator instance for another json byte slice
func (iter *Iterator) ResetBytes(input []byte) *Iterator { func (iter *Iterator) ResetBytes(input []byte) *Iterator {
iter.reader = nil iter.reader = nil
iter.Error = nil
iter.buf = input iter.buf = input
iter.head = 0 iter.head = 0
iter.tail = len(input) iter.tail = len(input)
return iter return iter
} }
// WhatIsNext gets ValueType of relatively next json element // WhatIsNext gets ValueType of relatively next json object
func (iter *Iterator) WhatIsNext() ValueType { func (iter *Iterator) WhatIsNext() ValueType {
valueType := valueTypes[iter.nextToken()] valueType := valueTypes[iter.nextToken()]
iter.unreadByte() iter.unreadByte()
@ -159,18 +146,6 @@ func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool {
return true return true
} }
func (iter *Iterator) isObjectEnd() bool {
c := iter.nextToken()
if c == ',' {
return false
}
if c == '}' {
return true
}
iter.ReportError("isObjectEnd", "object ended prematurely")
return true
}
func (iter *Iterator) nextToken() byte { func (iter *Iterator) nextToken() byte {
// a variation of skip whitespaces, returning the next non-whitespace token // a variation of skip whitespaces, returning the next non-whitespace token
for { for {
@ -189,8 +164,7 @@ func (iter *Iterator) nextToken() byte {
} }
} }
// ReportError record a error in iterator instance with current position. func (iter *Iterator) reportError(operation string, msg string) {
func (iter *Iterator) ReportError(operation string, msg string) {
if iter.Error != nil { if iter.Error != nil {
if iter.Error != io.EOF { if iter.Error != io.EOF {
return return
@ -204,7 +178,7 @@ func (iter *Iterator) ReportError(operation string, msg string) {
string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail])) string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
} }
// CurrentBuffer gets current buffer as string for debugging purpose // CurrentBuffer gets current buffer as string
func (iter *Iterator) CurrentBuffer() string { func (iter *Iterator) CurrentBuffer() string {
peekStart := iter.head - 10 peekStart := iter.head - 10
if peekStart < 0 { if peekStart < 0 {
@ -231,16 +205,10 @@ func (iter *Iterator) readByte() (ret byte) {
func (iter *Iterator) loadMore() bool { func (iter *Iterator) loadMore() bool {
if iter.reader == nil { if iter.reader == nil {
if iter.Error == nil { if iter.Error == nil {
iter.head = iter.tail
iter.Error = io.EOF iter.Error = io.EOF
} }
return false return false
} }
if iter.captured != nil {
iter.captured = append(iter.captured,
iter.buf[iter.captureStartedAt:iter.tail]...)
iter.captureStartedAt = 0
}
for { for {
n, err := iter.reader.Read(iter.buf) n, err := iter.reader.Read(iter.buf)
if n == 0 { if n == 0 {
@ -259,49 +227,58 @@ func (iter *Iterator) loadMore() bool {
} }
func (iter *Iterator) unreadByte() { func (iter *Iterator) unreadByte() {
if iter.Error != nil { if iter.head == 0 {
iter.reportError("unreadByte", "unread too many bytes")
return return
} }
iter.head-- iter.head--
return return
} }
// Read read the next JSON element as generic interface{}.
func (iter *Iterator) Read() interface{} { func (iter *Iterator) Read() interface{} {
valueType := iter.WhatIsNext() valueType := iter.WhatIsNext()
switch valueType { switch valueType {
case StringValue: case String:
return iter.ReadString() return iter.ReadString()
case NumberValue: case Number:
if iter.cfg.configBeforeFrozen.UseNumber {
return json.Number(iter.readNumberAsString())
}
return iter.ReadFloat64() return iter.ReadFloat64()
case NilValue: case Nil:
iter.skipFourBytes('n', 'u', 'l', 'l') iter.skipFixedBytes(4) // null
return nil return nil
case BoolValue: case Bool:
return iter.ReadBool() return iter.ReadBool()
case ArrayValue: case Array:
arr := []interface{}{} arr := []interface{}{}
iter.ReadArrayCB(func(iter *Iterator) bool { iter.ReadArrayCB(func(iter *Iterator) bool {
var elem interface{} arr = append(arr, iter.Read())
iter.ReadVal(&elem)
arr = append(arr, elem)
return true return true
}) })
return arr return arr
case ObjectValue: case Object:
obj := map[string]interface{}{} obj := map[string]interface{}{}
iter.ReadMapCB(func(Iter *Iterator, field string) bool { iter.ReadObjectCB(func(Iter *Iterator, field string) bool {
var elem interface{} obj[field] = iter.Read()
iter.ReadVal(&elem)
obj[field] = elem
return true return true
}) })
return obj return obj
default: default:
iter.ReportError("Read", fmt.Sprintf("unexpected value type: %v", valueType)) iter.reportError("Read", fmt.Sprintf("unexpected value type: %v", valueType))
return nil return nil
} }
} }
// ReadBase64 reads a json object as Base64 in byte slice
func (iter *Iterator) ReadBase64() (ret []byte) {
src := iter.ReadStringAsSlice()
if iter.Error != nil {
return
}
b64 := base64.StdEncoding
ret = make([]byte, b64.DecodedLen(len(src)))
n, err := b64.Decode(ret, src)
if err != nil {
iter.Error = err
return
}
return ret[:n]
}

View File

@ -1,11 +1,10 @@
package jsoniter package jsoniter
// ReadArray read array element, tells if the array has more element to read.
func (iter *Iterator) ReadArray() (ret bool) { func (iter *Iterator) ReadArray() (ret bool) {
c := iter.nextToken() c := iter.nextToken()
switch c { switch c {
case 'n': case 'n':
iter.skipThreeBytes('u', 'l', 'l') iter.skipFixedBytes(3)
return false // null return false // null
case '[': case '[':
c = iter.nextToken() c = iter.nextToken()
@ -19,12 +18,11 @@ 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
} }
} }
// ReadArrayCB read array with callback
func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) { func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) {
c := iter.nextToken() c := iter.nextToken()
if c == '[' { if c == '[' {
@ -34,25 +32,19 @@ func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) {
if !callback(iter) { if !callback(iter) {
return false return false
} }
c = iter.nextToken() for iter.nextToken() == ',' {
for c == ',' {
if !callback(iter) { if !callback(iter) {
return false return false
} }
c = iter.nextToken()
}
if c != ']' {
iter.ReportError("ReadArrayCB", "expect ] in the end")
return false
} }
return true return true
} }
return true return true
} }
if c == 'n' { if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l') iter.skipFixedBytes(3)
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

@ -4,7 +4,6 @@ import (
"io" "io"
"math/big" "math/big"
"strconv" "strconv"
"strings"
"unsafe" "unsafe"
) )
@ -31,7 +30,6 @@ func init() {
floatDigits['.'] = dotInNumber floatDigits['.'] = dotInNumber
} }
// ReadBigFloat read big.Float
func (iter *Iterator) ReadBigFloat() (ret *big.Float) { func (iter *Iterator) ReadBigFloat() (ret *big.Float) {
str := iter.readNumberAsString() str := iter.readNumberAsString()
if iter.Error != nil && iter.Error != io.EOF { if iter.Error != nil && iter.Error != io.EOF {
@ -49,7 +47,6 @@ func (iter *Iterator) ReadBigFloat() (ret *big.Float) {
return val return val
} }
// ReadBigInt read big.Int
func (iter *Iterator) ReadBigInt() (ret *big.Int) { func (iter *Iterator) ReadBigInt() (ret *big.Int) {
str := iter.readNumberAsString() str := iter.readNumberAsString()
if iter.Error != nil && iter.Error != io.EOF { if iter.Error != nil && iter.Error != io.EOF {
@ -59,55 +56,26 @@ func (iter *Iterator) ReadBigInt() (ret *big.Int) {
var success bool var success bool
ret, success = ret.SetString(str, 10) ret, success = ret.SetString(str, 10)
if !success { if !success {
iter.ReportError("ReadBigInt", "invalid big int") iter.reportError("ReadBigInt", "invalid big int")
return nil return nil
} }
return ret return ret
} }
//ReadFloat32 read float32
func (iter *Iterator) ReadFloat32() (ret float32) { func (iter *Iterator) ReadFloat32() (ret float32) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
return -iter.readPositiveFloat32() return -iter.readPositiveFloat32()
} else {
iter.unreadByte()
return iter.readPositiveFloat32()
} }
iter.unreadByte()
return iter.readPositiveFloat32()
} }
func (iter *Iterator) readPositiveFloat32() (ret float32) { func (iter *Iterator) readPositiveFloat32() (ret float32) {
value := uint64(0) value := uint64(0)
c := byte(' ') c := byte(' ')
i := iter.head i := iter.head
// first char
if i == iter.tail {
return iter.readFloat32SlowPath()
}
c = iter.buf[i]
i++
ind := floatDigits[c]
switch ind {
case invalidCharForNumber:
return iter.readFloat32SlowPath()
case endOfNumber:
iter.ReportError("readFloat32", "empty number")
return
case dotInNumber:
iter.ReportError("readFloat32", "leading dot is invalid")
return
case 0:
if i == iter.tail {
return iter.readFloat32SlowPath()
}
c = iter.buf[i]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
iter.ReportError("readFloat32", "leading zero is invalid")
return
}
}
value = uint64(ind)
// chars before dot
non_decimal_loop: non_decimal_loop:
for ; i < iter.tail; i++ { for ; i < iter.tail; i++ {
c = iter.buf[i] c = iter.buf[i]
@ -126,21 +94,17 @@ non_decimal_loop:
} }
value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind;
} }
// chars after dot
if c == '.' { if c == '.' {
i++ i++
decimalPlaces := 0 decimalPlaces := 0
if i == iter.tail {
return iter.readFloat32SlowPath()
}
for ; i < iter.tail; i++ { for ; i < iter.tail; i++ {
c = iter.buf[i] c = iter.buf[i]
ind := floatDigits[c] ind := floatDigits[c]
switch ind { switch ind {
case endOfNumber: case endOfNumber:
if decimalPlaces > 0 && decimalPlaces < len(pow10) { if decimalPlaces > 0 && decimalPlaces < len(POW10) {
iter.head = i iter.head = i
return float32(float64(value) / float64(pow10[decimalPlaces])) return float32(float64(value) / float64(POW10[decimalPlaces]))
} }
// too many decimal places // too many decimal places
return iter.readFloat32SlowPath() return iter.readFloat32SlowPath()
@ -167,7 +131,7 @@ load_loop:
for i := iter.head; i < iter.tail; i++ { for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i] c := iter.buf[i]
switch c { switch c {
case '+', '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
str = append(str, c) str = append(str, c)
continue continue
default: default:
@ -183,7 +147,7 @@ load_loop:
return return
} }
if len(str) == 0 { if len(str) == 0 {
iter.ReportError("readNumberAsString", "invalid number") iter.reportError("readNumberAsString", "invalid number")
} }
return *(*string)(unsafe.Pointer(&str)) return *(*string)(unsafe.Pointer(&str))
} }
@ -193,11 +157,6 @@ func (iter *Iterator) readFloat32SlowPath() (ret float32) {
if iter.Error != nil && iter.Error != io.EOF { if iter.Error != nil && iter.Error != io.EOF {
return return
} }
errMsg := validateFloat(str)
if errMsg != "" {
iter.ReportError("readFloat32SlowPath", errMsg)
return
}
val, err := strconv.ParseFloat(str, 32) val, err := strconv.ParseFloat(str, 32)
if err != nil { if err != nil {
iter.Error = err iter.Error = err
@ -206,49 +165,20 @@ func (iter *Iterator) readFloat32SlowPath() (ret float32) {
return float32(val) return float32(val)
} }
// ReadFloat64 read float64
func (iter *Iterator) ReadFloat64() (ret float64) { func (iter *Iterator) ReadFloat64() (ret float64) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
return -iter.readPositiveFloat64() return -iter.readPositiveFloat64()
} else {
iter.unreadByte()
return iter.readPositiveFloat64()
} }
iter.unreadByte()
return iter.readPositiveFloat64()
} }
func (iter *Iterator) readPositiveFloat64() (ret float64) { func (iter *Iterator) readPositiveFloat64() (ret float64) {
value := uint64(0) value := uint64(0)
c := byte(' ') c := byte(' ')
i := iter.head i := iter.head
// first char
if i == iter.tail {
return iter.readFloat64SlowPath()
}
c = iter.buf[i]
i++
ind := floatDigits[c]
switch ind {
case invalidCharForNumber:
return iter.readFloat64SlowPath()
case endOfNumber:
iter.ReportError("readFloat64", "empty number")
return
case dotInNumber:
iter.ReportError("readFloat64", "leading dot is invalid")
return
case 0:
if i == iter.tail {
return iter.readFloat64SlowPath()
}
c = iter.buf[i]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
iter.ReportError("readFloat64", "leading zero is invalid")
return
}
}
value = uint64(ind)
// chars before dot
non_decimal_loop: non_decimal_loop:
for ; i < iter.tail; i++ { for ; i < iter.tail; i++ {
c = iter.buf[i] c = iter.buf[i]
@ -267,21 +197,17 @@ non_decimal_loop:
} }
value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind; value = (value << 3) + (value << 1) + uint64(ind) // value = value * 10 + ind;
} }
// chars after dot
if c == '.' { if c == '.' {
i++ i++
decimalPlaces := 0 decimalPlaces := 0
if i == iter.tail {
return iter.readFloat64SlowPath()
}
for ; i < iter.tail; i++ { for ; i < iter.tail; i++ {
c = iter.buf[i] c = iter.buf[i]
ind := floatDigits[c] ind := floatDigits[c]
switch ind { switch ind {
case endOfNumber: case endOfNumber:
if decimalPlaces > 0 && decimalPlaces < len(pow10) { if decimalPlaces > 0 && decimalPlaces < len(POW10) {
iter.head = i iter.head = i
return float64(value) / float64(pow10[decimalPlaces]) return float64(value) / float64(POW10[decimalPlaces])
} }
// too many decimal places // too many decimal places
return iter.readFloat64SlowPath() return iter.readFloat64SlowPath()
@ -305,11 +231,6 @@ func (iter *Iterator) readFloat64SlowPath() (ret float64) {
if iter.Error != nil && iter.Error != io.EOF { if iter.Error != nil && iter.Error != io.EOF {
return return
} }
errMsg := validateFloat(str)
if errMsg != "" {
iter.ReportError("readFloat64SlowPath", errMsg)
return
}
val, err := strconv.ParseFloat(str, 64) val, err := strconv.ParseFloat(str, 64)
if err != nil { if err != nil {
iter.Error = err iter.Error = err
@ -317,25 +238,3 @@ func (iter *Iterator) readFloat64SlowPath() (ret float64) {
} }
return val return val
} }
func validateFloat(str string) string {
// strconv.ParseFloat is not validating `1.` or `1.e1`
if len(str) == 0 {
return "empty number"
}
if str[0] == '-' {
return "-- is not valid"
}
dotPos := strings.IndexByte(str, '.')
if dotPos != -1 {
if dotPos == len(str)-1 {
return "dot can not be last character"
}
switch str[dotPos+1] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
default:
return "missing digit after dot"
}
}
return ""
}

View File

@ -1,7 +1,6 @@
package jsoniter package jsoniter
import ( import (
"math"
"strconv" "strconv"
) )
@ -9,6 +8,12 @@ var intDigits []int8
const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1 const uint32SafeToMultiply10 = uint32(0xffffffff)/10 - 1
const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1 const uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1
const int64Max = uint64(0x7fffffffffffffff)
const int32Max = uint32(0x7fffffff)
const int16Max = uint32(0x7fff)
const uint16Max = uint32(0xffff)
const int8Max = uint32(0x7fff)
const uint8Max = uint32(0xffff)
func init() { func init() {
intDigits = make([]int8, 256) intDigits = make([]int8, 256)
@ -20,94 +25,89 @@ func init() {
} }
} }
// ReadUint read uint
func (iter *Iterator) ReadUint() uint { func (iter *Iterator) ReadUint() uint {
return uint(iter.ReadUint64()) return uint(iter.ReadUint64())
} }
// ReadInt read int
func (iter *Iterator) ReadInt() int { func (iter *Iterator) ReadInt() int {
return int(iter.ReadInt64()) return int(iter.ReadInt64())
} }
// ReadInt8 read int8
func (iter *Iterator) ReadInt8() (ret int8) { func (iter *Iterator) ReadInt8() (ret int8) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
val := iter.readUint32(iter.readByte()) val := iter.readUint32(iter.readByte())
if val > math.MaxInt8+1 { if val > int8Max+1 {
iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10)) iter.reportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10))
return return
} }
return -int8(val) return -int8(val)
} else {
val := iter.readUint32(c)
if val > int8Max {
iter.reportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10))
return
}
return int8(val)
} }
val := iter.readUint32(c)
if val > math.MaxInt8 {
iter.ReportError("ReadInt8", "overflow: "+strconv.FormatInt(int64(val), 10))
return
}
return int8(val)
} }
// ReadUint8 read uint8
func (iter *Iterator) ReadUint8() (ret uint8) { func (iter *Iterator) ReadUint8() (ret uint8) {
val := iter.readUint32(iter.nextToken()) val := iter.readUint32(iter.nextToken())
if val > math.MaxUint8 { if val > uint8Max {
iter.ReportError("ReadUint8", "overflow: "+strconv.FormatInt(int64(val), 10)) iter.reportError("ReadUint8", "overflow: "+strconv.FormatInt(int64(val), 10))
return return
} }
return uint8(val) return uint8(val)
} }
// ReadInt16 read int16
func (iter *Iterator) ReadInt16() (ret int16) { func (iter *Iterator) ReadInt16() (ret int16) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
val := iter.readUint32(iter.readByte()) val := iter.readUint32(iter.readByte())
if val > math.MaxInt16+1 { if val > int16Max+1 {
iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10)) iter.reportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10))
return return
} }
return -int16(val) return -int16(val)
} else {
val := iter.readUint32(c)
if val > int16Max {
iter.reportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10))
return
}
return int16(val)
} }
val := iter.readUint32(c)
if val > math.MaxInt16 {
iter.ReportError("ReadInt16", "overflow: "+strconv.FormatInt(int64(val), 10))
return
}
return int16(val)
} }
// ReadUint16 read uint16
func (iter *Iterator) ReadUint16() (ret uint16) { func (iter *Iterator) ReadUint16() (ret uint16) {
val := iter.readUint32(iter.nextToken()) val := iter.readUint32(iter.nextToken())
if val > math.MaxUint16 { if val > uint16Max {
iter.ReportError("ReadUint16", "overflow: "+strconv.FormatInt(int64(val), 10)) iter.reportError("ReadUint16", "overflow: "+strconv.FormatInt(int64(val), 10))
return return
} }
return uint16(val) return uint16(val)
} }
// ReadInt32 read int32
func (iter *Iterator) ReadInt32() (ret int32) { func (iter *Iterator) ReadInt32() (ret int32) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
val := iter.readUint32(iter.readByte()) val := iter.readUint32(iter.readByte())
if val > math.MaxInt32+1 { if val > int32Max+1 {
iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10)) iter.reportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10))
return return
} }
return -int32(val) return -int32(val)
} else {
val := iter.readUint32(c)
if val > int32Max {
iter.reportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10))
return
}
return int32(val)
} }
val := iter.readUint32(c)
if val > math.MaxInt32 {
iter.ReportError("ReadInt32", "overflow: "+strconv.FormatInt(int64(val), 10))
return
}
return int32(val)
} }
// ReadUint32 read uint32
func (iter *Iterator) ReadUint32() (ret uint32) { func (iter *Iterator) ReadUint32() (ret uint32) {
return iter.readUint32(iter.nextToken()) return iter.readUint32(iter.nextToken())
} }
@ -118,7 +118,7 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) {
return 0 // single zero return 0 // single zero
} }
if ind == invalidCharForNumber { if ind == invalidCharForNumber {
iter.ReportError("readUint32", "unexpected character: "+string([]byte{byte(ind)})) iter.reportError("readUint32", "unexpected character: "+string([]byte{byte(ind)}))
return return
} }
value := uint32(ind) value := uint32(ind)
@ -185,11 +185,12 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) {
if value > uint32SafeToMultiply10 { if value > uint32SafeToMultiply10 {
value2 := (value << 3) + (value << 1) + uint32(ind) value2 := (value << 3) + (value << 1) + uint32(ind)
if value2 < value { if value2 < value {
iter.ReportError("readUint32", "overflow") iter.reportError("readUint32", "overflow")
return return
} else {
value = value2
continue
} }
value = value2
continue
} }
value = (value << 3) + (value << 1) + uint32(ind) value = (value << 3) + (value << 1) + uint32(ind)
} }
@ -199,26 +200,25 @@ func (iter *Iterator) readUint32(c byte) (ret uint32) {
} }
} }
// ReadInt64 read int64
func (iter *Iterator) ReadInt64() (ret int64) { func (iter *Iterator) ReadInt64() (ret int64) {
c := iter.nextToken() c := iter.nextToken()
if c == '-' { if c == '-' {
val := iter.readUint64(iter.readByte()) val := iter.readUint64(iter.readByte())
if val > math.MaxInt64+1 { if val > int64Max+1 {
iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10)) iter.reportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10))
return return
} }
return -int64(val) return -int64(val)
} else {
val := iter.readUint64(c)
if val > int64Max {
iter.reportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10))
return
}
return int64(val)
} }
val := iter.readUint64(c)
if val > math.MaxInt64 {
iter.ReportError("ReadInt64", "overflow: "+strconv.FormatUint(uint64(val), 10))
return
}
return int64(val)
} }
// ReadUint64 read uint64
func (iter *Iterator) ReadUint64() uint64 { func (iter *Iterator) ReadUint64() uint64 {
return iter.readUint64(iter.nextToken()) return iter.readUint64(iter.nextToken())
} }
@ -229,7 +229,7 @@ func (iter *Iterator) readUint64(c byte) (ret uint64) {
return 0 // single zero return 0 // single zero
} }
if ind == invalidCharForNumber { if ind == invalidCharForNumber {
iter.ReportError("readUint64", "unexpected character: "+string([]byte{byte(ind)})) iter.reportError("readUint64", "unexpected character: "+string([]byte{byte(ind)}))
return return
} }
value := uint64(ind) value := uint64(ind)
@ -243,11 +243,12 @@ func (iter *Iterator) readUint64(c byte) (ret uint64) {
if value > uint64SafeToMultiple10 { if value > uint64SafeToMultiple10 {
value2 := (value << 3) + (value << 1) + uint64(ind) value2 := (value << 3) + (value << 1) + uint64(ind)
if value2 < value { if value2 < value {
iter.ReportError("readUint64", "overflow") iter.reportError("readUint64", "overflow")
return return
} else {
value = value2
continue
} }
value = value2
continue
} }
value = (value << 3) + (value << 1) + uint64(ind) value = (value << 3) + (value << 1) + uint64(ind)
} }

View File

@ -3,17 +3,13 @@ package jsoniter
import ( import (
"fmt" "fmt"
"unicode" "unicode"
"unsafe"
) )
// ReadObject read one field from object.
// If object ended, returns empty string.
// Otherwise, returns the field name.
func (iter *Iterator) ReadObject() (ret string) { func (iter *Iterator) ReadObject() (ret string) {
c := iter.nextToken() c := iter.nextToken()
switch c { switch c {
case 'n': case 'n':
iter.skipThreeBytes('u', 'l', 'l') iter.skipFixedBytes(3)
return "" // null return "" // null
case '{': case '{':
c = iter.nextToken() c = iter.nextToken()
@ -24,14 +20,14 @@ func (iter *Iterator) ReadObject() (ret string) {
if c == '}' { if c == '}' {
return "" // end of object return "" // end of object
} }
iter.ReportError("ReadObject", `expect " after {`) iter.reportError("ReadObject", `expect " after {`)
return return
case ',': case ',':
return string(iter.readObjectFieldAsBytes()) return string(iter.readObjectFieldAsBytes())
case '}': case '}':
return "" // end of object return "" // end of object
default: default:
iter.ReportError("ReadObject", fmt.Sprintf(`expect { or , or } or n, but found %s`, string([]byte{c}))) iter.reportError("ReadObject", fmt.Sprintf(`expect { or , or } or n, but found %s`, string([]byte{c})))
return return
} }
} }
@ -51,7 +47,7 @@ func (iter *Iterator) readFieldHash() int32 {
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 int32(hash) return int32(hash)
} }
@ -59,12 +55,12 @@ func (iter *Iterator) readFieldHash() int32 {
hash *= 0x1000193 hash *= 0x1000193
} }
if !iter.loadMore() { if !iter.loadMore() {
iter.ReportError("readFieldHash", `incomplete field name`) iter.reportError("readFieldHash", `incomplete field name`)
return 0 return 0
} }
} }
} }
iter.ReportError("readFieldHash", `expect ", but found `+string([]byte{c})) iter.reportError("readFieldHash", `expect ", but found `+string([]byte{c}))
return 0 return 0
} }
@ -77,46 +73,38 @@ func calcHash(str string) int32 {
return int32(hash) return int32(hash)
} }
// 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()
if c == '{' { if c == '{' {
c = iter.nextToken() c = iter.nextToken()
if c == '"' { if c == '"' {
iter.unreadByte() iter.unreadByte()
field := iter.readObjectFieldAsBytes() field := string(iter.readObjectFieldAsBytes())
if !callback(iter, *(*string)(unsafe.Pointer(&field))) { if !callback(iter, field) {
return false return false
} }
c = iter.nextToken() for iter.nextToken() == ',' {
for c == ',' { field = string(iter.readObjectFieldAsBytes())
field = iter.readObjectFieldAsBytes() if !callback(iter, field) {
if !callback(iter, *(*string)(unsafe.Pointer(&field))) {
return false return false
} }
c = iter.nextToken()
}
if c != '}' {
iter.ReportError("ReadObjectCB", `object not ended with }`)
return false
} }
return true return true
} }
if c == '}' { if c == '}' {
return true return true
} }
iter.ReportError("ReadObjectCB", `expect " after }`) iter.reportError("ReadObjectCB", `expect " after }`)
return false return false
} }
if c == 'n' { if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l') iter.skipFixedBytes(3)
return true // null return true // null
} }
iter.ReportError("ReadObjectCB", `expect { or n`) iter.reportError("ReadObjectCB", `expect { or n`)
return false return false
} }
// ReadMapCB read map with callback, the key can be any string
func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool { func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
c := iter.nextToken() c := iter.nextToken()
if c == '{' { if c == '{' {
@ -125,41 +113,35 @@ 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")
return false return false
} }
if !callback(iter, field) { if !callback(iter, field) {
return false return false
} }
c = iter.nextToken() for iter.nextToken() == ',' {
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")
return false return false
} }
if !callback(iter, field) { if !callback(iter, field) {
return false return false
} }
c = iter.nextToken()
}
if c != '}' {
iter.ReportError("ReadMapCB", `object not ended with }`)
return false
} }
return true return true
} }
if c == '}' { if c == '}' {
return true return true
} }
iter.ReportError("ReadMapCB", `expect " after }`) iter.reportError("ReadMapCB", `expect " after }`)
return false return false
} }
if c == 'n' { if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l') iter.skipFixedBytes(3)
return true // null return true // null
} }
iter.ReportError("ReadMapCB", `expect { or n`) iter.reportError("ReadMapCB", `expect { or n`)
return false return false
} }
@ -173,10 +155,10 @@ func (iter *Iterator) readObjectStart() bool {
iter.unreadByte() iter.unreadByte()
return true return true
} else if c == 'n' { } else if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l') iter.skipFixedBytes(3)
return false return false
} }
iter.ReportError("readObjectStart", "expect { or n") iter.reportError("readObjectStart", "expect { or n")
return false return false
} }
@ -192,7 +174,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")
return return
} }
iter.head++ iter.head++

View File

@ -7,62 +7,36 @@ import "fmt"
func (iter *Iterator) ReadNil() (ret bool) { func (iter *Iterator) ReadNil() (ret bool) {
c := iter.nextToken() c := iter.nextToken()
if c == 'n' { if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l') // null iter.skipFixedBytes(3) // null
return true return true
} }
iter.unreadByte() iter.unreadByte()
return false return false
} }
// ReadBool reads a json object as BoolValue // ReadBool reads a json object as Bool
func (iter *Iterator) ReadBool() (ret bool) { func (iter *Iterator) ReadBool() (ret bool) {
c := iter.nextToken() c := iter.nextToken()
if c == 't' { if c == 't' {
iter.skipThreeBytes('r', 'u', 'e') iter.skipFixedBytes(3)
return true return true
} }
if c == 'f' { if c == 'f' {
iter.skipFourBytes('a', 'l', 's', 'e') iter.skipFixedBytes(4)
return false return false
} }
iter.ReportError("ReadBool", "expect t or f") iter.reportError("ReadBool", "expect t or f")
return return
} }
// SkipAndReturnBytes skip next JSON element, and return its content as []byte.
// The []byte can be kept, it is a copy of data.
func (iter *Iterator) SkipAndReturnBytes() []byte { func (iter *Iterator) SkipAndReturnBytes() []byte {
iter.startCapture(iter.head) if iter.reader != nil {
panic("reader input does not support this api")
}
before := iter.head
iter.Skip() iter.Skip()
return iter.stopCapture() after := iter.head
} return iter.buf[before:after]
type captureBuffer struct {
startedAt int
captured []byte
}
func (iter *Iterator) startCapture(captureStartedAt int) {
if iter.captured != nil {
panic("already in capture mode")
}
iter.captureStartedAt = captureStartedAt
iter.captured = make([]byte, 0, 32)
}
func (iter *Iterator) stopCapture() []byte {
if iter.captured == nil {
panic("not in capture mode")
}
captured := iter.captured
remaining := iter.buf[iter.captureStartedAt:iter.head]
iter.captureStartedAt = -1
iter.captured = nil
if len(captured) == 0 {
return remaining
}
captured = append(captured, remaining...)
return captured
} }
// Skip skips a json object and positions to relatively the next json object // Skip skips a json object and positions to relatively the next json object
@ -71,57 +45,172 @@ func (iter *Iterator) Skip() {
switch c { switch c {
case '"': case '"':
iter.skipString() iter.skipString()
case 'n': case 'n', 't':
iter.skipThreeBytes('u', 'l', 'l') // null iter.skipFixedBytes(3) // null or true
case 't':
iter.skipThreeBytes('r', 'u', 'e') // true
case 'f': case 'f':
iter.skipFourBytes('a', 'l', 's', 'e') // false iter.skipFixedBytes(4) // false
case '0': case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
iter.unreadByte() iter.skipUntilBreak()
iter.ReadFloat32()
case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9':
iter.skipNumber()
case '[': case '[':
iter.skipArray() iter.skipArray()
case '{': case '{':
iter.skipObject() iter.skipObject()
default: default:
iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c)) iter.reportError("Skip", fmt.Sprintf("do not know how to skip: %v", c))
return return
} }
} }
func (iter *Iterator) skipFourBytes(b1, b2, b3, b4 byte) { func (iter *Iterator) skipString() {
if iter.readByte() != b1 { for {
iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) end, escaped := iter.findStringEnd()
return if end == -1 {
} if !iter.loadMore() {
if iter.readByte() != b2 { iter.reportError("skipString", "incomplete string")
iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) return
return }
} if escaped {
if iter.readByte() != b3 { iter.head = 1 // skip the first char as last char read is \
iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) }
return } else {
} iter.head = end
if iter.readByte() != b4 { return
iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4}))) }
return
} }
} }
func (iter *Iterator) skipThreeBytes(b1, b2, b3 byte) { // adapted from: https://github.com/buger/jsonparser/blob/master/parser.go
if iter.readByte() != b1 { // Tries to find the end of string
iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) // Support if string contains escaped quote symbols.
return func (iter *Iterator) findStringEnd() (int, bool) {
escaped := false
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
if c == '"' {
if !escaped {
return i + 1, false
}
j := i - 1
for {
if j < iter.head || iter.buf[j] != '\\' {
// even number of backslashes
// either end of buffer, or " found
return i + 1, true
}
j--
if j < iter.head || iter.buf[j] != '\\' {
// odd number of backslashes
// it is \" or \\\"
break
}
j--
}
} else if c == '\\' {
escaped = true
}
} }
if iter.readByte() != b2 { j := iter.tail - 1
iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) for {
return if j < iter.head || iter.buf[j] != '\\' {
// even number of backslashes
// either end of buffer, or " found
return -1, false // do not end with \
}
j--
if j < iter.head || iter.buf[j] != '\\' {
// odd number of backslashes
// it is \" or \\\"
break
}
j--
} }
if iter.readByte() != b3 { return -1, true // end with \
iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3}))) }
return
func (iter *Iterator) skipArray() {
level := 1
for {
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '[': // If open symbol, increase level
level++
case ']': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
return
}
}
}
if !iter.loadMore() {
iter.reportError("skipObject", "incomplete array")
return
}
}
}
func (iter *Iterator) skipObject() {
level := 1
for {
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '{': // If open symbol, increase level
level++
case '}': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
return
}
}
}
if !iter.loadMore() {
iter.reportError("skipObject", "incomplete object")
return
}
}
}
func (iter *Iterator) skipUntilBreak() {
// true, false, null, number
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\r', '\t', ',', '}', ']':
iter.head = i
return
}
}
if !iter.loadMore() {
return
}
}
}
func (iter *Iterator) skipFixedBytes(n int) {
iter.head += n
if iter.head >= iter.tail {
more := iter.head - iter.tail
if !iter.loadMore() {
if more > 0 {
iter.reportError("skipFixedBytes", "unexpected end")
}
return
}
iter.head += more
} }
} }

View File

@ -1,144 +0,0 @@
//+build jsoniter-sloppy
package jsoniter
// sloppy but faster implementation, do not validate the input json
func (iter *Iterator) skipNumber() {
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\r', '\t', ',', '}', ']':
iter.head = i
return
}
}
if !iter.loadMore() {
return
}
}
}
func (iter *Iterator) skipArray() {
level := 1
for {
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '[': // If open symbol, increase level
level++
case ']': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
return
}
}
}
if !iter.loadMore() {
iter.ReportError("skipObject", "incomplete array")
return
}
}
}
func (iter *Iterator) skipObject() {
level := 1
for {
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '{': // If open symbol, increase level
level++
case '}': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
return
}
}
}
if !iter.loadMore() {
iter.ReportError("skipObject", "incomplete object")
return
}
}
}
func (iter *Iterator) skipString() {
for {
end, escaped := iter.findStringEnd()
if end == -1 {
if !iter.loadMore() {
iter.ReportError("skipString", "incomplete string")
return
}
if escaped {
iter.head = 1 // skip the first char as last char read is \
}
} else {
iter.head = end
return
}
}
}
// adapted from: https://github.com/buger/jsonparser/blob/master/parser.go
// Tries to find the end of string
// Support if string contains escaped quote symbols.
func (iter *Iterator) findStringEnd() (int, bool) {
escaped := false
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
if c == '"' {
if !escaped {
return i + 1, false
}
j := i - 1
for {
if j < iter.head || iter.buf[j] != '\\' {
// even number of backslashes
// either end of buffer, or " found
return i + 1, true
}
j--
if j < iter.head || iter.buf[j] != '\\' {
// odd number of backslashes
// it is \" or \\\"
break
}
j--
}
} else if c == '\\' {
escaped = true
}
}
j := iter.tail - 1
for {
if j < iter.head || iter.buf[j] != '\\' {
// even number of backslashes
// either end of buffer, or " found
return -1, false // do not end with \
}
j--
if j < iter.head || iter.buf[j] != '\\' {
// odd number of backslashes
// it is \" or \\\"
break
}
j--
}
return -1, true // end with \
}

View File

@ -1,89 +0,0 @@
//+build !jsoniter-sloppy
package jsoniter
import "fmt"
func (iter *Iterator) skipNumber() {
if !iter.trySkipNumber() {
iter.unreadByte()
iter.ReadFloat32()
}
}
func (iter *Iterator) trySkipNumber() bool {
dotFound := false
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
case '.':
if dotFound {
iter.ReportError("validateNumber", `more than one dot found in number`)
return true // already failed
}
if i+1 == iter.tail {
return false
}
c = iter.buf[i+1]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
default:
iter.ReportError("validateNumber", `missing digit after dot`)
return true // already failed
}
dotFound = true
default:
switch c {
case ',', ']', '}', ' ', '\t', '\n', '\r':
if iter.head == i {
return false // if - without following digits
}
iter.head = i
return true // must be valid
}
return false // may be invalid
}
}
return false
}
func (iter *Iterator) skipString() {
if !iter.trySkipString() {
iter.unreadByte()
iter.ReadString()
}
}
func (iter *Iterator) trySkipString() bool {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
if c == '"' {
iter.head = i + 1
return true // valid
} else if c == '\\' {
return false
} else if c < ' ' {
iter.ReportError("trySkipString",
fmt.Sprintf(`invalid control character found: %d`, c))
return true // already failed
}
}
return false
}
func (iter *Iterator) skipObject() {
iter.unreadByte()
iter.ReadObjectCB(func(iter *Iterator, field string) bool {
iter.Skip()
return true
})
}
func (iter *Iterator) skipArray() {
iter.unreadByte()
iter.ReadArrayCB(func(iter *Iterator) bool {
iter.Skip()
return true
})
}

View File

@ -1,11 +1,9 @@
package jsoniter package jsoniter
import ( import (
"fmt"
"unicode/utf16" "unicode/utf16"
) )
// ReadString read string from iterator
func (iter *Iterator) ReadString() (ret string) { func (iter *Iterator) ReadString() (ret string) {
c := iter.nextToken() c := iter.nextToken()
if c == '"' { if c == '"' {
@ -17,18 +15,14 @@ func (iter *Iterator) ReadString() (ret string) {
return ret return ret
} else if c == '\\' { } else if c == '\\' {
break break
} else if c < ' ' {
iter.ReportError("ReadString",
fmt.Sprintf(`invalid control character found: %d`, c))
return
} }
} }
return iter.readStringSlowPath() return iter.readStringSlowPath()
} else if c == 'n' { } else if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l') iter.skipFixedBytes(3)
return "" return ""
} }
iter.ReportError("ReadString", `expects " or n`) iter.reportError("ReadString", `expects " or n`)
return return
} }
@ -42,77 +36,66 @@ func (iter *Iterator) readStringSlowPath() (ret string) {
} }
if c == '\\' { if c == '\\' {
c = iter.readByte() c = iter.readByte()
str = iter.readEscapedChar(c, str) switch c {
case 'u', 'U':
r := iter.readU4()
if utf16.IsSurrogate(r) {
c = iter.readByte()
if iter.Error != nil {
return
}
if c != '\\' {
iter.reportError("ReadString",
`expects \u after utf16 surrogate, but \ not found`)
return
}
c = iter.readByte()
if iter.Error != nil {
return
}
if c != 'u' && c != 'U' {
iter.reportError("ReadString",
`expects \u after utf16 surrogate, but \u not found`)
return
}
r2 := iter.readU4()
if iter.Error != nil {
return
}
combined := utf16.DecodeRune(r, r2)
str = appendRune(str, combined)
} else {
str = appendRune(str, r)
}
case '"':
str = append(str, '"')
case '\\':
str = append(str, '\\')
case '/':
str = append(str, '/')
case 'b':
str = append(str, '\b')
case 'f':
str = append(str, '\f')
case 'n':
str = append(str, '\n')
case 'r':
str = append(str, '\r')
case 't':
str = append(str, '\t')
default:
iter.reportError("ReadString",
`invalid escape char after \`)
return
}
} else { } else {
str = append(str, c) str = append(str, c)
} }
} }
iter.ReportError("readStringSlowPath", "unexpected end of input") iter.reportError("ReadString", "unexpected end of input")
return return
} }
func (iter *Iterator) readEscapedChar(c byte, str []byte) []byte {
switch c {
case 'u':
r := iter.readU4()
if utf16.IsSurrogate(r) {
c = iter.readByte()
if iter.Error != nil {
return nil
}
if c != '\\' {
iter.unreadByte()
str = appendRune(str, r)
return str
}
c = iter.readByte()
if iter.Error != nil {
return nil
}
if c != 'u' {
str = appendRune(str, r)
return iter.readEscapedChar(c, str)
}
r2 := iter.readU4()
if iter.Error != nil {
return nil
}
combined := utf16.DecodeRune(r, r2)
if combined == '\uFFFD' {
str = appendRune(str, r)
str = appendRune(str, r2)
} else {
str = appendRune(str, combined)
}
} else {
str = appendRune(str, r)
}
case '"':
str = append(str, '"')
case '\\':
str = append(str, '\\')
case '/':
str = append(str, '/')
case 'b':
str = append(str, '\b')
case 'f':
str = append(str, '\f')
case 'n':
str = append(str, '\n')
case 'r':
str = append(str, '\r')
case 't':
str = append(str, '\t')
default:
iter.ReportError("readEscapedChar",
`invalid escape char after \`)
return nil
}
return str
}
// ReadStringAsSlice read string from iterator without copying into string form.
// The []byte can not be kept, as it will change after next iterator call.
func (iter *Iterator) ReadStringAsSlice() (ret []byte) { func (iter *Iterator) ReadStringAsSlice() (ret []byte) {
c := iter.nextToken() c := iter.nextToken()
if c == '"' { if c == '"' {
@ -139,7 +122,7 @@ func (iter *Iterator) ReadStringAsSlice() (ret []byte) {
} }
return copied return copied
} }
iter.ReportError("ReadStringAsSlice", `expects " or n`) iter.reportError("ReadString", `expects " or n`)
return return
} }
@ -156,7 +139,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")
return return
} }
} }

View File

@ -1,15 +0,0 @@
package jsoniter
import "encoding/json"
type Number string
func CastJsonNumber(val interface{}) (string, bool) {
switch typedVal := val.(type) {
case json.Number:
return string(typedVal), true
case Number:
return string(typedVal), true
}
return "", false
}

View File

@ -1,57 +0,0 @@
package jsoniter
import (
"io"
)
// IteratorPool a thread safe pool of iterators with same configuration
type IteratorPool interface {
BorrowIterator(data []byte) *Iterator
ReturnIterator(iter *Iterator)
}
// StreamPool a thread safe pool of streams with same configuration
type StreamPool interface {
BorrowStream(writer io.Writer) *Stream
ReturnStream(stream *Stream)
}
func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream {
select {
case stream := <-cfg.streamPool:
stream.Reset(writer)
return stream
default:
return NewStream(cfg, writer, 512)
}
}
func (cfg *frozenConfig) ReturnStream(stream *Stream) {
stream.Error = nil
select {
case cfg.streamPool <- stream:
return
default:
return
}
}
func (cfg *frozenConfig) BorrowIterator(data []byte) *Iterator {
select {
case iter := <-cfg.iteratorPool:
iter.ResetBytes(data)
return iter
default:
return ParseBytes(cfg, data)
}
}
func (cfg *frozenConfig) ReturnIterator(iter *Iterator) {
iter.Error = nil
select {
case cfg.iteratorPool <- iter:
return
default:
return
}
}

View File

@ -5,12 +5,12 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect" "reflect"
"time" "sync/atomic"
"unsafe" "unsafe"
) )
// ValDecoder is an internal type registered to cache as needed. // Decoder is an internal type registered to cache as needed.
// Don't confuse jsoniter.ValDecoder with json.Decoder. // Don't confuse jsoniter.Decoder with json.Decoder.
// For json.Decoder's adapter, refer to jsoniter.AdapterDecoder(todo link). // For json.Decoder's adapter, refer to jsoniter.AdapterDecoder(todo link).
// //
// Reflection on type to create decoders, which is then cached // Reflection on type to create decoders, which is then cached
@ -19,170 +19,231 @@ import (
// 2. append to slice, if the existing cap is not enough, allocate will be done using Reflect.New // 2. append to slice, if the existing cap is not enough, allocate will be done using Reflect.New
// 3. assignment to map, both key and value will be reflect.Value // 3. assignment to map, both key and value will be reflect.Value
// For a simple struct binding, it will be reflect.Value free and allocation free // For a simple struct binding, it will be reflect.Value free and allocation free
type ValDecoder interface { type Decoder interface {
Decode(ptr unsafe.Pointer, iter *Iterator) decode(ptr unsafe.Pointer, iter *Iterator)
} }
// ValEncoder is an internal type registered to cache as needed. // Encoder is an internal type registered to cache as needed.
// Don't confuse jsoniter.ValEncoder with json.Encoder. // Don't confuse jsoniter.Encoder with json.Encoder.
// For json.Encoder's adapter, refer to jsoniter.AdapterEncoder(todo godoc link). // For json.Encoder's adapter, refer to jsoniter.AdapterEncoder(todo godoc link).
type ValEncoder interface { type Encoder interface {
IsEmpty(ptr unsafe.Pointer) bool isEmpty(ptr unsafe.Pointer) bool
Encode(ptr unsafe.Pointer, stream *Stream) encode(ptr unsafe.Pointer, stream *Stream)
EncodeInterface(val interface{}, stream *Stream) encodeInterface(val interface{}, stream *Stream)
} }
type checkIsEmpty interface { func writeToStream(val interface{}, stream *Stream, encoder Encoder) {
IsEmpty(ptr unsafe.Pointer) bool
}
// WriteToStream the default implementation for TypeEncoder method EncodeInterface
func WriteToStream(val interface{}, stream *Stream, encoder ValEncoder) {
e := (*emptyInterface)(unsafe.Pointer(&val)) e := (*emptyInterface)(unsafe.Pointer(&val))
if e.word == nil {
stream.WriteNil()
return
}
if reflect.TypeOf(val).Kind() == reflect.Ptr { if reflect.TypeOf(val).Kind() == reflect.Ptr {
encoder.Encode(unsafe.Pointer(&e.word), stream) encoder.encode(unsafe.Pointer(&e.word), stream)
} else { } else {
encoder.Encode(e.word, stream) encoder.encode(e.word, stream)
} }
} }
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
type EncoderFunc func(ptr unsafe.Pointer, stream *Stream)
type ExtensionFunc func(typ reflect.Type, field *reflect.StructField) ([]string, EncoderFunc, DecoderFunc)
type funcDecoder struct {
fun DecoderFunc
}
func (decoder *funcDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.fun(ptr, iter)
}
type funcEncoder struct {
fun EncoderFunc
}
func (encoder *funcEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
encoder.fun(ptr, stream)
}
func (encoder *funcEncoder) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (encoder *funcEncoder) isEmpty(ptr unsafe.Pointer) bool {
return false
}
var DECODERS unsafe.Pointer
var ENCODERS unsafe.Pointer
var typeDecoders map[string]Decoder
var fieldDecoders map[string]Decoder
var typeEncoders map[string]Encoder
var fieldEncoders map[string]Encoder
var extensions []ExtensionFunc
var jsonNumberType reflect.Type var jsonNumberType reflect.Type
var jsoniterNumberType reflect.Type
var jsonRawMessageType reflect.Type var jsonRawMessageType reflect.Type
var jsoniterRawMessageType reflect.Type
var anyType reflect.Type var anyType reflect.Type
var marshalerType reflect.Type var marshalerType reflect.Type
var unmarshalerType reflect.Type var unmarshalerType reflect.Type
var textMarshalerType reflect.Type
var textUnmarshalerType reflect.Type var textUnmarshalerType reflect.Type
func init() { func init() {
typeDecoders = map[string]Decoder{}
fieldDecoders = map[string]Decoder{}
typeEncoders = map[string]Encoder{}
fieldEncoders = map[string]Encoder{}
extensions = []ExtensionFunc{}
atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
atomic.StorePointer(&ENCODERS, unsafe.Pointer(&map[string]Encoder{}))
jsonNumberType = reflect.TypeOf((*json.Number)(nil)).Elem() jsonNumberType = reflect.TypeOf((*json.Number)(nil)).Elem()
jsoniterNumberType = reflect.TypeOf((*Number)(nil)).Elem()
jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem() jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem()
jsoniterRawMessageType = reflect.TypeOf((*RawMessage)(nil)).Elem()
anyType = reflect.TypeOf((*Any)(nil)).Elem() anyType = reflect.TypeOf((*Any)(nil)).Elem()
marshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem() marshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
} }
func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
done := false
for !done {
ptr := atomic.LoadPointer(&DECODERS)
cache := *(*map[reflect.Type]Decoder)(ptr)
copied := map[reflect.Type]Decoder{}
for k, v := range cache {
copied[k] = v
}
copied[cacheKey] = decoder
done = atomic.CompareAndSwapPointer(&DECODERS, ptr, unsafe.Pointer(&copied))
}
}
func addEncoderToCache(cacheKey reflect.Type, encoder Encoder) {
done := false
for !done {
ptr := atomic.LoadPointer(&ENCODERS)
cache := *(*map[reflect.Type]Encoder)(ptr)
copied := map[reflect.Type]Encoder{}
for k, v := range cache {
copied[k] = v
}
copied[cacheKey] = encoder
done = atomic.CompareAndSwapPointer(&ENCODERS, ptr, unsafe.Pointer(&copied))
}
}
func getDecoderFromCache(cacheKey reflect.Type) Decoder {
ptr := atomic.LoadPointer(&DECODERS)
cache := *(*map[reflect.Type]Decoder)(ptr)
return cache[cacheKey]
}
func getEncoderFromCache(cacheKey reflect.Type) Encoder {
ptr := atomic.LoadPointer(&ENCODERS)
cache := *(*map[reflect.Type]Encoder)(ptr)
return cache[cacheKey]
}
// RegisterTypeDecoder can register a type for json object
func RegisterTypeDecoder(typ string, fun DecoderFunc) {
typeDecoders[typ] = &funcDecoder{fun}
}
// RegisterFieldDecoder can register a type for json field
func RegisterFieldDecoder(typ string, field string, fun DecoderFunc) {
fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = &funcDecoder{fun}
}
func RegisterTypeEncoder(typ string, fun EncoderFunc) {
typeEncoders[typ] = &funcEncoder{fun}
}
func RegisterFieldEncoder(typ string, field string, fun EncoderFunc) {
fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = &funcEncoder{fun}
}
// RegisterExtension can register a custom extension
func RegisterExtension(extension ExtensionFunc) {
extensions = append(extensions, extension)
}
// CleanDecoders cleans decoders registered or cached
func CleanDecoders() {
typeDecoders = map[string]Decoder{}
fieldDecoders = map[string]Decoder{}
atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
}
// CleanEncoders cleans encoders registered or cached
func CleanEncoders() {
typeEncoders = map[string]Encoder{}
fieldEncoders = map[string]Encoder{}
atomic.StorePointer(&ENCODERS, unsafe.Pointer(&map[string]Encoder{}))
}
type optionalDecoder struct { type optionalDecoder struct {
valueType reflect.Type valueType reflect.Type
valueDecoder ValDecoder valueDecoder Decoder
} }
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 decoder.valueDecoder.decode(unsafe.Pointer(value.Pointer()), iter)
decoder.valueDecoder.Decode(newPtr, iter) *((*uintptr)(ptr)) = value.Pointer()
*((*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)
} }
} }
} }
type deferenceDecoder struct {
// only to deference a pointer
valueType reflect.Type
valueDecoder ValDecoder
}
func (decoder *deferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if *((*unsafe.Pointer)(ptr)) == nil {
//pointer to null, we have to allocate memory to hold the value
value := reflect.New(decoder.valueType)
newPtr := extractInterface(value.Interface()).word
decoder.valueDecoder.Decode(newPtr, iter)
*((*uintptr)(ptr)) = uintptr(newPtr)
} else {
//reuse existing instance
decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter)
}
}
type optionalEncoder struct { type optionalEncoder struct {
valueEncoder ValEncoder valueEncoder Encoder
} }
func (encoder *optionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { func (encoder *optionalEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
if *((*unsafe.Pointer)(ptr)) == nil { if *((*unsafe.Pointer)(ptr)) == nil {
stream.WriteNil() stream.WriteNil()
} else { } else {
encoder.valueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream) encoder.valueEncoder.encode(*((*unsafe.Pointer)(ptr)), stream)
} }
} }
func (encoder *optionalEncoder) EncodeInterface(val interface{}, stream *Stream) { func (encoder *optionalEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder) writeToStream(val, stream, encoder)
} }
func (encoder *optionalEncoder) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *optionalEncoder) isEmpty(ptr unsafe.Pointer) bool {
if *((*unsafe.Pointer)(ptr)) == nil { if *((*unsafe.Pointer)(ptr)) == nil {
return true return true
} else {
return encoder.valueEncoder.isEmpty(*((*unsafe.Pointer)(ptr)))
} }
return false
} }
type placeholderEncoder struct { type placeholderEncoder struct {
cfg *frozenConfig valueEncoder Encoder
cacheKey reflect.Type
} }
func (encoder *placeholderEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { func (encoder *placeholderEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
encoder.getRealEncoder().Encode(ptr, stream) encoder.valueEncoder.encode(ptr, stream)
} }
func (encoder *placeholderEncoder) EncodeInterface(val interface{}, stream *Stream) { func (encoder *placeholderEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder) writeToStream(val, stream, encoder)
} }
func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *placeholderEncoder) isEmpty(ptr unsafe.Pointer) bool {
return encoder.getRealEncoder().IsEmpty(ptr) return encoder.valueEncoder.isEmpty(ptr)
}
func (encoder *placeholderEncoder) getRealEncoder() ValEncoder {
for i := 0; i < 500; i++ {
realDecoder := encoder.cfg.getEncoderFromCache(encoder.cacheKey)
_, isPlaceholder := realDecoder.(*placeholderEncoder)
if isPlaceholder {
time.Sleep(10 * time.Millisecond)
} else {
return realDecoder
}
}
panic(fmt.Sprintf("real encoder not found for cache key: %v", encoder.cacheKey))
} }
type placeholderDecoder struct { type placeholderDecoder struct {
cfg *frozenConfig valueDecoder Decoder
cacheKey reflect.Type
} }
func (decoder *placeholderDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *placeholderDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
for i := 0; i < 500; i++ { decoder.valueDecoder.decode(ptr, iter)
realDecoder := decoder.cfg.getDecoderFromCache(decoder.cacheKey)
_, isPlaceholder := realDecoder.(*placeholderDecoder)
if isPlaceholder {
time.Sleep(10 * time.Millisecond)
} else {
realDecoder.Decode(ptr, iter)
return
}
}
panic(fmt.Sprintf("real decoder not found for cache key: %v", decoder.cacheKey))
} }
// emptyInterface is the header for an interface{} value. // emptyInterface is the header for an interface{} value.
@ -205,20 +266,24 @@ type nonEmptyInterface struct {
word unsafe.Pointer word unsafe.Pointer
} }
// ReadVal copy the underlying JSON into go interface, same as json.Unmarshal // Read converts an Iterator instance into go interface, same as json.Unmarshal
func (iter *Iterator) ReadVal(obj interface{}) { func (iter *Iterator) ReadVal(obj interface{}) {
typ := reflect.TypeOf(obj) typ := reflect.TypeOf(obj)
cacheKey := typ.Elem() cacheKey := typ.Elem()
decoder, err := decoderOfType(iter.cfg, cacheKey) cachedDecoder := getDecoderFromCache(cacheKey)
if err != nil { if cachedDecoder == nil {
iter.Error = err decoder, err := decoderOfType(cacheKey)
return if err != nil {
iter.Error = err
return
}
cachedDecoder = decoder
addDecoderToCache(cacheKey, decoder)
} }
e := (*emptyInterface)(unsafe.Pointer(&obj)) e := (*emptyInterface)(unsafe.Pointer(&obj))
decoder.Decode(e.word, iter) cachedDecoder.decode(e.word, iter)
} }
// WriteVal copy the go interface into underlying JSON, same as json.Marshal
func (stream *Stream) WriteVal(val interface{}) { func (stream *Stream) WriteVal(val interface{}) {
if nil == val { if nil == val {
stream.WriteNil() stream.WriteNil()
@ -226,283 +291,167 @@ func (stream *Stream) WriteVal(val interface{}) {
} }
typ := reflect.TypeOf(val) typ := reflect.TypeOf(val)
cacheKey := typ cacheKey := typ
encoder, err := encoderOfType(stream.cfg, cacheKey) cachedEncoder := getEncoderFromCache(cacheKey)
if err != nil { if cachedEncoder == nil {
stream.Error = err encoder, err := encoderOfType(cacheKey)
return if err != nil {
stream.Error = err
return
}
cachedEncoder = encoder
addEncoderToCache(cacheKey, encoder)
} }
encoder.EncodeInterface(val, stream) cachedEncoder.encodeInterface(val, stream)
} }
type prefix string type prefix string
func (p prefix) addToDecoder(decoder ValDecoder, err error) (ValDecoder, error) { func (p prefix) addToDecoder(decoder Decoder, err error) (Decoder, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("%s: %s", p, err.Error()) return nil, fmt.Errorf("%s: %s", p, err.Error())
} }
return decoder, err return decoder, err
} }
func (p prefix) addToEncoder(encoder ValEncoder, err error) (ValEncoder, error) { func (p prefix) addToEncoder(encoder Encoder, err error) (Encoder, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("%s: %s", p, err.Error()) return nil, fmt.Errorf("%s: %s", p, err.Error())
} }
return encoder, err return encoder, err
} }
func decoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { func decoderOfType(typ reflect.Type) (Decoder, error) {
typeName := typ.String()
typeDecoder := typeDecoders[typeName]
if typeDecoder != nil {
return typeDecoder, nil
}
if typ.Kind() == reflect.Ptr {
typeDecoder := typeDecoders[typ.Elem().String()]
if typeDecoder != nil {
return &optionalDecoder{typ.Elem(), typeDecoder}, nil
}
}
cacheKey := typ cacheKey := typ
decoder := cfg.getDecoderFromCache(cacheKey) cachedDecoder := getDecoderFromCache(cacheKey)
if decoder != nil { if cachedDecoder != nil {
return decoder, nil return cachedDecoder, nil
} }
decoder = getTypeDecoderFromExtension(typ) placeholder := &placeholderDecoder{}
if decoder != nil { addDecoderToCache(cacheKey, placeholder)
cfg.addDecoderToCache(cacheKey, decoder) newDecoder, err := createDecoderOfType(typ)
return decoder, nil placeholder.valueDecoder = newDecoder
} addDecoderToCache(cacheKey, newDecoder)
decoder = &placeholderDecoder{cfg: cfg, cacheKey: cacheKey} return newDecoder, err
cfg.addDecoderToCache(cacheKey, decoder)
decoder, err := createDecoderOfType(cfg, typ)
for _, extension := range extensions {
decoder = extension.DecorateDecoder(typ, decoder)
}
cfg.addDecoderToCache(cacheKey, decoder)
return decoder, err
} }
func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { func createDecoderOfType(typ reflect.Type) (Decoder, error) {
typeName := typ.String() if typ.String() == "[]uint8" {
if typ == jsonRawMessageType { return &base64Codec{}, nil
return &jsonRawMessageCodec{}, nil
} }
if typ == jsoniterRawMessageType { if typ.AssignableTo(jsonRawMessageType) {
return &jsoniterRawMessageCodec{}, nil return &jsonRawMessageCodec{}, nil
} }
if typ.AssignableTo(jsonNumberType) { if typ.AssignableTo(jsonNumberType) {
return &jsonNumberCodec{}, nil return &jsonNumberCodec{}, nil
} }
if typ.AssignableTo(jsoniterNumberType) { if typ.ConvertibleTo(unmarshalerType) {
return &jsoniterNumberCodec{}, nil
}
if typ.Implements(unmarshalerType) {
templateInterface := reflect.New(typ).Elem().Interface() templateInterface := reflect.New(typ).Elem().Interface()
var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)} return &optionalDecoder{typ, &unmarshalerDecoder{extractInterface(templateInterface)}}, nil
if typ.Kind() == reflect.Ptr {
decoder = &optionalDecoder{typ.Elem(), decoder}
}
return decoder, nil
} }
if reflect.PtrTo(typ).Implements(unmarshalerType) { if typ.ConvertibleTo(anyType) {
templateInterface := reflect.New(typ).Interface()
var decoder ValDecoder = &unmarshalerDecoder{extractInterface(templateInterface)}
return decoder, nil
}
if typ.Implements(textUnmarshalerType) {
templateInterface := reflect.New(typ).Elem().Interface()
var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)}
if typ.Kind() == reflect.Ptr {
decoder = &optionalDecoder{typ.Elem(), decoder}
}
return decoder, nil
}
if reflect.PtrTo(typ).Implements(textUnmarshalerType) {
templateInterface := reflect.New(typ).Interface()
var decoder ValDecoder = &textUnmarshalerDecoder{extractInterface(templateInterface)}
return decoder, nil
}
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
sliceDecoder, err := prefix("[slice]").addToDecoder(decoderOfSlice(cfg, typ))
if err != nil {
return nil, err
}
return &base64Codec{sliceDecoder: sliceDecoder}, nil
}
if typ.Implements(anyType) {
return &anyCodec{}, nil return &anyCodec{}, nil
} }
switch typ.Kind() { switch typ.Kind() {
case reflect.String: case reflect.String:
if typeName != "string" {
return decoderOfType(cfg, reflect.TypeOf((*string)(nil)).Elem())
}
return &stringCodec{}, nil return &stringCodec{}, nil
case reflect.Int: case reflect.Int:
if typeName != "int" {
return decoderOfType(cfg, reflect.TypeOf((*int)(nil)).Elem())
}
return &intCodec{}, nil return &intCodec{}, nil
case reflect.Int8: case reflect.Int8:
if typeName != "int8" {
return decoderOfType(cfg, reflect.TypeOf((*int8)(nil)).Elem())
}
return &int8Codec{}, nil return &int8Codec{}, nil
case reflect.Int16: case reflect.Int16:
if typeName != "int16" {
return decoderOfType(cfg, reflect.TypeOf((*int16)(nil)).Elem())
}
return &int16Codec{}, nil return &int16Codec{}, nil
case reflect.Int32: case reflect.Int32:
if typeName != "int32" {
return decoderOfType(cfg, reflect.TypeOf((*int32)(nil)).Elem())
}
return &int32Codec{}, nil return &int32Codec{}, nil
case reflect.Int64: case reflect.Int64:
if typeName != "int64" {
return decoderOfType(cfg, reflect.TypeOf((*int64)(nil)).Elem())
}
return &int64Codec{}, nil return &int64Codec{}, nil
case reflect.Uint: case reflect.Uint:
if typeName != "uint" {
return decoderOfType(cfg, reflect.TypeOf((*uint)(nil)).Elem())
}
return &uintCodec{}, nil return &uintCodec{}, nil
case reflect.Uint8: case reflect.Uint8:
if typeName != "uint8" {
return decoderOfType(cfg, reflect.TypeOf((*uint8)(nil)).Elem())
}
return &uint8Codec{}, nil return &uint8Codec{}, nil
case reflect.Uint16: case reflect.Uint16:
if typeName != "uint16" {
return decoderOfType(cfg, reflect.TypeOf((*uint16)(nil)).Elem())
}
return &uint16Codec{}, nil return &uint16Codec{}, nil
case reflect.Uint32: case reflect.Uint32:
if typeName != "uint32" {
return decoderOfType(cfg, reflect.TypeOf((*uint32)(nil)).Elem())
}
return &uint32Codec{}, nil return &uint32Codec{}, nil
case reflect.Uintptr:
if typeName != "uintptr" {
return decoderOfType(cfg, reflect.TypeOf((*uintptr)(nil)).Elem())
}
return &uintptrCodec{}, nil
case reflect.Uint64: case reflect.Uint64:
if typeName != "uint64" {
return decoderOfType(cfg, reflect.TypeOf((*uint64)(nil)).Elem())
}
return &uint64Codec{}, nil return &uint64Codec{}, nil
case reflect.Float32: case reflect.Float32:
if typeName != "float32" {
return decoderOfType(cfg, reflect.TypeOf((*float32)(nil)).Elem())
}
return &float32Codec{}, nil return &float32Codec{}, nil
case reflect.Float64: case reflect.Float64:
if typeName != "float64" {
return decoderOfType(cfg, reflect.TypeOf((*float64)(nil)).Elem())
}
return &float64Codec{}, nil return &float64Codec{}, nil
case reflect.Bool: case reflect.Bool:
if typeName != "bool" {
return decoderOfType(cfg, reflect.TypeOf((*bool)(nil)).Elem())
}
return &boolCodec{}, nil return &boolCodec{}, nil
case reflect.Interface: case reflect.Interface:
if typ.NumMethod() == 0 { if typ.NumMethod() == 0 {
return &emptyInterfaceCodec{}, nil return &emptyInterfaceCodec{}, nil
} else {
return &nonEmptyInterfaceCodec{}, nil
} }
return &nonEmptyInterfaceCodec{}, nil
case reflect.Struct: case reflect.Struct:
return prefix(fmt.Sprintf("[%s]", typeName)).addToDecoder(decoderOfStruct(cfg, typ)) return prefix(fmt.Sprintf("[%s]", typ.String())).addToDecoder(decoderOfStruct(typ))
case reflect.Array:
return prefix("[array]").addToDecoder(decoderOfArray(cfg, typ))
case reflect.Slice: case reflect.Slice:
return prefix("[slice]").addToDecoder(decoderOfSlice(cfg, typ)) return prefix("[slice]").addToDecoder(decoderOfSlice(typ))
case reflect.Map: case reflect.Map:
return prefix("[map]").addToDecoder(decoderOfMap(cfg, typ)) return prefix("[map]").addToDecoder(decoderOfMap(typ))
case reflect.Ptr: case reflect.Ptr:
return prefix("[optional]").addToDecoder(decoderOfOptional(cfg, typ)) return prefix("[optional]").addToDecoder(decoderOfOptional(typ))
default: default:
return nil, fmt.Errorf("unsupported type: %v", typ) return nil, fmt.Errorf("unsupported type: %v", typ)
} }
} }
func encoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { func encoderOfType(typ reflect.Type) (Encoder, error) {
typeName := typ.String()
typeEncoder := typeEncoders[typeName]
if typeEncoder != nil {
return typeEncoder, nil
}
if typ.Kind() == reflect.Ptr {
typeEncoder := typeEncoders[typ.Elem().String()]
if typeEncoder != nil {
return &optionalEncoder{typeEncoder}, nil
}
}
cacheKey := typ cacheKey := typ
encoder := cfg.getEncoderFromCache(cacheKey) cachedEncoder := getEncoderFromCache(cacheKey)
if encoder != nil { if cachedEncoder != nil {
return encoder, nil return cachedEncoder, nil
} }
encoder = getTypeEncoderFromExtension(typ) placeholder := &placeholderEncoder{}
if encoder != nil { addEncoderToCache(cacheKey, placeholder)
cfg.addEncoderToCache(cacheKey, encoder) newEncoder, err := createEncoderOfType(typ)
return encoder, nil placeholder.valueEncoder = newEncoder
} addEncoderToCache(cacheKey, newEncoder)
encoder = &placeholderEncoder{cfg: cfg, cacheKey: cacheKey} return newEncoder, err
cfg.addEncoderToCache(cacheKey, encoder)
encoder, err := createEncoderOfType(cfg, typ)
for _, extension := range extensions {
encoder = extension.DecorateEncoder(typ, encoder)
}
cfg.addEncoderToCache(cacheKey, encoder)
return encoder, err
} }
func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { func createEncoderOfType(typ reflect.Type) (Encoder, error) {
if typ == jsonRawMessageType { if typ.String() == "[]uint8" {
return &jsonRawMessageCodec{}, nil return &base64Codec{}, nil
} }
if typ == jsoniterRawMessageType { if typ.AssignableTo(jsonRawMessageType) {
return &jsoniterRawMessageCodec{}, nil return &jsonRawMessageCodec{}, nil
} }
if typ.AssignableTo(jsonNumberType) { if typ.AssignableTo(jsonNumberType) {
return &jsonNumberCodec{}, nil return &jsonNumberCodec{}, nil
} }
if typ.AssignableTo(jsoniterNumberType) { if typ.ConvertibleTo(marshalerType) {
return &jsoniterNumberCodec{}, nil
}
if typ.Implements(marshalerType) {
checkIsEmpty, err := createCheckIsEmpty(typ)
if err != nil {
return nil, err
}
templateInterface := reflect.New(typ).Elem().Interface() templateInterface := reflect.New(typ).Elem().Interface()
var encoder ValEncoder = &marshalerEncoder{ return &marshalerEncoder{extractInterface(templateInterface)}, nil
templateInterface: extractInterface(templateInterface),
checkIsEmpty: checkIsEmpty,
}
if typ.Kind() == reflect.Ptr {
encoder = &optionalEncoder{encoder}
}
return encoder, nil
} }
if reflect.PtrTo(typ).Implements(marshalerType) { if typ.ConvertibleTo(anyType) {
checkIsEmpty, err := createCheckIsEmpty(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
}
if typ.Implements(textMarshalerType) {
checkIsEmpty, err := createCheckIsEmpty(typ)
if err != nil {
return nil, err
}
templateInterface := reflect.New(typ).Elem().Interface()
var encoder ValEncoder = &textMarshalerEncoder{
templateInterface: extractInterface(templateInterface),
checkIsEmpty: checkIsEmpty,
}
if typ.Kind() == reflect.Ptr {
encoder = &optionalEncoder{encoder}
}
return encoder, nil
}
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
return &base64Codec{}, nil
}
if typ.Implements(anyType) {
return &anyCodec{}, nil return &anyCodec{}, nil
} }
return createEncoderOfSimpleType(cfg, typ)
}
func createCheckIsEmpty(typ reflect.Type) (checkIsEmpty, error) {
kind := typ.Kind() kind := typ.Kind()
switch kind { switch kind {
case reflect.String: case reflect.String:
@ -525,8 +474,6 @@ func createCheckIsEmpty(typ reflect.Type) (checkIsEmpty, error) {
return &uint16Codec{}, nil return &uint16Codec{}, nil
case reflect.Uint32: case reflect.Uint32:
return &uint32Codec{}, nil return &uint32Codec{}, nil
case reflect.Uintptr:
return &uintptrCodec{}, nil
case reflect.Uint64: case reflect.Uint64:
return &uint64Codec{}, nil return &uint64Codec{}, nil
case reflect.Float32: case reflect.Float32:
@ -538,146 +485,42 @@ func createCheckIsEmpty(typ reflect.Type) (checkIsEmpty, error) {
case reflect.Interface: case reflect.Interface:
if typ.NumMethod() == 0 { if typ.NumMethod() == 0 {
return &emptyInterfaceCodec{}, nil return &emptyInterfaceCodec{}, nil
} else {
return &nonEmptyInterfaceCodec{}, nil
} }
return &nonEmptyInterfaceCodec{}, nil
case reflect.Struct: case reflect.Struct:
return &structEncoder{}, nil return prefix(fmt.Sprintf("[%s]", typ.String())).addToEncoder(encoderOfStruct(typ))
case reflect.Array:
return &arrayEncoder{}, nil
case reflect.Slice: case reflect.Slice:
return &sliceEncoder{}, nil return prefix("[slice]").addToEncoder(encoderOfSlice(typ))
case reflect.Map: case reflect.Map:
return &mapEncoder{}, nil return prefix("[map]").addToEncoder(encoderOfMap(typ))
case reflect.Ptr: case reflect.Ptr:
return &optionalEncoder{}, nil return prefix("[optional]").addToEncoder(encoderOfOptional(typ))
default: default:
return nil, fmt.Errorf("unsupported type: %v", typ) return nil, fmt.Errorf("unsupported type: %v", typ)
} }
} }
func createEncoderOfSimpleType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { func decoderOfOptional(typ reflect.Type) (Decoder, error) {
typeName := typ.String()
kind := typ.Kind()
switch kind {
case reflect.String:
if typeName != "string" {
return encoderOfType(cfg, reflect.TypeOf((*string)(nil)).Elem())
}
return &stringCodec{}, nil
case reflect.Int:
if typeName != "int" {
return encoderOfType(cfg, reflect.TypeOf((*int)(nil)).Elem())
}
return &intCodec{}, nil
case reflect.Int8:
if typeName != "int8" {
return encoderOfType(cfg, reflect.TypeOf((*int8)(nil)).Elem())
}
return &int8Codec{}, nil
case reflect.Int16:
if typeName != "int16" {
return encoderOfType(cfg, reflect.TypeOf((*int16)(nil)).Elem())
}
return &int16Codec{}, nil
case reflect.Int32:
if typeName != "int32" {
return encoderOfType(cfg, reflect.TypeOf((*int32)(nil)).Elem())
}
return &int32Codec{}, nil
case reflect.Int64:
if typeName != "int64" {
return encoderOfType(cfg, reflect.TypeOf((*int64)(nil)).Elem())
}
return &int64Codec{}, nil
case reflect.Uint:
if typeName != "uint" {
return encoderOfType(cfg, reflect.TypeOf((*uint)(nil)).Elem())
}
return &uintCodec{}, nil
case reflect.Uint8:
if typeName != "uint8" {
return encoderOfType(cfg, reflect.TypeOf((*uint8)(nil)).Elem())
}
return &uint8Codec{}, nil
case reflect.Uint16:
if typeName != "uint16" {
return encoderOfType(cfg, reflect.TypeOf((*uint16)(nil)).Elem())
}
return &uint16Codec{}, nil
case reflect.Uint32:
if typeName != "uint32" {
return encoderOfType(cfg, reflect.TypeOf((*uint32)(nil)).Elem())
}
return &uint32Codec{}, nil
case reflect.Uintptr:
if typeName != "uintptr" {
return encoderOfType(cfg, reflect.TypeOf((*uintptr)(nil)).Elem())
}
return &uintptrCodec{}, nil
case reflect.Uint64:
if typeName != "uint64" {
return encoderOfType(cfg, reflect.TypeOf((*uint64)(nil)).Elem())
}
return &uint64Codec{}, nil
case reflect.Float32:
if typeName != "float32" {
return encoderOfType(cfg, reflect.TypeOf((*float32)(nil)).Elem())
}
return &float32Codec{}, nil
case reflect.Float64:
if typeName != "float64" {
return encoderOfType(cfg, reflect.TypeOf((*float64)(nil)).Elem())
}
return &float64Codec{}, nil
case reflect.Bool:
if typeName != "bool" {
return encoderOfType(cfg, reflect.TypeOf((*bool)(nil)).Elem())
}
return &boolCodec{}, nil
case reflect.Interface:
if typ.NumMethod() == 0 {
return &emptyInterfaceCodec{}, nil
}
return &nonEmptyInterfaceCodec{}, nil
case reflect.Struct:
return prefix(fmt.Sprintf("[%s]", typeName)).addToEncoder(encoderOfStruct(cfg, typ))
case reflect.Array:
return prefix("[array]").addToEncoder(encoderOfArray(cfg, typ))
case reflect.Slice:
return prefix("[slice]").addToEncoder(encoderOfSlice(cfg, typ))
case reflect.Map:
return prefix("[map]").addToEncoder(encoderOfMap(cfg, typ))
case reflect.Ptr:
return prefix("[optional]").addToEncoder(encoderOfOptional(cfg, typ))
default:
return nil, fmt.Errorf("unsupported type: %v", typ)
}
}
func decoderOfOptional(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) {
elemType := typ.Elem() elemType := typ.Elem()
decoder, err := decoderOfType(cfg, elemType) decoder, err := decoderOfType(elemType)
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(typ reflect.Type) (Encoder, error) {
elemType := typ.Elem() elemType := typ.Elem()
elemEncoder, err := encoderOfType(cfg, elemType) decoder, err := encoderOfType(elemType)
if err != nil { if err != nil {
return nil, err return nil, err
} }
encoder := &optionalEncoder{elemEncoder} return &optionalEncoder{decoder}, nil
if elemType.Kind() == reflect.Map {
encoder = &optionalEncoder{encoder}
}
return encoder, nil
} }
func decoderOfMap(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { func decoderOfMap(typ reflect.Type) (Decoder, error) {
decoder, err := decoderOfType(cfg, typ.Elem()) decoder, err := decoderOfType(typ.Elem())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -689,15 +532,12 @@ func extractInterface(val interface{}) emptyInterface {
return *((*emptyInterface)(unsafe.Pointer(&val))) return *((*emptyInterface)(unsafe.Pointer(&val)))
} }
func encoderOfMap(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { func encoderOfMap(typ reflect.Type) (Encoder, error) {
elemType := typ.Elem() elemType := typ.Elem()
encoder, err := encoderOfType(cfg, elemType) encoder, err := encoderOfType(elemType)
if err != nil { if err != nil {
return nil, err return nil, err
} }
mapInterface := reflect.New(typ).Elem().Interface() mapInterface := reflect.New(typ).Elem().Interface()
if cfg.sortMapKeys {
return &sortKeysMapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
}
return &mapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil return &mapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
} }

View File

@ -7,93 +7,152 @@ import (
"unsafe" "unsafe"
) )
func decoderOfArray(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { func decoderOfSlice(typ reflect.Type) (Decoder, error) {
decoder, err := decoderOfType(cfg, typ.Elem()) decoder, err := decoderOfType(typ.Elem())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &arrayDecoder{typ, typ.Elem(), decoder}, nil return &sliceDecoder{typ, typ.Elem(), decoder}, nil
} }
func encoderOfArray(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { func encoderOfSlice(typ reflect.Type) (Encoder, error) {
encoder, err := encoderOfType(cfg, typ.Elem()) encoder, err := encoderOfType(typ.Elem())
if err != nil { if err != nil {
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 &sliceEncoder{typ, typ.Elem(), encoder}, nil
} }
type arrayEncoder struct { type sliceEncoder struct {
arrayType reflect.Type sliceType reflect.Type
elemType reflect.Type elemType reflect.Type
elemEncoder ValEncoder elemEncoder Encoder
} }
func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { func (encoder *sliceEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
slice := (*sliceHeader)(ptr)
if slice.Len == 0 {
stream.WriteEmptyArray()
return
}
stream.WriteArrayStart() stream.WriteArrayStart()
elemPtr := unsafe.Pointer(ptr) elemPtr := uintptr(slice.Data)
encoder.elemEncoder.Encode(elemPtr, stream) encoder.elemEncoder.encode(unsafe.Pointer(elemPtr), stream)
for i := 1; i < encoder.arrayType.Len(); i++ { for i := 1; i < slice.Len; i++ {
stream.WriteMore() stream.WriteMore()
elemPtr = unsafe.Pointer(uintptr(elemPtr) + encoder.elemType.Size()) elemPtr += encoder.elemType.Size()
encoder.elemEncoder.Encode(unsafe.Pointer(elemPtr), stream) encoder.elemEncoder.encode(unsafe.Pointer(elemPtr), stream)
} }
stream.WriteArrayEnd() stream.WriteArrayEnd()
if stream.Error != nil && stream.Error != io.EOF { if stream.Error != nil && stream.Error != io.EOF {
stream.Error = fmt.Errorf("%v: %s", encoder.arrayType, stream.Error.Error()) stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error())
} }
} }
func (encoder *arrayEncoder) EncodeInterface(val interface{}, stream *Stream) { func (encoder *sliceEncoder) encodeInterface(val interface{}, stream *Stream) {
// special optimization for interface{} writeToStream(val, stream, encoder)
e := (*emptyInterface)(unsafe.Pointer(&val))
if e.word == nil {
stream.WriteArrayStart()
stream.WriteNil()
stream.WriteArrayEnd()
return
}
elemType := encoder.arrayType.Elem()
if encoder.arrayType.Len() == 1 && (elemType.Kind() == reflect.Ptr || elemType.Kind() == reflect.Map) {
ptr := uintptr(e.word)
e.word = unsafe.Pointer(&ptr)
}
if reflect.TypeOf(val).Kind() == reflect.Ptr {
encoder.Encode(unsafe.Pointer(&e.word), stream)
} else {
encoder.Encode(e.word, stream)
}
} }
func (encoder *arrayEncoder) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *sliceEncoder) isEmpty(ptr unsafe.Pointer) bool {
return false slice := (*sliceHeader)(ptr)
return slice.Len == 0
} }
type arrayDecoder struct { type sliceDecoder struct {
arrayType reflect.Type sliceType reflect.Type
elemType reflect.Type elemType reflect.Type
elemDecoder ValDecoder elemDecoder Decoder
} }
func (decoder *arrayDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { // sliceHeader is a safe version of SliceHeader used within this package.
type sliceHeader struct {
Data unsafe.Pointer
Len int
Cap int
}
func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.doDecode(ptr, iter) decoder.doDecode(ptr, iter)
if iter.Error != nil && iter.Error != io.EOF { if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.arrayType, iter.Error.Error()) iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
} }
} }
func (decoder *arrayDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
slice := (*sliceHeader)(ptr)
reuseSlice(slice, decoder.sliceType, 4)
if !iter.ReadArray() {
return
}
offset := uintptr(0) offset := uintptr(0)
iter.ReadArrayCB(func(iter *Iterator) bool { decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
if offset < decoder.arrayType.Size() { if !iter.ReadArray() {
decoder.elemDecoder.Decode(unsafe.Pointer(uintptr(ptr)+offset), iter) slice.Len = 1
offset += decoder.elemType.Size() return
} else { }
iter.Skip() offset += decoder.elemType.Size()
} decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
return true if !iter.ReadArray() {
}) slice.Len = 2
return
}
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
if !iter.ReadArray() {
slice.Len = 3
return
}
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
slice.Len = 4
for iter.ReadArray() {
growOne(slice, decoder.sliceType, decoder.elemType)
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
}
}
// grow grows the slice s so that it can hold extra more values, allocating
// more capacity if needed. It also returns the old and new slice lengths.
func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
newLen := slice.Len + 1
if newLen <= slice.Cap {
slice.Len = newLen
return
}
newCap := slice.Cap
if newCap == 0 {
newCap = 1
} else {
for newCap < newLen {
if slice.Len < 1024 {
newCap += newCap
} else {
newCap += newCap / 4
}
}
}
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, newLen, newCap).Pointer())
// copy old array into new array
originalBytesCount := uintptr(slice.Len) * elementType.Size()
srcPtr := (*[1 << 30]byte)(slice.Data)
dstPtr := (*[1 << 30]byte)(dst)
for i := uintptr(0); i < originalBytesCount; i++ {
dstPtr[i] = srcPtr[i]
}
slice.Len = newLen
slice.Cap = newCap
slice.Data = dst
}
func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
if expectedCap <= slice.Cap {
return
}
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, 0, expectedCap).Pointer())
slice.Cap = expectedCap
slice.Data = dst
} }

View File

@ -1,413 +0,0 @@
package jsoniter
import (
"fmt"
"reflect"
"sort"
"strings"
"unicode"
"unsafe"
)
var typeDecoders = map[string]ValDecoder{}
var fieldDecoders = map[string]ValDecoder{}
var typeEncoders = map[string]ValEncoder{}
var fieldEncoders = map[string]ValEncoder{}
var extensions = []Extension{}
// StructDescriptor describe how should we encode/decode the struct
type StructDescriptor struct {
onePtrEmbedded bool
onePtrOptimization bool
Type reflect.Type
Fields []*Binding
}
// GetField get one field from the descriptor by its name.
// Can not use map here to keep field orders.
func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding {
for _, binding := range structDescriptor.Fields {
if binding.Field.Name == fieldName {
return binding
}
}
return nil
}
// Binding describe how should we encode/decode the struct field
type Binding struct {
levels []int
Field *reflect.StructField
FromNames []string
ToNames []string
Encoder ValEncoder
Decoder ValDecoder
}
// Extension the one for all SPI. Customize encoding/decoding by specifying alternate encoder/decoder.
// Can also rename fields by UpdateStructDescriptor.
type Extension interface {
UpdateStructDescriptor(structDescriptor *StructDescriptor)
CreateDecoder(typ reflect.Type) ValDecoder
CreateEncoder(typ reflect.Type) ValEncoder
DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder
DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder
}
// DummyExtension embed this type get dummy implementation for all methods of Extension
type DummyExtension struct {
}
// UpdateStructDescriptor No-op
func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) {
}
// CreateDecoder No-op
func (extension *DummyExtension) CreateDecoder(typ reflect.Type) ValDecoder {
return nil
}
// CreateEncoder No-op
func (extension *DummyExtension) CreateEncoder(typ reflect.Type) ValEncoder {
return nil
}
// DecorateDecoder No-op
func (extension *DummyExtension) DecorateDecoder(typ reflect.Type, decoder ValDecoder) ValDecoder {
return decoder
}
// DecorateEncoder No-op
func (extension *DummyExtension) DecorateEncoder(typ reflect.Type, encoder ValEncoder) ValEncoder {
return encoder
}
type funcDecoder struct {
fun DecoderFunc
}
func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.fun(ptr, iter)
}
type funcEncoder struct {
fun EncoderFunc
isEmptyFunc func(ptr unsafe.Pointer) bool
}
func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
encoder.fun(ptr, stream)
}
func (encoder *funcEncoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
}
func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool {
if encoder.isEmptyFunc == nil {
return false
}
return encoder.isEmptyFunc(ptr)
}
// DecoderFunc the function form of TypeDecoder
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
// EncoderFunc the function form of TypeEncoder
type EncoderFunc func(ptr unsafe.Pointer, stream *Stream)
// RegisterTypeDecoderFunc register TypeDecoder for a type with function
func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) {
typeDecoders[typ] = &funcDecoder{fun}
}
// RegisterTypeDecoder register TypeDecoder for a typ
func RegisterTypeDecoder(typ string, decoder ValDecoder) {
typeDecoders[typ] = decoder
}
// RegisterFieldDecoderFunc register TypeDecoder for a struct field with function
func RegisterFieldDecoderFunc(typ string, field string, fun DecoderFunc) {
RegisterFieldDecoder(typ, field, &funcDecoder{fun})
}
// RegisterFieldDecoder register TypeDecoder for a struct field
func RegisterFieldDecoder(typ string, field string, decoder ValDecoder) {
fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = decoder
}
// RegisterTypeEncoderFunc register TypeEncoder for a type with encode/isEmpty function
func RegisterTypeEncoderFunc(typ string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) {
typeEncoders[typ] = &funcEncoder{fun, isEmptyFunc}
}
// RegisterTypeEncoder register TypeEncoder for a type
func RegisterTypeEncoder(typ string, encoder ValEncoder) {
typeEncoders[typ] = encoder
}
// RegisterFieldEncoderFunc register TypeEncoder for a struct field with encode/isEmpty function
func RegisterFieldEncoderFunc(typ string, field string, fun EncoderFunc, isEmptyFunc func(unsafe.Pointer) bool) {
RegisterFieldEncoder(typ, field, &funcEncoder{fun, isEmptyFunc})
}
// RegisterFieldEncoder register TypeEncoder for a struct field
func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) {
fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder
}
// RegisterExtension register extension
func RegisterExtension(extension Extension) {
extensions = append(extensions, extension)
}
func getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
decoder := _getTypeDecoderFromExtension(typ)
if decoder != nil {
for _, extension := range extensions {
decoder = extension.DecorateDecoder(typ, decoder)
}
}
return decoder
}
func _getTypeDecoderFromExtension(typ reflect.Type) ValDecoder {
for _, extension := range extensions {
decoder := extension.CreateDecoder(typ)
if decoder != nil {
return decoder
}
}
typeName := typ.String()
decoder := typeDecoders[typeName]
if decoder != nil {
return decoder
}
if typ.Kind() == reflect.Ptr {
decoder := typeDecoders[typ.Elem().String()]
if decoder != nil {
return &optionalDecoder{typ.Elem(), decoder}
}
}
return nil
}
func getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
encoder := _getTypeEncoderFromExtension(typ)
if encoder != nil {
for _, extension := range extensions {
encoder = extension.DecorateEncoder(typ, encoder)
}
}
return encoder
}
func _getTypeEncoderFromExtension(typ reflect.Type) ValEncoder {
for _, extension := range extensions {
encoder := extension.CreateEncoder(typ)
if encoder != nil {
return encoder
}
}
typeName := typ.String()
encoder := typeEncoders[typeName]
if encoder != nil {
return encoder
}
if typ.Kind() == reflect.Ptr {
encoder := typeEncoders[typ.Elem().String()]
if encoder != nil {
return &optionalEncoder{encoder}
}
}
return nil
}
func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, error) {
embeddedBindings := []*Binding{}
bindings := []*Binding{}
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
tag := field.Tag.Get(cfg.getTagKey())
tagParts := strings.Split(tag, ",")
if tag == "-" {
continue
}
if field.Anonymous && (tag == "" || tagParts[0] == "") {
if field.Type.Kind() == reflect.Struct {
structDescriptor, err := describeStruct(cfg, field.Type)
if err != nil {
return nil, err
}
for _, binding := range structDescriptor.Fields {
binding.levels = append([]int{i}, binding.levels...)
omitempty := binding.Encoder.(*structFieldEncoder).omitempty
binding.Encoder = &structFieldEncoder{&field, binding.Encoder, omitempty}
binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
embeddedBindings = append(embeddedBindings, binding)
}
continue
} else if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
structDescriptor, err := describeStruct(cfg, field.Type.Elem())
if err != nil {
return nil, err
}
for _, binding := range structDescriptor.Fields {
binding.levels = append([]int{i}, binding.levels...)
omitempty := binding.Encoder.(*structFieldEncoder).omitempty
binding.Encoder = &optionalEncoder{binding.Encoder}
binding.Encoder = &structFieldEncoder{&field, binding.Encoder, omitempty}
binding.Decoder = &deferenceDecoder{field.Type.Elem(), binding.Decoder}
binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
embeddedBindings = append(embeddedBindings, binding)
}
continue
}
}
fieldNames := calcFieldNames(field.Name, tagParts[0], tag)
fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
decoder := fieldDecoders[fieldCacheKey]
if decoder == nil {
var err error
decoder, err = decoderOfType(cfg, field.Type)
if err != nil {
return nil, err
}
}
encoder := fieldEncoders[fieldCacheKey]
if encoder == nil {
var err error
encoder, err = encoderOfType(cfg, field.Type)
if err != nil {
return nil, err
}
// map is stored as pointer in the struct
if field.Type.Kind() == reflect.Map {
encoder = &optionalEncoder{encoder}
}
}
binding := &Binding{
Field: &field,
FromNames: fieldNames,
ToNames: fieldNames,
Decoder: decoder,
Encoder: encoder,
}
binding.levels = []int{i}
bindings = append(bindings, binding)
}
return createStructDescriptor(cfg, typ, bindings, embeddedBindings), nil
}
func createStructDescriptor(cfg *frozenConfig, typ reflect.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor {
onePtrEmbedded := false
onePtrOptimization := false
if typ.NumField() == 1 {
firstField := typ.Field(0)
switch firstField.Type.Kind() {
case reflect.Ptr:
if firstField.Anonymous && firstField.Type.Elem().Kind() == reflect.Struct {
onePtrEmbedded = true
}
fallthrough
case reflect.Map:
onePtrOptimization = true
case reflect.Struct:
onePtrOptimization = isStructOnePtr(firstField.Type)
}
}
structDescriptor := &StructDescriptor{
onePtrEmbedded: onePtrEmbedded,
onePtrOptimization: onePtrOptimization,
Type: typ,
Fields: bindings,
}
for _, extension := range extensions {
extension.UpdateStructDescriptor(structDescriptor)
}
processTags(structDescriptor, cfg)
// merge normal & embedded bindings & sort with original order
allBindings := sortableBindings(append(embeddedBindings, structDescriptor.Fields...))
sort.Sort(allBindings)
structDescriptor.Fields = allBindings
return structDescriptor
}
func isStructOnePtr(typ reflect.Type) bool {
if typ.NumField() == 1 {
firstField := typ.Field(0)
switch firstField.Type.Kind() {
case reflect.Ptr:
return true
case reflect.Map:
return true
case reflect.Struct:
return isStructOnePtr(firstField.Type)
}
}
return false
}
type sortableBindings []*Binding
func (bindings sortableBindings) Len() int {
return len(bindings)
}
func (bindings sortableBindings) Less(i, j int) bool {
left := bindings[i].levels
right := bindings[j].levels
k := 0
for {
if left[k] < right[k] {
return true
} else if left[k] > right[k] {
return false
}
k++
}
}
func (bindings sortableBindings) Swap(i, j int) {
bindings[i], bindings[j] = bindings[j], bindings[i]
}
func processTags(structDescriptor *StructDescriptor, cfg *frozenConfig) {
for _, binding := range structDescriptor.Fields {
shouldOmitEmpty := false
tagParts := strings.Split(binding.Field.Tag.Get(cfg.getTagKey()), ",")
for _, tagPart := range tagParts[1:] {
if tagPart == "omitempty" {
shouldOmitEmpty = true
} else if tagPart == "string" {
if binding.Field.Type.Kind() == reflect.String {
binding.Decoder = &stringModeStringDecoder{binding.Decoder, cfg}
binding.Encoder = &stringModeStringEncoder{binding.Encoder, cfg}
} else {
binding.Decoder = &stringModeNumberDecoder{binding.Decoder}
binding.Encoder = &stringModeNumberEncoder{binding.Encoder}
}
}
}
binding.Decoder = &structFieldDecoder{binding.Field, binding.Decoder}
binding.Encoder = &structFieldEncoder{binding.Field, binding.Encoder, shouldOmitEmpty}
}
}
func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string {
// ignore?
if wholeTag == "-" {
return []string{}
}
// rename?
var fieldNames []string
if tagProvidedFieldName == "" {
fieldNames = []string{originalFieldName}
} else {
fieldNames = []string{tagProvidedFieldName}
}
// private?
isNotExported := unicode.IsLower(rune(originalFieldName[0]))
if isNotExported {
fieldNames = []string{}
}
return fieldNames
}

View File

@ -4,7 +4,6 @@ import (
"encoding" "encoding"
"encoding/json" "encoding/json"
"reflect" "reflect"
"sort"
"strconv" "strconv"
"unsafe" "unsafe"
) )
@ -13,57 +12,43 @@ type mapDecoder struct {
mapType reflect.Type mapType reflect.Type
keyType reflect.Type keyType reflect.Type
elemType reflect.Type elemType reflect.Type
elemDecoder ValDecoder elemDecoder Decoder
mapInterface emptyInterface mapInterface emptyInterface
} }
func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *mapDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
// dark magic to cast unsafe.Pointer back to interface{} using reflect.Type // dark magic to cast unsafe.Pointer back to interface{} using reflect.Type
mapInterface := decoder.mapInterface mapInterface := decoder.mapInterface
mapInterface.word = ptr mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface)) realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface).Elem() realVal := reflect.ValueOf(*realInterface).Elem()
if iter.ReadNil() {
realVal.Set(reflect.Zero(decoder.mapType))
return
}
if realVal.IsNil() { if realVal.IsNil() {
realVal.Set(reflect.MakeMap(realVal.Type())) realVal.Set(reflect.MakeMap(realVal.Type()))
} }
iter.ReadMapCB(func(iter *Iterator, keyStr string) bool { iter.ReadMapCB(func(iter *Iterator, keyStr string) bool {
elem := reflect.New(decoder.elemType) elem := reflect.New(decoder.elemType)
decoder.elemDecoder.Decode(unsafe.Pointer(elem.Pointer()), iter) decoder.elemDecoder.decode(unsafe.Pointer(elem.Pointer()), iter)
// to put into map, we have to use reflection // to put into map, we have to use reflection
keyType := decoder.keyType keyType := decoder.keyType
// TODO: remove this from loop
switch { switch {
case keyType.Kind() == reflect.String: case keyType.Kind() == reflect.String:
realVal.SetMapIndex(reflect.ValueOf(keyStr).Convert(keyType), elem.Elem()) realVal.SetMapIndex(reflect.ValueOf(keyStr), elem.Elem())
return true return true
case keyType.Implements(textUnmarshalerType): case keyType.Implements(textUnmarshalerType):
textUnmarshaler := reflect.New(keyType.Elem()).Interface().(encoding.TextUnmarshaler) textUnmarshaler := reflect.New(keyType.Elem()).Interface().(encoding.TextUnmarshaler)
err := textUnmarshaler.UnmarshalText([]byte(keyStr)) err := textUnmarshaler.UnmarshalText([]byte(keyStr))
if err != nil { if err != nil {
iter.ReportError("read map key as TextUnmarshaler", err.Error()) iter.reportError("read map key as TextUnmarshaler", err.Error())
return false return false
} }
realVal.SetMapIndex(reflect.ValueOf(textUnmarshaler), elem.Elem()) realVal.SetMapIndex(reflect.ValueOf(textUnmarshaler), elem.Elem())
return true return true
case reflect.PtrTo(keyType).Implements(textUnmarshalerType):
textUnmarshaler := reflect.New(keyType).Interface().(encoding.TextUnmarshaler)
err := textUnmarshaler.UnmarshalText([]byte(keyStr))
if err != nil {
iter.ReportError("read map key as TextUnmarshaler", err.Error())
return false
}
realVal.SetMapIndex(reflect.ValueOf(textUnmarshaler).Elem(), elem.Elem())
return true
default: default:
switch keyType.Kind() { switch keyType.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n, err := strconv.ParseInt(keyStr, 10, 64) n, err := strconv.ParseInt(keyStr, 10, 64)
if err != nil || reflect.Zero(keyType).OverflowInt(n) { if err != nil || reflect.Zero(keyType).OverflowInt(n) {
iter.ReportError("read map key as int64", "read int64 failed") iter.reportError("read map key as int64", "read int64 failed")
return false return false
} }
realVal.SetMapIndex(reflect.ValueOf(n).Convert(keyType), elem.Elem()) realVal.SetMapIndex(reflect.ValueOf(n).Convert(keyType), elem.Elem())
@ -71,14 +56,14 @@ func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n, err := strconv.ParseUint(keyStr, 10, 64) n, err := strconv.ParseUint(keyStr, 10, 64)
if err != nil || reflect.Zero(keyType).OverflowUint(n) { if err != nil || reflect.Zero(keyType).OverflowUint(n) {
iter.ReportError("read map key as uint64", "read uint64 failed") iter.reportError("read map key as uint64", "read uint64 failed")
return false return false
} }
realVal.SetMapIndex(reflect.ValueOf(n).Convert(keyType), elem.Elem()) realVal.SetMapIndex(reflect.ValueOf(n).Convert(keyType), elem.Elem())
return true return true
} }
} }
iter.ReportError("read map key", "unexpected map key type "+keyType.String()) iter.reportError("read map key", "unexpected map key type "+keyType.String())
return true return true
}) })
} }
@ -86,28 +71,25 @@ func (decoder *mapDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
type mapEncoder struct { type mapEncoder struct {
mapType reflect.Type mapType reflect.Type
elemType reflect.Type elemType reflect.Type
elemEncoder ValEncoder elemEncoder Encoder
mapInterface emptyInterface mapInterface emptyInterface
} }
func (encoder *mapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { func (encoder *mapEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
mapInterface := encoder.mapInterface mapInterface := encoder.mapInterface
mapInterface.word = ptr mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface)) realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface) realVal := reflect.ValueOf(*realInterface)
stream.WriteObjectStart() stream.WriteObjectStart()
for i, key := range realVal.MapKeys() { for i, key := range realVal.MapKeys() {
if i != 0 { if i != 0 {
stream.WriteMore() stream.WriteMore()
} }
encodeMapKey(key, stream) encodeMapKey(key, stream)
if stream.indention > 0 { stream.writeByte(':')
stream.writeTwoBytes(byte(':'), byte(' '))
} else {
stream.writeByte(':')
}
val := realVal.MapIndex(key).Interface() val := realVal.MapIndex(key).Interface()
encoder.elemEncoder.EncodeInterface(val, stream) encoder.elemEncoder.encodeInterface(val, stream)
} }
stream.WriteObjectEnd() stream.WriteObjectEnd()
} }
@ -140,102 +122,14 @@ func encodeMapKey(key reflect.Value, stream *Stream) {
stream.writeByte('"') stream.writeByte('"')
return return
} }
stream.Error = &json.UnsupportedTypeError{Type: key.Type()} stream.Error = &json.UnsupportedTypeError{key.Type()}
} }
func (encoder *mapEncoder) EncodeInterface(val interface{}, stream *Stream) { func (encoder *mapEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder) writeToStream(val, stream, encoder)
} }
func (encoder *mapEncoder) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *mapEncoder) isEmpty(ptr unsafe.Pointer) bool {
mapInterface := encoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface)
return realVal.Len() == 0
}
type sortKeysMapEncoder struct {
mapType reflect.Type
elemType reflect.Type
elemEncoder ValEncoder
mapInterface emptyInterface
}
func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
mapInterface := encoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface)
// Extract and sort the keys.
keys := realVal.MapKeys()
sv := stringValues(make([]reflectWithString, len(keys)))
for i, v := range keys {
sv[i].v = v
if err := sv[i].resolve(); err != nil {
stream.Error = err
return
}
}
sort.Sort(sv)
stream.WriteObjectStart()
for i, key := range sv {
if i != 0 {
stream.WriteMore()
}
stream.WriteVal(key.s) // might need html escape, so can not WriteString directly
if stream.indention > 0 {
stream.writeTwoBytes(byte(':'), byte(' '))
} else {
stream.writeByte(':')
}
val := realVal.MapIndex(key.v).Interface()
encoder.elemEncoder.EncodeInterface(val, stream)
}
stream.WriteObjectEnd()
}
// stringValues is a slice of reflect.Value holding *reflect.StringValue.
// It implements the methods to sort by string.
type stringValues []reflectWithString
type reflectWithString struct {
v reflect.Value
s string
}
func (w *reflectWithString) resolve() error {
if w.v.Kind() == reflect.String {
w.s = w.v.String()
return nil
}
if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok {
buf, err := tm.MarshalText()
w.s = string(buf)
return err
}
switch w.v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
w.s = strconv.FormatInt(w.v.Int(), 10)
return nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
w.s = strconv.FormatUint(w.v.Uint(), 10)
return nil
}
return &json.UnsupportedTypeError{Type: w.v.Type()}
}
func (sv stringValues) Len() int { return len(sv) }
func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
func (sv stringValues) Less(i, j int) bool { return sv[i].s < sv[j].s }
func (encoder *sortKeysMapEncoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
}
func (encoder *sortKeysMapEncoder) IsEmpty(ptr unsafe.Pointer) bool {
mapInterface := encoder.mapInterface mapInterface := encoder.mapInterface
mapInterface.word = ptr mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface)) realInterface := (*interface{})(unsafe.Pointer(&mapInterface))

View File

@ -1,390 +1,304 @@
package jsoniter package jsoniter
import ( import (
"encoding"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"reflect"
"unsafe" "unsafe"
) )
type stringCodec struct { type stringCodec struct {
} }
func (codec *stringCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *stringCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*string)(ptr)) = iter.ReadString() *((*string)(ptr)) = iter.ReadString()
} }
func (codec *stringCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *stringCodec) encode(ptr unsafe.Pointer, stream *Stream) {
str := *((*string)(ptr)) str := *((*string)(ptr))
stream.WriteString(str) stream.WriteString(str)
} }
func (codec *stringCodec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *stringCodec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *stringCodec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *stringCodec) isEmpty(ptr unsafe.Pointer) bool {
return *((*string)(ptr)) == "" return *((*string)(ptr)) == ""
} }
type intCodec struct { 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) {
stream.WriteInt(*((*int)(ptr))) stream.WriteInt(*((*int)(ptr)))
} }
func (codec *intCodec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *intCodec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *intCodec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *intCodec) isEmpty(ptr unsafe.Pointer) bool {
return *((*int)(ptr)) == 0 return *((*int)(ptr)) == 0
} }
type uintptrCodec struct {
}
func (codec *uintptrCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.ReadNil() {
*((*uintptr)(ptr)) = uintptr(iter.ReadUint64())
}
}
func (codec *uintptrCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint64(uint64(*((*uintptr)(ptr))))
}
func (codec *uintptrCodec) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec)
}
func (codec *uintptrCodec) IsEmpty(ptr unsafe.Pointer) bool {
return *((*uintptr)(ptr)) == 0
}
type int8Codec struct { 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) {
stream.WriteInt8(*((*int8)(ptr))) stream.WriteInt8(*((*int8)(ptr)))
} }
func (codec *int8Codec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *int8Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *int8Codec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *int8Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*int8)(ptr)) == 0 return *((*int8)(ptr)) == 0
} }
type int16Codec struct { 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) {
stream.WriteInt16(*((*int16)(ptr))) stream.WriteInt16(*((*int16)(ptr)))
} }
func (codec *int16Codec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *int16Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *int16Codec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *int16Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*int16)(ptr)) == 0 return *((*int16)(ptr)) == 0
} }
type int32Codec struct { 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) {
stream.WriteInt32(*((*int32)(ptr))) stream.WriteInt32(*((*int32)(ptr)))
} }
func (codec *int32Codec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *int32Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *int32Codec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *int32Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*int32)(ptr)) == 0 return *((*int32)(ptr)) == 0
} }
type int64Codec struct { 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) {
stream.WriteInt64(*((*int64)(ptr))) stream.WriteInt64(*((*int64)(ptr)))
} }
func (codec *int64Codec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *int64Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *int64Codec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *int64Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*int64)(ptr)) == 0 return *((*int64)(ptr)) == 0
} }
type uintCodec struct { 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) {
stream.WriteUint(*((*uint)(ptr))) stream.WriteUint(*((*uint)(ptr)))
} }
func (codec *uintCodec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *uintCodec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *uintCodec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *uintCodec) isEmpty(ptr unsafe.Pointer) bool {
return *((*uint)(ptr)) == 0 return *((*uint)(ptr)) == 0
} }
type uint8Codec struct { 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) {
stream.WriteUint8(*((*uint8)(ptr))) stream.WriteUint8(*((*uint8)(ptr)))
} }
func (codec *uint8Codec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *uint8Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *uint8Codec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *uint8Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*uint8)(ptr)) == 0 return *((*uint8)(ptr)) == 0
} }
type uint16Codec struct { type uint16Codec struct {
} }
func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *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) {
stream.WriteUint16(*((*uint16)(ptr))) stream.WriteUint16(*((*uint16)(ptr)))
} }
func (codec *uint16Codec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *uint16Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *uint16Codec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *uint16Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*uint16)(ptr)) == 0 return *((*uint16)(ptr)) == 0
} }
type uint32Codec struct { 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) {
stream.WriteUint32(*((*uint32)(ptr))) stream.WriteUint32(*((*uint32)(ptr)))
} }
func (codec *uint32Codec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *uint32Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *uint32Codec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *uint32Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*uint32)(ptr)) == 0 return *((*uint32)(ptr)) == 0
} }
type uint64Codec struct { 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) {
stream.WriteUint64(*((*uint64)(ptr))) stream.WriteUint64(*((*uint64)(ptr)))
} }
func (codec *uint64Codec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *uint64Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *uint64Codec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *uint64Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*uint64)(ptr)) == 0 return *((*uint64)(ptr)) == 0
} }
type float32Codec struct { 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) {
stream.WriteFloat32(*((*float32)(ptr))) stream.WriteFloat32(*((*float32)(ptr)))
} }
func (codec *float32Codec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *float32Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *float32Codec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *float32Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*float32)(ptr)) == 0 return *((*float32)(ptr)) == 0
} }
type float64Codec struct { 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) {
stream.WriteFloat64(*((*float64)(ptr))) stream.WriteFloat64(*((*float64)(ptr)))
} }
func (codec *float64Codec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *float64Codec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *float64Codec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *float64Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*float64)(ptr)) == 0 return *((*float64)(ptr)) == 0
} }
type boolCodec struct { 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) {
stream.WriteBool(*((*bool)(ptr))) stream.WriteBool(*((*bool)(ptr)))
} }
func (codec *boolCodec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *boolCodec) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, codec) writeToStream(val, stream, encoder)
} }
func (codec *boolCodec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *boolCodec) isEmpty(ptr unsafe.Pointer) bool {
return !(*((*bool)(ptr))) return !(*((*bool)(ptr)))
} }
type emptyInterfaceCodec struct { type emptyInterfaceCodec struct {
} }
func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *emptyInterfaceCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
existing := *((*interface{})(ptr)) *((*interface{})(ptr)) = iter.Read()
// 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()
}
} }
func (codec *emptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *emptyInterfaceCodec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteVal(*((*interface{})(ptr))) stream.WriteVal(*((*interface{})(ptr)))
} }
func (codec *emptyInterfaceCodec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *emptyInterfaceCodec) encodeInterface(val interface{}, stream *Stream) {
stream.WriteVal(val) stream.WriteVal(val)
} }
func (codec *emptyInterfaceCodec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *emptyInterfaceCodec) isEmpty(ptr unsafe.Pointer) bool {
emptyInterface := (*emptyInterface)(ptr) return ptr == nil
return emptyInterface.typ == nil
} }
type nonEmptyInterfaceCodec struct { type nonEmptyInterfaceCodec struct {
} }
func (codec *nonEmptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *nonEmptyInterfaceCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
nonEmptyInterface := (*nonEmptyInterface)(ptr) nonEmptyInterface := (*nonEmptyInterface)(ptr)
if nonEmptyInterface.itab == nil { if nonEmptyInterface.itab == nil {
iter.ReportError("read non-empty interface", "do not know which concrete type to decode to") iter.reportError("read non-empty interface", "do not know which concrete type to decode to")
return return
} }
var i interface{} var i interface{}
@ -392,28 +306,23 @@ 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)
} }
func (codec *nonEmptyInterfaceCodec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *nonEmptyInterfaceCodec) encodeInterface(val interface{}, stream *Stream) {
stream.WriteVal(val) stream.WriteVal(val)
} }
func (codec *nonEmptyInterfaceCodec) IsEmpty(ptr unsafe.Pointer) bool { func (codec *nonEmptyInterfaceCodec) isEmpty(ptr unsafe.Pointer) bool {
nonEmptyInterface := (*nonEmptyInterface)(ptr) nonEmptyInterface := (*nonEmptyInterface)(ptr)
return nonEmptyInterface.word == nil return nonEmptyInterface.word == nil
} }
@ -421,143 +330,81 @@ func (codec *nonEmptyInterfaceCodec) IsEmpty(ptr unsafe.Pointer) bool {
type anyCodec struct { type anyCodec struct {
} }
func (codec *anyCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *anyCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*Any)(ptr)) = iter.ReadAny() *((*Any)(ptr)) = iter.ReadAny()
} }
func (codec *anyCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *anyCodec) encode(ptr unsafe.Pointer, stream *Stream) {
(*((*Any)(ptr))).WriteTo(stream) (*((*Any)(ptr))).WriteTo(stream)
} }
func (codec *anyCodec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *anyCodec) encodeInterface(val interface{}, stream *Stream) {
(val.(Any)).WriteTo(stream) (val.(Any)).WriteTo(stream)
} }
func (codec *anyCodec) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *anyCodec) isEmpty(ptr unsafe.Pointer) bool {
return (*((*Any)(ptr))).Size() == 0 return (*((*Any)(ptr))).Size() == 0
} }
type jsonNumberCodec struct { type jsonNumberCodec struct {
} }
func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *jsonNumberCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*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) {
stream.WriteRaw(string(*((*json.Number)(ptr)))) stream.WriteRaw(string(*((*json.Number)(ptr))))
} }
func (codec *jsonNumberCodec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *jsonNumberCodec) encodeInterface(val interface{}, stream *Stream) {
stream.WriteRaw(string(val.(json.Number))) stream.WriteRaw(string(val.(json.Number)))
} }
func (codec *jsonNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *jsonNumberCodec) isEmpty(ptr unsafe.Pointer) bool {
return len(*((*json.Number)(ptr))) == 0 return len(*((*json.Number)(ptr))) == 0
} }
type jsoniterNumberCodec struct {
}
func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
*((*Number)(ptr)) = Number([]byte(iter.readNumberAsString()))
}
func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteRaw(string(*((*Number)(ptr))))
}
func (codec *jsoniterNumberCodec) EncodeInterface(val interface{}, stream *Stream) {
stream.WriteRaw(string(val.(Number)))
}
func (codec *jsoniterNumberCodec) IsEmpty(ptr unsafe.Pointer) bool {
return len(*((*Number)(ptr))) == 0
}
type jsonRawMessageCodec struct { type jsonRawMessageCodec struct {
} }
func (codec *jsonRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *jsonRawMessageCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*json.RawMessage)(ptr)) = json.RawMessage(iter.SkipAndReturnBytes()) *((*json.RawMessage)(ptr)) = json.RawMessage(iter.SkipAndReturnBytes())
} }
func (codec *jsonRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *jsonRawMessageCodec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteRaw(string(*((*json.RawMessage)(ptr)))) stream.WriteRaw(string(*((*json.RawMessage)(ptr))))
} }
func (codec *jsonRawMessageCodec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *jsonRawMessageCodec) encodeInterface(val interface{}, stream *Stream) {
stream.WriteRaw(string(val.(json.RawMessage))) stream.WriteRaw(string(val.(json.RawMessage)))
} }
func (codec *jsonRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *jsonRawMessageCodec) isEmpty(ptr unsafe.Pointer) bool {
return len(*((*json.RawMessage)(ptr))) == 0 return len(*((*json.RawMessage)(ptr))) == 0
} }
type jsoniterRawMessageCodec struct {
}
func (codec *jsoniterRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
*((*RawMessage)(ptr)) = RawMessage(iter.SkipAndReturnBytes())
}
func (codec *jsoniterRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteRaw(string(*((*RawMessage)(ptr))))
}
func (codec *jsoniterRawMessageCodec) EncodeInterface(val interface{}, stream *Stream) {
stream.WriteRaw(string(val.(RawMessage)))
}
func (codec *jsoniterRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool {
return len(*((*RawMessage)(ptr))) == 0
}
type base64Codec struct { type base64Codec struct {
sliceDecoder ValDecoder
} }
func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *base64Codec) decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() { encoding := base64.StdEncoding
ptrSlice := (*sliceHeader)(ptr) src := iter.SkipAndReturnBytes()
ptrSlice.Len = 0 src = src[1 : len(src)-1]
ptrSlice.Cap = 0 decodedLen := encoding.DecodedLen(len(src))
ptrSlice.Data = nil dst := make([]byte, decodedLen)
return _, err := encoding.Decode(dst, src)
} if err != nil {
switch iter.WhatIsNext() { iter.reportError("decode base64", err.Error())
case StringValue: } else {
encoding := base64.StdEncoding *((*[]byte)(ptr)) = dst
src := iter.SkipAndReturnBytes()
src = src[1 : len(src)-1]
decodedLen := encoding.DecodedLen(len(src))
dst := make([]byte, decodedLen)
len, err := encoding.Decode(dst, src)
if err != nil {
iter.ReportError("decode base64", err.Error())
} else {
dst = dst[:len]
dstSlice := (*sliceHeader)(unsafe.Pointer(&dst))
ptrSlice := (*sliceHeader)(ptr)
ptrSlice.Data = dstSlice.Data
ptrSlice.Cap = dstSlice.Cap
ptrSlice.Len = dstSlice.Len
}
case ArrayValue:
codec.sliceDecoder.Decode(ptr, iter)
default:
iter.ReportError("base64Codec", "invalid input")
} }
} }
func (codec *base64Codec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *base64Codec) encode(ptr unsafe.Pointer, stream *Stream) {
src := *((*[]byte)(ptr))
if len(src) == 0 {
stream.WriteNil()
return
}
encoding := base64.StdEncoding encoding := base64.StdEncoding
stream.writeByte('"') stream.writeByte('"')
src := *((*[]byte)(ptr))
toGrow := encoding.EncodedLen(len(src)) toGrow := encoding.EncodedLen(len(src))
stream.ensure(toGrow) stream.ensure(toGrow)
encoding.Encode(stream.buf[stream.n:], src) encoding.Encode(stream.buf[stream.n:], src)
@ -565,15 +412,10 @@ func (codec *base64Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.writeByte('"') stream.writeByte('"')
} }
func (codec *base64Codec) EncodeInterface(val interface{}, stream *Stream) { func (encoder *base64Codec) encodeInterface(val interface{}, stream *Stream) {
ptr := extractInterface(val).word
src := *((*[]byte)(ptr))
if len(src) == 0 {
stream.WriteNil()
return
}
encoding := base64.StdEncoding encoding := base64.StdEncoding
stream.writeByte('"') stream.writeByte('"')
src := val.([]byte)
toGrow := encoding.EncodedLen(len(src)) toGrow := encoding.EncodedLen(len(src))
stream.ensure(toGrow) stream.ensure(toGrow)
encoding.Encode(stream.buf[stream.n:], src) encoding.Encode(stream.buf[stream.n:], src)
@ -581,97 +423,40 @@ func (codec *base64Codec) EncodeInterface(val interface{}, stream *Stream) {
stream.writeByte('"') stream.writeByte('"')
} }
func (codec *base64Codec) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *base64Codec) isEmpty(ptr unsafe.Pointer) bool {
return len(*((*[]byte)(ptr))) == 0 return len(*((*[]byte)(ptr))) == 0
} }
type stringModeNumberDecoder struct { type stringNumberDecoder struct {
elemDecoder ValDecoder elemDecoder Decoder
} }
func (decoder *stringModeNumberDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *stringNumberDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
c := iter.nextToken() c := iter.nextToken()
if c != '"' { if c != '"' {
iter.ReportError("stringModeNumberDecoder", `expect "`) iter.reportError("stringNumberDecoder", `expect "`)
return return
} }
decoder.elemDecoder.Decode(ptr, iter) decoder.elemDecoder.decode(ptr, iter)
if iter.Error != nil { if iter.Error != nil {
return return
} }
c = iter.readByte() c = iter.readByte()
if c != '"' { if c != '"' {
iter.ReportError("stringModeNumberDecoder", `expect "`) iter.reportError("stringNumberDecoder", `expect "`)
return return
} }
} }
type stringModeStringDecoder struct {
elemDecoder ValDecoder
cfg *frozenConfig
}
func (decoder *stringModeStringDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.elemDecoder.Decode(ptr, iter)
str := *((*string)(ptr))
tempIter := decoder.cfg.BorrowIterator([]byte(str))
defer decoder.cfg.ReturnIterator(tempIter)
*((*string)(ptr)) = tempIter.ReadString()
}
type stringModeNumberEncoder struct {
elemEncoder ValEncoder
}
func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.writeByte('"')
encoder.elemEncoder.Encode(ptr, stream)
stream.writeByte('"')
}
func (encoder *stringModeNumberEncoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
}
func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.elemEncoder.IsEmpty(ptr)
}
type stringModeStringEncoder struct {
elemEncoder ValEncoder
cfg *frozenConfig
}
func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
tempStream := encoder.cfg.BorrowStream(nil)
defer encoder.cfg.ReturnStream(tempStream)
encoder.elemEncoder.Encode(ptr, tempStream)
stream.WriteString(string(tempStream.Buffer()))
}
func (encoder *stringModeStringEncoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
}
func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.elemEncoder.IsEmpty(ptr)
}
type marshalerEncoder struct { type marshalerEncoder struct {
templateInterface emptyInterface templateInterface emptyInterface
checkIsEmpty checkIsEmpty
} }
func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { 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, ok := (*realInterface).(json.Marshaler) marshaler := (*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
@ -679,70 +464,35 @@ func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.Write(bytes) stream.Write(bytes)
} }
} }
func (encoder *marshalerEncoder) EncodeInterface(val interface{}, stream *Stream) { func (encoder *marshalerEncoder) encodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder) writeToStream(val, stream, encoder)
} }
func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool { func (encoder *marshalerEncoder) isEmpty(ptr unsafe.Pointer) bool {
return encoder.checkIsEmpty.IsEmpty(ptr)
}
type textMarshalerEncoder struct {
templateInterface emptyInterface
checkIsEmpty checkIsEmpty
}
func (encoder *textMarshalerEncoder) 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).(encoding.TextMarshaler) marshaler := (*realInterface).(json.Marshaler)
bytes, err := marshaler.MarshalText() bytes, err := marshaler.MarshalJSON()
if err != nil { if err != nil {
stream.Error = err return true
} else { } else {
stream.WriteString(string(bytes)) return len(bytes) > 0
} }
} }
func (encoder *textMarshalerEncoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
}
func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.checkIsEmpty.IsEmpty(ptr)
}
type unmarshalerDecoder struct { type unmarshalerDecoder struct {
templateInterface emptyInterface templateInterface emptyInterface
} }
func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) { func (decoder *unmarshalerDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
templateInterface := decoder.templateInterface templateInterface := decoder.templateInterface
templateInterface.word = ptr templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface)) realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
unmarshaler := (*realInterface).(json.Unmarshaler) unmarshaler := (*realInterface).(json.Unmarshaler)
iter.nextToken()
iter.unreadByte() // skip spaces
bytes := iter.SkipAndReturnBytes() bytes := iter.SkipAndReturnBytes()
err := unmarshaler.UnmarshalJSON(bytes) err := unmarshaler.UnmarshalJSON(bytes)
if err != nil { if err != nil {
iter.ReportError("unmarshalerDecoder", err.Error()) iter.reportError("unmarshaler", err.Error())
}
}
type textUnmarshalerDecoder struct {
templateInterface emptyInterface
}
func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
templateInterface := decoder.templateInterface
templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
unmarshaler := (*realInterface).(encoding.TextUnmarshaler)
str := iter.ReadString()
err := unmarshaler.UnmarshalText([]byte(str))
if err != nil {
iter.ReportError("textUnmarshalerDecoder", err.Error())
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,149 +0,0 @@
package jsoniter
import (
"fmt"
"io"
"reflect"
"unsafe"
)
func decoderOfSlice(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) {
decoder, err := decoderOfType(cfg, typ.Elem())
if err != nil {
return nil, err
}
return &sliceDecoder{typ, typ.Elem(), decoder}, nil
}
func encoderOfSlice(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
encoder, err := encoderOfType(cfg, typ.Elem())
if err != nil {
return nil, err
}
if typ.Elem().Kind() == reflect.Map {
encoder = &optionalEncoder{encoder}
}
return &sliceEncoder{typ, typ.Elem(), encoder}, nil
}
type sliceEncoder struct {
sliceType reflect.Type
elemType reflect.Type
elemEncoder ValEncoder
}
func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
slice := (*sliceHeader)(ptr)
if slice.Data == nil {
stream.WriteNil()
return
}
if slice.Len == 0 {
stream.WriteEmptyArray()
return
}
stream.WriteArrayStart()
elemPtr := unsafe.Pointer(slice.Data)
encoder.elemEncoder.Encode(unsafe.Pointer(elemPtr), stream)
for i := 1; i < slice.Len; i++ {
stream.WriteMore()
elemPtr = unsafe.Pointer(uintptr(elemPtr) + encoder.elemType.Size())
encoder.elemEncoder.Encode(unsafe.Pointer(elemPtr), stream)
}
stream.WriteArrayEnd()
if stream.Error != nil && stream.Error != io.EOF {
stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error())
}
}
func (encoder *sliceEncoder) EncodeInterface(val interface{}, stream *Stream) {
WriteToStream(val, stream, encoder)
}
func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
slice := (*sliceHeader)(ptr)
return slice.Len == 0
}
type sliceDecoder struct {
sliceType reflect.Type
elemType reflect.Type
elemDecoder ValDecoder
}
// sliceHeader is a safe version of SliceHeader used within this package.
type sliceHeader struct {
Data unsafe.Pointer
Len int
Cap int
}
func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.doDecode(ptr, iter)
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
}
}
func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
slice := (*sliceHeader)(ptr)
if iter.ReadNil() {
slice.Len = 0
slice.Cap = 0
slice.Data = nil
return
}
reuseSlice(slice, decoder.sliceType, 4)
slice.Len = 0
offset := uintptr(0)
iter.ReadArrayCB(func(iter *Iterator) bool {
growOne(slice, decoder.sliceType, decoder.elemType)
decoder.elemDecoder.Decode(unsafe.Pointer(uintptr(slice.Data)+offset), iter)
offset += decoder.elemType.Size()
return true
})
}
// grow grows the slice s so that it can hold extra more values, allocating
// more capacity if needed. It also returns the old and new slice lengths.
func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
newLen := slice.Len + 1
if newLen <= slice.Cap {
slice.Len = newLen
return
}
newCap := slice.Cap
if newCap == 0 {
newCap = 1
} else {
for newCap < newLen {
if slice.Len < 1024 {
newCap += newCap
} else {
newCap += newCap / 4
}
}
}
newVal := reflect.MakeSlice(sliceType, newLen, newCap)
dst := unsafe.Pointer(newVal.Pointer())
// copy old array into new array
originalBytesCount := uintptr(slice.Len) * elementType.Size()
srcPtr := (*[1 << 30]byte)(slice.Data)
dstPtr := (*[1 << 30]byte)(dst)
for i := uintptr(0); i < originalBytesCount; i++ {
dstPtr[i] = srcPtr[i]
}
slice.Data = dst
slice.Len = newLen
slice.Cap = newCap
}
func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
if expectedCap <= slice.Cap {
return
}
newVal := reflect.MakeSlice(sliceType, 0, expectedCap)
dst := unsafe.Pointer(newVal.Pointer())
slice.Data = dst
slice.Cap = expectedCap
}

View File

@ -1,916 +0,0 @@
package jsoniter
import (
"fmt"
"io"
"reflect"
"strings"
"unsafe"
)
func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder) (ValDecoder, error) {
knownHash := map[int32]struct{}{
0: {},
}
switch len(fields) {
case 0:
return &skipObjectDecoder{typ}, nil
case 1:
for fieldName, fieldDecoder := range fields {
fieldHash := calcHash(fieldName)
_, known := knownHash[fieldHash]
if known {
return &generalStructDecoder{typ, fields}, nil
}
knownHash[fieldHash] = struct{}{}
return &oneFieldStructDecoder{typ, fieldHash, fieldDecoder}, nil
}
case 2:
var fieldHash1 int32
var fieldHash2 int32
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
fieldHash := calcHash(fieldName)
_, known := knownHash[fieldHash]
if known {
return &generalStructDecoder{typ, fields}, nil
}
knownHash[fieldHash] = struct{}{}
if fieldHash1 == 0 {
fieldHash1 = fieldHash
fieldDecoder1 = fieldDecoder
} else {
fieldHash2 = fieldHash
fieldDecoder2 = fieldDecoder
}
}
return &twoFieldsStructDecoder{typ, fieldHash1, fieldDecoder1, fieldHash2, fieldDecoder2}, nil
case 3:
var fieldName1 int32
var fieldName2 int32
var fieldName3 int32
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
var fieldDecoder3 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
fieldHash := calcHash(fieldName)
_, known := knownHash[fieldHash]
if known {
return &generalStructDecoder{typ, fields}, nil
}
knownHash[fieldHash] = struct{}{}
if fieldName1 == 0 {
fieldName1 = fieldHash
fieldDecoder1 = fieldDecoder
} else if fieldName2 == 0 {
fieldName2 = fieldHash
fieldDecoder2 = fieldDecoder
} else {
fieldName3 = fieldHash
fieldDecoder3 = fieldDecoder
}
}
return &threeFieldsStructDecoder{typ,
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
case 4:
var fieldName1 int32
var fieldName2 int32
var fieldName3 int32
var fieldName4 int32
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
var fieldDecoder3 *structFieldDecoder
var fieldDecoder4 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
fieldHash := calcHash(fieldName)
_, known := knownHash[fieldHash]
if known {
return &generalStructDecoder{typ, fields}, nil
}
knownHash[fieldHash] = struct{}{}
if fieldName1 == 0 {
fieldName1 = fieldHash
fieldDecoder1 = fieldDecoder
} else if fieldName2 == 0 {
fieldName2 = fieldHash
fieldDecoder2 = fieldDecoder
} else if fieldName3 == 0 {
fieldName3 = fieldHash
fieldDecoder3 = fieldDecoder
} else {
fieldName4 = fieldHash
fieldDecoder4 = fieldDecoder
}
}
return &fourFieldsStructDecoder{typ,
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
fieldName4, fieldDecoder4}, nil
case 5:
var fieldName1 int32
var fieldName2 int32
var fieldName3 int32
var fieldName4 int32
var fieldName5 int32
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
var fieldDecoder3 *structFieldDecoder
var fieldDecoder4 *structFieldDecoder
var fieldDecoder5 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
fieldHash := calcHash(fieldName)
_, known := knownHash[fieldHash]
if known {
return &generalStructDecoder{typ, fields}, nil
}
knownHash[fieldHash] = struct{}{}
if fieldName1 == 0 {
fieldName1 = fieldHash
fieldDecoder1 = fieldDecoder
} else if fieldName2 == 0 {
fieldName2 = fieldHash
fieldDecoder2 = fieldDecoder
} else if fieldName3 == 0 {
fieldName3 = fieldHash
fieldDecoder3 = fieldDecoder
} else if fieldName4 == 0 {
fieldName4 = fieldHash
fieldDecoder4 = fieldDecoder
} else {
fieldName5 = fieldHash
fieldDecoder5 = fieldDecoder
}
}
return &fiveFieldsStructDecoder{typ,
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil
case 6:
var fieldName1 int32
var fieldName2 int32
var fieldName3 int32
var fieldName4 int32
var fieldName5 int32
var fieldName6 int32
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
var fieldDecoder3 *structFieldDecoder
var fieldDecoder4 *structFieldDecoder
var fieldDecoder5 *structFieldDecoder
var fieldDecoder6 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
fieldHash := calcHash(fieldName)
_, known := knownHash[fieldHash]
if known {
return &generalStructDecoder{typ, fields}, nil
}
knownHash[fieldHash] = struct{}{}
if fieldName1 == 0 {
fieldName1 = fieldHash
fieldDecoder1 = fieldDecoder
} else if fieldName2 == 0 {
fieldName2 = fieldHash
fieldDecoder2 = fieldDecoder
} else if fieldName3 == 0 {
fieldName3 = fieldHash
fieldDecoder3 = fieldDecoder
} else if fieldName4 == 0 {
fieldName4 = fieldHash
fieldDecoder4 = fieldDecoder
} else if fieldName5 == 0 {
fieldName5 = fieldHash
fieldDecoder5 = fieldDecoder
} else {
fieldName6 = fieldHash
fieldDecoder6 = fieldDecoder
}
}
return &sixFieldsStructDecoder{typ,
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil
case 7:
var fieldName1 int32
var fieldName2 int32
var fieldName3 int32
var fieldName4 int32
var fieldName5 int32
var fieldName6 int32
var fieldName7 int32
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
var fieldDecoder3 *structFieldDecoder
var fieldDecoder4 *structFieldDecoder
var fieldDecoder5 *structFieldDecoder
var fieldDecoder6 *structFieldDecoder
var fieldDecoder7 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
fieldHash := calcHash(fieldName)
_, known := knownHash[fieldHash]
if known {
return &generalStructDecoder{typ, fields}, nil
}
knownHash[fieldHash] = struct{}{}
if fieldName1 == 0 {
fieldName1 = fieldHash
fieldDecoder1 = fieldDecoder
} else if fieldName2 == 0 {
fieldName2 = fieldHash
fieldDecoder2 = fieldDecoder
} else if fieldName3 == 0 {
fieldName3 = fieldHash
fieldDecoder3 = fieldDecoder
} else if fieldName4 == 0 {
fieldName4 = fieldHash
fieldDecoder4 = fieldDecoder
} else if fieldName5 == 0 {
fieldName5 = fieldHash
fieldDecoder5 = fieldDecoder
} else if fieldName6 == 0 {
fieldName6 = fieldHash
fieldDecoder6 = fieldDecoder
} else {
fieldName7 = fieldHash
fieldDecoder7 = fieldDecoder
}
}
return &sevenFieldsStructDecoder{typ,
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
fieldName7, fieldDecoder7}, nil
case 8:
var fieldName1 int32
var fieldName2 int32
var fieldName3 int32
var fieldName4 int32
var fieldName5 int32
var fieldName6 int32
var fieldName7 int32
var fieldName8 int32
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
var fieldDecoder3 *structFieldDecoder
var fieldDecoder4 *structFieldDecoder
var fieldDecoder5 *structFieldDecoder
var fieldDecoder6 *structFieldDecoder
var fieldDecoder7 *structFieldDecoder
var fieldDecoder8 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
fieldHash := calcHash(fieldName)
_, known := knownHash[fieldHash]
if known {
return &generalStructDecoder{typ, fields}, nil
}
knownHash[fieldHash] = struct{}{}
if fieldName1 == 0 {
fieldName1 = fieldHash
fieldDecoder1 = fieldDecoder
} else if fieldName2 == 0 {
fieldName2 = fieldHash
fieldDecoder2 = fieldDecoder
} else if fieldName3 == 0 {
fieldName3 = fieldHash
fieldDecoder3 = fieldDecoder
} else if fieldName4 == 0 {
fieldName4 = fieldHash
fieldDecoder4 = fieldDecoder
} else if fieldName5 == 0 {
fieldName5 = fieldHash
fieldDecoder5 = fieldDecoder
} else if fieldName6 == 0 {
fieldName6 = fieldHash
fieldDecoder6 = fieldDecoder
} else if fieldName7 == 0 {
fieldName7 = fieldHash
fieldDecoder7 = fieldDecoder
} else {
fieldName8 = fieldHash
fieldDecoder8 = fieldDecoder
}
}
return &eightFieldsStructDecoder{typ,
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil
case 9:
var fieldName1 int32
var fieldName2 int32
var fieldName3 int32
var fieldName4 int32
var fieldName5 int32
var fieldName6 int32
var fieldName7 int32
var fieldName8 int32
var fieldName9 int32
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
var fieldDecoder3 *structFieldDecoder
var fieldDecoder4 *structFieldDecoder
var fieldDecoder5 *structFieldDecoder
var fieldDecoder6 *structFieldDecoder
var fieldDecoder7 *structFieldDecoder
var fieldDecoder8 *structFieldDecoder
var fieldDecoder9 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
fieldHash := calcHash(fieldName)
_, known := knownHash[fieldHash]
if known {
return &generalStructDecoder{typ, fields}, nil
}
knownHash[fieldHash] = struct{}{}
if fieldName1 == 0 {
fieldName1 = fieldHash
fieldDecoder1 = fieldDecoder
} else if fieldName2 == 0 {
fieldName2 = fieldHash
fieldDecoder2 = fieldDecoder
} else if fieldName3 == 0 {
fieldName3 = fieldHash
fieldDecoder3 = fieldDecoder
} else if fieldName4 == 0 {
fieldName4 = fieldHash
fieldDecoder4 = fieldDecoder
} else if fieldName5 == 0 {
fieldName5 = fieldHash
fieldDecoder5 = fieldDecoder
} else if fieldName6 == 0 {
fieldName6 = fieldHash
fieldDecoder6 = fieldDecoder
} else if fieldName7 == 0 {
fieldName7 = fieldHash
fieldDecoder7 = fieldDecoder
} else if fieldName8 == 0 {
fieldName8 = fieldHash
fieldDecoder8 = fieldDecoder
} else {
fieldName9 = fieldHash
fieldDecoder9 = fieldDecoder
}
}
return &nineFieldsStructDecoder{typ,
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil
case 10:
var fieldName1 int32
var fieldName2 int32
var fieldName3 int32
var fieldName4 int32
var fieldName5 int32
var fieldName6 int32
var fieldName7 int32
var fieldName8 int32
var fieldName9 int32
var fieldName10 int32
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
var fieldDecoder3 *structFieldDecoder
var fieldDecoder4 *structFieldDecoder
var fieldDecoder5 *structFieldDecoder
var fieldDecoder6 *structFieldDecoder
var fieldDecoder7 *structFieldDecoder
var fieldDecoder8 *structFieldDecoder
var fieldDecoder9 *structFieldDecoder
var fieldDecoder10 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
fieldHash := calcHash(fieldName)
_, known := knownHash[fieldHash]
if known {
return &generalStructDecoder{typ, fields}, nil
}
knownHash[fieldHash] = struct{}{}
if fieldName1 == 0 {
fieldName1 = fieldHash
fieldDecoder1 = fieldDecoder
} else if fieldName2 == 0 {
fieldName2 = fieldHash
fieldDecoder2 = fieldDecoder
} else if fieldName3 == 0 {
fieldName3 = fieldHash
fieldDecoder3 = fieldDecoder
} else if fieldName4 == 0 {
fieldName4 = fieldHash
fieldDecoder4 = fieldDecoder
} else if fieldName5 == 0 {
fieldName5 = fieldHash
fieldDecoder5 = fieldDecoder
} else if fieldName6 == 0 {
fieldName6 = fieldHash
fieldDecoder6 = fieldDecoder
} else if fieldName7 == 0 {
fieldName7 = fieldHash
fieldDecoder7 = fieldDecoder
} else if fieldName8 == 0 {
fieldName8 = fieldHash
fieldDecoder8 = fieldDecoder
} else if fieldName9 == 0 {
fieldName9 = fieldHash
fieldDecoder9 = fieldDecoder
} else {
fieldName10 = fieldHash
fieldDecoder10 = fieldDecoder
}
}
return &tenFieldsStructDecoder{typ,
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9,
fieldName10, fieldDecoder10}, nil
}
return &generalStructDecoder{typ, fields}, nil
}
type generalStructDecoder struct {
typ reflect.Type
fields map[string]*structFieldDecoder
}
func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.readObjectStart() {
return
}
fieldBytes := iter.readObjectFieldAsBytes()
field := *(*string)(unsafe.Pointer(&fieldBytes))
fieldDecoder := decoder.fields[strings.ToLower(field)]
if fieldDecoder == nil {
iter.Skip()
} else {
fieldDecoder.Decode(ptr, iter)
}
for iter.nextToken() == ',' {
fieldBytes = iter.readObjectFieldAsBytes()
field = *(*string)(unsafe.Pointer(&fieldBytes))
fieldDecoder = decoder.fields[strings.ToLower(field)]
if fieldDecoder == nil {
iter.Skip()
} else {
fieldDecoder.Decode(ptr, iter)
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
}
}
type skipObjectDecoder struct {
typ reflect.Type
}
func (decoder *skipObjectDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
valueType := iter.WhatIsNext()
if valueType != ObjectValue && valueType != NilValue {
iter.ReportError("skipObjectDecoder", "expect object or null")
return
}
iter.Skip()
}
type oneFieldStructDecoder struct {
typ reflect.Type
fieldHash int32
fieldDecoder *structFieldDecoder
}
func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.readObjectStart() {
return
}
for {
if iter.readFieldHash() == decoder.fieldHash {
decoder.fieldDecoder.Decode(ptr, iter)
} else {
iter.Skip()
}
if iter.isObjectEnd() {
break
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
}
}
type twoFieldsStructDecoder struct {
typ reflect.Type
fieldHash1 int32
fieldDecoder1 *structFieldDecoder
fieldHash2 int32
fieldDecoder2 *structFieldDecoder
}
func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.readObjectStart() {
return
}
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
decoder.fieldDecoder1.Decode(ptr, iter)
case decoder.fieldHash2:
decoder.fieldDecoder2.Decode(ptr, iter)
default:
iter.Skip()
}
if iter.isObjectEnd() {
break
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
}
}
type threeFieldsStructDecoder struct {
typ reflect.Type
fieldHash1 int32
fieldDecoder1 *structFieldDecoder
fieldHash2 int32
fieldDecoder2 *structFieldDecoder
fieldHash3 int32
fieldDecoder3 *structFieldDecoder
}
func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.readObjectStart() {
return
}
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
decoder.fieldDecoder1.Decode(ptr, iter)
case decoder.fieldHash2:
decoder.fieldDecoder2.Decode(ptr, iter)
case decoder.fieldHash3:
decoder.fieldDecoder3.Decode(ptr, iter)
default:
iter.Skip()
}
if iter.isObjectEnd() {
break
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
}
}
type fourFieldsStructDecoder struct {
typ reflect.Type
fieldHash1 int32
fieldDecoder1 *structFieldDecoder
fieldHash2 int32
fieldDecoder2 *structFieldDecoder
fieldHash3 int32
fieldDecoder3 *structFieldDecoder
fieldHash4 int32
fieldDecoder4 *structFieldDecoder
}
func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.readObjectStart() {
return
}
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
decoder.fieldDecoder1.Decode(ptr, iter)
case decoder.fieldHash2:
decoder.fieldDecoder2.Decode(ptr, iter)
case decoder.fieldHash3:
decoder.fieldDecoder3.Decode(ptr, iter)
case decoder.fieldHash4:
decoder.fieldDecoder4.Decode(ptr, iter)
default:
iter.Skip()
}
if iter.isObjectEnd() {
break
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
}
}
type fiveFieldsStructDecoder struct {
typ reflect.Type
fieldHash1 int32
fieldDecoder1 *structFieldDecoder
fieldHash2 int32
fieldDecoder2 *structFieldDecoder
fieldHash3 int32
fieldDecoder3 *structFieldDecoder
fieldHash4 int32
fieldDecoder4 *structFieldDecoder
fieldHash5 int32
fieldDecoder5 *structFieldDecoder
}
func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.readObjectStart() {
return
}
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
decoder.fieldDecoder1.Decode(ptr, iter)
case decoder.fieldHash2:
decoder.fieldDecoder2.Decode(ptr, iter)
case decoder.fieldHash3:
decoder.fieldDecoder3.Decode(ptr, iter)
case decoder.fieldHash4:
decoder.fieldDecoder4.Decode(ptr, iter)
case decoder.fieldHash5:
decoder.fieldDecoder5.Decode(ptr, iter)
default:
iter.Skip()
}
if iter.isObjectEnd() {
break
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
}
}
type sixFieldsStructDecoder struct {
typ reflect.Type
fieldHash1 int32
fieldDecoder1 *structFieldDecoder
fieldHash2 int32
fieldDecoder2 *structFieldDecoder
fieldHash3 int32
fieldDecoder3 *structFieldDecoder
fieldHash4 int32
fieldDecoder4 *structFieldDecoder
fieldHash5 int32
fieldDecoder5 *structFieldDecoder
fieldHash6 int32
fieldDecoder6 *structFieldDecoder
}
func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.readObjectStart() {
return
}
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
decoder.fieldDecoder1.Decode(ptr, iter)
case decoder.fieldHash2:
decoder.fieldDecoder2.Decode(ptr, iter)
case decoder.fieldHash3:
decoder.fieldDecoder3.Decode(ptr, iter)
case decoder.fieldHash4:
decoder.fieldDecoder4.Decode(ptr, iter)
case decoder.fieldHash5:
decoder.fieldDecoder5.Decode(ptr, iter)
case decoder.fieldHash6:
decoder.fieldDecoder6.Decode(ptr, iter)
default:
iter.Skip()
}
if iter.isObjectEnd() {
break
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
}
}
type sevenFieldsStructDecoder struct {
typ reflect.Type
fieldHash1 int32
fieldDecoder1 *structFieldDecoder
fieldHash2 int32
fieldDecoder2 *structFieldDecoder
fieldHash3 int32
fieldDecoder3 *structFieldDecoder
fieldHash4 int32
fieldDecoder4 *structFieldDecoder
fieldHash5 int32
fieldDecoder5 *structFieldDecoder
fieldHash6 int32
fieldDecoder6 *structFieldDecoder
fieldHash7 int32
fieldDecoder7 *structFieldDecoder
}
func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.readObjectStart() {
return
}
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
decoder.fieldDecoder1.Decode(ptr, iter)
case decoder.fieldHash2:
decoder.fieldDecoder2.Decode(ptr, iter)
case decoder.fieldHash3:
decoder.fieldDecoder3.Decode(ptr, iter)
case decoder.fieldHash4:
decoder.fieldDecoder4.Decode(ptr, iter)
case decoder.fieldHash5:
decoder.fieldDecoder5.Decode(ptr, iter)
case decoder.fieldHash6:
decoder.fieldDecoder6.Decode(ptr, iter)
case decoder.fieldHash7:
decoder.fieldDecoder7.Decode(ptr, iter)
default:
iter.Skip()
}
if iter.isObjectEnd() {
break
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
}
}
type eightFieldsStructDecoder struct {
typ reflect.Type
fieldHash1 int32
fieldDecoder1 *structFieldDecoder
fieldHash2 int32
fieldDecoder2 *structFieldDecoder
fieldHash3 int32
fieldDecoder3 *structFieldDecoder
fieldHash4 int32
fieldDecoder4 *structFieldDecoder
fieldHash5 int32
fieldDecoder5 *structFieldDecoder
fieldHash6 int32
fieldDecoder6 *structFieldDecoder
fieldHash7 int32
fieldDecoder7 *structFieldDecoder
fieldHash8 int32
fieldDecoder8 *structFieldDecoder
}
func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.readObjectStart() {
return
}
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
decoder.fieldDecoder1.Decode(ptr, iter)
case decoder.fieldHash2:
decoder.fieldDecoder2.Decode(ptr, iter)
case decoder.fieldHash3:
decoder.fieldDecoder3.Decode(ptr, iter)
case decoder.fieldHash4:
decoder.fieldDecoder4.Decode(ptr, iter)
case decoder.fieldHash5:
decoder.fieldDecoder5.Decode(ptr, iter)
case decoder.fieldHash6:
decoder.fieldDecoder6.Decode(ptr, iter)
case decoder.fieldHash7:
decoder.fieldDecoder7.Decode(ptr, iter)
case decoder.fieldHash8:
decoder.fieldDecoder8.Decode(ptr, iter)
default:
iter.Skip()
}
if iter.isObjectEnd() {
break
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
}
}
type nineFieldsStructDecoder struct {
typ reflect.Type
fieldHash1 int32
fieldDecoder1 *structFieldDecoder
fieldHash2 int32
fieldDecoder2 *structFieldDecoder
fieldHash3 int32
fieldDecoder3 *structFieldDecoder
fieldHash4 int32
fieldDecoder4 *structFieldDecoder
fieldHash5 int32
fieldDecoder5 *structFieldDecoder
fieldHash6 int32
fieldDecoder6 *structFieldDecoder
fieldHash7 int32
fieldDecoder7 *structFieldDecoder
fieldHash8 int32
fieldDecoder8 *structFieldDecoder
fieldHash9 int32
fieldDecoder9 *structFieldDecoder
}
func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.readObjectStart() {
return
}
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
decoder.fieldDecoder1.Decode(ptr, iter)
case decoder.fieldHash2:
decoder.fieldDecoder2.Decode(ptr, iter)
case decoder.fieldHash3:
decoder.fieldDecoder3.Decode(ptr, iter)
case decoder.fieldHash4:
decoder.fieldDecoder4.Decode(ptr, iter)
case decoder.fieldHash5:
decoder.fieldDecoder5.Decode(ptr, iter)
case decoder.fieldHash6:
decoder.fieldDecoder6.Decode(ptr, iter)
case decoder.fieldHash7:
decoder.fieldDecoder7.Decode(ptr, iter)
case decoder.fieldHash8:
decoder.fieldDecoder8.Decode(ptr, iter)
case decoder.fieldHash9:
decoder.fieldDecoder9.Decode(ptr, iter)
default:
iter.Skip()
}
if iter.isObjectEnd() {
break
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
}
}
type tenFieldsStructDecoder struct {
typ reflect.Type
fieldHash1 int32
fieldDecoder1 *structFieldDecoder
fieldHash2 int32
fieldDecoder2 *structFieldDecoder
fieldHash3 int32
fieldDecoder3 *structFieldDecoder
fieldHash4 int32
fieldDecoder4 *structFieldDecoder
fieldHash5 int32
fieldDecoder5 *structFieldDecoder
fieldHash6 int32
fieldDecoder6 *structFieldDecoder
fieldHash7 int32
fieldDecoder7 *structFieldDecoder
fieldHash8 int32
fieldDecoder8 *structFieldDecoder
fieldHash9 int32
fieldDecoder9 *structFieldDecoder
fieldHash10 int32
fieldDecoder10 *structFieldDecoder
}
func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
if !iter.readObjectStart() {
return
}
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
decoder.fieldDecoder1.Decode(ptr, iter)
case decoder.fieldHash2:
decoder.fieldDecoder2.Decode(ptr, iter)
case decoder.fieldHash3:
decoder.fieldDecoder3.Decode(ptr, iter)
case decoder.fieldHash4:
decoder.fieldDecoder4.Decode(ptr, iter)
case decoder.fieldHash5:
decoder.fieldDecoder5.Decode(ptr, iter)
case decoder.fieldHash6:
decoder.fieldDecoder6.Decode(ptr, iter)
case decoder.fieldHash7:
decoder.fieldDecoder7.Decode(ptr, iter)
case decoder.fieldHash8:
decoder.fieldDecoder8.Decode(ptr, iter)
case decoder.fieldHash9:
decoder.fieldDecoder9.Decode(ptr, iter)
case decoder.fieldHash10:
decoder.fieldDecoder10.Decode(ptr, iter)
default:
iter.Skip()
}
if iter.isObjectEnd() {
break
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.typ, iter.Error.Error())
}
}
type structFieldDecoder struct {
field *reflect.StructField
fieldDecoder ValDecoder
}
func (decoder *structFieldDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
fieldPtr := unsafe.Pointer(uintptr(ptr) + decoder.field.Offset)
decoder.fieldDecoder.Decode(fieldPtr, iter)
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%s: %s", decoder.field.Name, iter.Error.Error())
}
}

View File

@ -4,229 +4,262 @@ import (
"io" "io"
) )
// 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.
type Stream struct { type Stream struct {
cfg *frozenConfig out io.Writer
out io.Writer buf []byte
buf []byte n int
n int Error error
Error error indention int
indention int IndentionStep int
} }
// NewStream create new stream instance. func NewStream(out io.Writer, bufSize int) *Stream {
// cfg can be jsoniter.ConfigDefault. return &Stream{out, make([]byte, bufSize), 0, nil, 0, 0}
// out can be nil if write to internal buffer.
// bufSize is the initial size for the internal buffer in bytes.
func NewStream(cfg API, out io.Writer, bufSize int) *Stream {
return &Stream{
cfg: cfg.(*frozenConfig),
out: out,
buf: make([]byte, bufSize),
n: 0,
Error: nil,
indention: 0,
}
} }
// Pool returns a pool can provide more stream with same configuration func (b *Stream) Reset(out io.Writer) {
func (stream *Stream) Pool() StreamPool { b.out = out
return stream.cfg b.n = 0
}
// Reset reuse this stream instance by assign a new writer
func (stream *Stream) Reset(out io.Writer) {
stream.out = out
stream.n = 0
} }
// Available returns how many bytes are unused in the buffer. // Available returns how many bytes are unused in the buffer.
func (stream *Stream) Available() int { func (b *Stream) Available() int {
return len(stream.buf) - stream.n return len(b.buf) - b.n
} }
// Buffered returns the number of bytes that have been written into the current buffer. // Buffered returns the number of bytes that have been written into the current buffer.
func (stream *Stream) Buffered() int { func (b *Stream) Buffered() int {
return stream.n return b.n
} }
// Buffer if writer is nil, use this method to take the result func (b *Stream) Buffer() []byte {
func (stream *Stream) Buffer() []byte { return b.buf[:b.n]
return stream.buf[:stream.n]
} }
// Write writes the contents of p into the buffer. // Write writes the contents of p into the buffer.
// It returns the number of bytes written. // It returns the number of bytes written.
// If nn < len(p), it also returns an error explaining // If nn < len(p), it also returns an error explaining
// why the write is short. // why the write is short.
func (stream *Stream) Write(p []byte) (nn int, err error) { func (b *Stream) Write(p []byte) (nn int, err error) {
for len(p) > stream.Available() && stream.Error == nil { for len(p) > b.Available() && b.Error == nil {
if stream.out == nil { if b.out == nil {
stream.growAtLeast(len(p)) b.growAtLeast(len(p))
} else { } else {
var n int var n int
if stream.Buffered() == 0 { if b.Buffered() == 0 {
// Large write, empty buffer. // Large write, empty buffer.
// Write directly from p to avoid copy. // Write directly from p to avoid copy.
n, stream.Error = stream.out.Write(p) n, b.Error = b.out.Write(p)
} else { } else {
n = copy(stream.buf[stream.n:], p) n = copy(b.buf[b.n:], p)
stream.n += n b.n += n
stream.Flush() b.Flush()
} }
nn += n nn += n
p = p[n:] p = p[n:]
} }
} }
if stream.Error != nil { if b.Error != nil {
return nn, stream.Error return nn, b.Error
} }
n := copy(stream.buf[stream.n:], p) n := copy(b.buf[b.n:], p)
stream.n += n b.n += n
nn += n nn += n
return nn, nil return nn, nil
} }
// WriteByte writes a single byte. // WriteByte writes a single byte.
func (stream *Stream) writeByte(c byte) { func (b *Stream) writeByte(c byte) {
if stream.Error != nil { if b.Error != nil {
return return
} }
if stream.Available() < 1 { if b.Available() < 1 {
stream.growAtLeast(1) b.growAtLeast(1)
} }
stream.buf[stream.n] = c b.buf[b.n] = c
stream.n++ b.n++
} }
func (stream *Stream) writeTwoBytes(c1 byte, c2 byte) { func (b *Stream) writeTwoBytes(c1 byte, c2 byte) {
if stream.Error != nil { if b.Error != nil {
return return
} }
if stream.Available() < 2 { if b.Available() < 2 {
stream.growAtLeast(2) b.growAtLeast(2)
} }
stream.buf[stream.n] = c1 b.buf[b.n] = c1
stream.buf[stream.n+1] = c2 b.buf[b.n+1] = c2
stream.n += 2 b.n += 2
} }
func (stream *Stream) writeThreeBytes(c1 byte, c2 byte, c3 byte) { func (b *Stream) writeThreeBytes(c1 byte, c2 byte, c3 byte) {
if stream.Error != nil { if b.Error != nil {
return return
} }
if stream.Available() < 3 { if b.Available() < 3 {
stream.growAtLeast(3) b.growAtLeast(3)
} }
stream.buf[stream.n] = c1 b.buf[b.n] = c1
stream.buf[stream.n+1] = c2 b.buf[b.n+1] = c2
stream.buf[stream.n+2] = c3 b.buf[b.n+2] = c3
stream.n += 3 b.n += 3
} }
func (stream *Stream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) { func (b *Stream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) {
if stream.Error != nil { if b.Error != nil {
return return
} }
if stream.Available() < 4 { if b.Available() < 4 {
stream.growAtLeast(4) b.growAtLeast(4)
} }
stream.buf[stream.n] = c1 b.buf[b.n] = c1
stream.buf[stream.n+1] = c2 b.buf[b.n+1] = c2
stream.buf[stream.n+2] = c3 b.buf[b.n+2] = c3
stream.buf[stream.n+3] = c4 b.buf[b.n+3] = c4
stream.n += 4 b.n += 4
} }
func (stream *Stream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) { func (b *Stream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) {
if stream.Error != nil { if b.Error != nil {
return return
} }
if stream.Available() < 5 { if b.Available() < 5 {
stream.growAtLeast(5) b.growAtLeast(5)
} }
stream.buf[stream.n] = c1 b.buf[b.n] = c1
stream.buf[stream.n+1] = c2 b.buf[b.n+1] = c2
stream.buf[stream.n+2] = c3 b.buf[b.n+2] = c3
stream.buf[stream.n+3] = c4 b.buf[b.n+3] = c4
stream.buf[stream.n+4] = c5 b.buf[b.n+4] = c5
stream.n += 5 b.n += 5
} }
// Flush writes any buffered data to the underlying io.Writer. // Flush writes any buffered data to the underlying io.Writer.
func (stream *Stream) Flush() error { func (b *Stream) Flush() error {
if stream.out == nil { if b.out == nil {
return nil return nil
} }
if stream.Error != nil { if b.Error != nil {
return stream.Error return b.Error
} }
if stream.n == 0 { if b.n == 0 {
return nil return nil
} }
n, err := stream.out.Write(stream.buf[0:stream.n]) n, err := b.out.Write(b.buf[0:b.n])
if n < stream.n && err == nil { if n < b.n && err == nil {
err = io.ErrShortWrite err = io.ErrShortWrite
} }
if err != nil { if err != nil {
if n > 0 && n < stream.n { if n > 0 && n < b.n {
copy(stream.buf[0:stream.n-n], stream.buf[n:stream.n]) copy(b.buf[0:b.n-n], b.buf[n:b.n])
} }
stream.n -= n b.n -= n
stream.Error = err b.Error = err
return err return err
} }
stream.n = 0 b.n = 0
return nil return nil
} }
func (stream *Stream) ensure(minimal int) { func (b *Stream) ensure(minimal int) {
available := stream.Available() available := b.Available()
if available < minimal { if available < minimal {
stream.growAtLeast(minimal) if b.n > 1024 {
b.Flush()
}
b.growAtLeast(minimal)
} }
} }
func (stream *Stream) growAtLeast(minimal int) { func (b *Stream) growAtLeast(minimal int) {
if stream.out != nil { toGrow := len(b.buf)
stream.Flush()
}
toGrow := len(stream.buf)
if toGrow < minimal { if toGrow < minimal {
toGrow = minimal toGrow = minimal
} }
newBuf := make([]byte, len(stream.buf)+toGrow) newBuf := make([]byte, len(b.buf)+toGrow)
copy(newBuf, stream.Buffer()) copy(newBuf, b.Buffer())
stream.buf = newBuf b.buf = newBuf
} }
// WriteRaw write string out without quotes, just like []byte func (b *Stream) WriteRaw(s string) {
func (stream *Stream) WriteRaw(s string) { b.ensure(len(s))
stream.ensure(len(s)) if b.Error != nil {
if stream.Error != nil {
return return
} }
n := copy(stream.buf[stream.n:], s) n := copy(b.buf[b.n:], s)
stream.n += n b.n += n
}
func (stream *Stream) WriteString(s string) {
stream.ensure(32)
valLen := len(s)
toWriteLen := valLen
bufLengthMinusTwo := len(stream.buf) - 2 // make room for the quotes
if stream.n+toWriteLen > bufLengthMinusTwo {
toWriteLen = bufLengthMinusTwo - stream.n
}
n := stream.n
stream.buf[n] = '"'
n++
// write string, the fast path, without utf8 and escape support
i := 0
for ; i < toWriteLen; i++ {
c := s[i]
if c > 31 && c != '"' && c != '\\' {
stream.buf[n] = c
n++
} else {
break
}
}
if i == valLen {
stream.buf[n] = '"'
n++
stream.n = n
return
}
stream.n = n
// for the remaining parts, we process them char by char
stream.writeStringSlowPath(s, i, valLen)
stream.writeByte('"')
}
func (stream *Stream) writeStringSlowPath(s string, i int, valLen int) {
for ; i < valLen; i++ {
c := s[i]
switch c {
case '"':
stream.writeTwoBytes('\\', '"')
case '\\':
stream.writeTwoBytes('\\', '\\')
case '\b':
stream.writeTwoBytes('\\', 'b')
case '\f':
stream.writeTwoBytes('\\', 'f')
case '\n':
stream.writeTwoBytes('\\', 'n')
case '\r':
stream.writeTwoBytes('\\', 'r')
case '\t':
stream.writeTwoBytes('\\', 't')
default:
stream.writeByte(c)
}
}
} }
// WriteNil write null to stream
func (stream *Stream) WriteNil() { func (stream *Stream) WriteNil() {
stream.writeFourBytes('n', 'u', 'l', 'l') stream.writeFourBytes('n', 'u', 'l', 'l')
} }
// WriteTrue write true to stream
func (stream *Stream) WriteTrue() { func (stream *Stream) WriteTrue() {
stream.writeFourBytes('t', 'r', 'u', 'e') stream.writeFourBytes('t', 'r', 'u', 'e')
} }
// WriteFalse write false to stream
func (stream *Stream) WriteFalse() { func (stream *Stream) WriteFalse() {
stream.writeFiveBytes('f', 'a', 'l', 's', 'e') stream.writeFiveBytes('f', 'a', 'l', 's', 'e')
} }
// WriteBool write true or false into stream
func (stream *Stream) WriteBool(val bool) { func (stream *Stream) WriteBool(val bool) {
if val { if val {
stream.WriteTrue() stream.WriteTrue()
@ -235,59 +268,47 @@ func (stream *Stream) WriteBool(val bool) {
} }
} }
// WriteObjectStart write { with possible indention
func (stream *Stream) WriteObjectStart() { func (stream *Stream) WriteObjectStart() {
stream.indention += stream.cfg.indentionStep stream.indention += stream.IndentionStep
stream.writeByte('{') stream.writeByte('{')
stream.writeIndention(0) stream.writeIndention(0)
} }
// WriteObjectField write "field": with possible indention
func (stream *Stream) WriteObjectField(field string) { func (stream *Stream) WriteObjectField(field string) {
stream.WriteString(field) stream.WriteString(field)
if stream.indention > 0 { stream.writeByte(':')
stream.writeTwoBytes(':', ' ')
} else {
stream.writeByte(':')
}
} }
// WriteObjectEnd write } with possible indention
func (stream *Stream) WriteObjectEnd() { func (stream *Stream) WriteObjectEnd() {
stream.writeIndention(stream.cfg.indentionStep) stream.writeIndention(stream.IndentionStep)
stream.indention -= stream.cfg.indentionStep stream.indention -= stream.IndentionStep
stream.writeByte('}') stream.writeByte('}')
} }
// WriteEmptyObject write {}
func (stream *Stream) WriteEmptyObject() { func (stream *Stream) WriteEmptyObject() {
stream.writeByte('{') stream.writeByte('{')
stream.writeByte('}') stream.writeByte('}')
} }
// WriteMore write , with possible indention
func (stream *Stream) WriteMore() { func (stream *Stream) WriteMore() {
stream.writeByte(',') stream.writeByte(',')
stream.writeIndention(0) stream.writeIndention(0)
} }
// WriteArrayStart write [ with possible indention
func (stream *Stream) WriteArrayStart() { func (stream *Stream) WriteArrayStart() {
stream.indention += stream.cfg.indentionStep stream.indention += stream.IndentionStep
stream.writeByte('[') stream.writeByte('[')
stream.writeIndention(0) stream.writeIndention(0)
} }
// WriteEmptyArray write []
func (stream *Stream) WriteEmptyArray() { func (stream *Stream) WriteEmptyArray() {
stream.writeByte('[') stream.writeByte('[')
stream.writeByte(']') stream.writeByte(']')
} }
// WriteArrayEnd write ] with possible indention
func (stream *Stream) WriteArrayEnd() { func (stream *Stream) WriteArrayEnd() {
stream.writeIndention(stream.cfg.indentionStep) stream.writeIndention(stream.IndentionStep)
stream.indention -= stream.cfg.indentionStep stream.indention -= stream.IndentionStep
stream.writeByte(']') stream.writeByte(']')
} }

View File

@ -1,37 +1,27 @@
package jsoniter package jsoniter
import ( import (
"math"
"strconv" "strconv"
"unsafe"
) )
var pow10 []uint64 var POW10 []uint64
func init() { func init() {
pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000} POW10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000}
} }
// WriteFloat32 write float32 to stream
func (stream *Stream) WriteFloat32(val float32) { func (stream *Stream) WriteFloat32(val float32) {
abs := math.Abs(float64(val)) stream.WriteRaw(strconv.FormatFloat(float64(val), 'f', -1, 32))
fmt := byte('f')
// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
if abs != 0 {
if float32(abs) < 1e-6 || float32(abs) >= 1e21 {
fmt = 'e'
}
}
stream.WriteRaw(strconv.FormatFloat(float64(val), fmt, -1, 32))
} }
// WriteFloat32Lossy write float32 to stream with ONLY 6 digits precision although much much faster
func (stream *Stream) WriteFloat32Lossy(val float32) { func (stream *Stream) WriteFloat32Lossy(val float32) {
if val < 0 { if val < 0 {
stream.writeByte('-') stream.writeByte('-')
val = -val val = -val
} }
if val > 0x4ffffff { if val > 0x4ffffff {
stream.WriteFloat32(val) stream.WriteRaw(strconv.FormatFloat(float64(val), 'f', -1, 32))
return return
} }
precision := 6 precision := 6
@ -44,7 +34,7 @@ func (stream *Stream) WriteFloat32Lossy(val float32) {
} }
stream.writeByte('.') stream.writeByte('.')
stream.ensure(10) stream.ensure(10)
for p := precision - 1; p > 0 && fval < pow10[p]; p-- { for p := precision - 1; p > 0 && fval < POW10[p]; p-- {
stream.writeByte('0') stream.writeByte('0')
} }
stream.WriteUint64(fval) stream.WriteUint64(fval)
@ -53,27 +43,17 @@ func (stream *Stream) WriteFloat32Lossy(val float32) {
} }
} }
// WriteFloat64 write float64 to stream
func (stream *Stream) WriteFloat64(val float64) { func (stream *Stream) WriteFloat64(val float64) {
abs := math.Abs(val) stream.WriteRaw(strconv.FormatFloat(float64(val), 'f', -1, 64))
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'
}
}
stream.WriteRaw(strconv.FormatFloat(float64(val), fmt, -1, 64))
} }
// WriteFloat64Lossy write float64 to stream with ONLY 6 digits precision although much much faster
func (stream *Stream) WriteFloat64Lossy(val float64) { func (stream *Stream) WriteFloat64Lossy(val float64) {
if val < 0 { if val < 0 {
stream.writeByte('-') stream.writeByte('-')
val = -val val = -val
} }
if val > 0x4ffffff { if val > 0x4ffffff {
stream.WriteFloat64(val) stream.WriteRaw(strconv.FormatFloat(val, 'f', -1, 64))
return return
} }
precision := 6 precision := 6
@ -86,7 +66,7 @@ func (stream *Stream) WriteFloat64Lossy(val float64) {
} }
stream.writeByte('.') stream.writeByte('.')
stream.ensure(10) stream.ensure(10)
for p := precision - 1; p > 0 && fval < pow10[p]; p-- { for p := precision - 1; p > 0 && fval < POW10[p]; p-- {
stream.writeByte('0') stream.writeByte('0')
} }
stream.WriteUint64(fval) stream.WriteUint64(fval)
@ -94,3 +74,17 @@ func (stream *Stream) WriteFloat64Lossy(val float64) {
stream.n-- stream.n--
} }
} }
// EnableLossyFloatMarshalling keeps 10**(-6) precision
// for float variables for better performance.
func EnableLossyFloatMarshalling() {
// for better performance
RegisterTypeEncoder("float32", func(ptr unsafe.Pointer, stream *Stream) {
val := *((*float32)(ptr))
stream.WriteFloat32Lossy(val)
})
RegisterTypeEncoder("float64", func(ptr unsafe.Pointer, stream *Stream) {
val := *((*float64)(ptr))
stream.WriteFloat64Lossy(val)
})
}

View File

@ -1,15 +1,15 @@
package jsoniter package jsoniter
var digits []uint32 var DIGITS []uint32
func init() { func init() {
digits = make([]uint32, 1000) DIGITS = make([]uint32, 1000)
for i := uint32(0); i < 1000; i++ { for i := uint32(0); i < 1000; i++ {
digits[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i%10 + '0' DIGITS[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i%10 + '0'
if i < 10 { if i < 10 {
digits[i] += 2 << 24 DIGITS[i] += 2 << 24
} else if i < 100 { } else if i < 100 {
digits[i] += 1 << 24 DIGITS[i] += 1 << 24
} }
} }
} }
@ -36,13 +36,11 @@ func writeBuf(buf []byte, v uint32, n int) {
buf[n+2] = byte(v) buf[n+2] = byte(v)
} }
// WriteUint8 write uint8 to stream
func (stream *Stream) WriteUint8(val uint8) { func (stream *Stream) WriteUint8(val uint8) {
stream.ensure(3) stream.ensure(3)
stream.n = writeFirstBuf(stream.buf, digits[val], stream.n) stream.n = writeFirstBuf(stream.buf, DIGITS[val], stream.n)
} }
// WriteInt8 write int8 to stream
func (stream *Stream) WriteInt8(nval int8) { func (stream *Stream) WriteInt8(nval int8) {
stream.ensure(4) stream.ensure(4)
n := stream.n n := stream.n
@ -54,25 +52,23 @@ func (stream *Stream) WriteInt8(nval int8) {
} else { } else {
val = uint8(nval) val = uint8(nval)
} }
stream.n = writeFirstBuf(stream.buf, digits[val], n) stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
} }
// WriteUint16 write uint16 to stream
func (stream *Stream) WriteUint16(val uint16) { func (stream *Stream) WriteUint16(val uint16) {
stream.ensure(5) stream.ensure(5)
q1 := val / 1000 q1 := val / 1000
if q1 == 0 { if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, digits[val], stream.n) stream.n = writeFirstBuf(stream.buf, DIGITS[val], stream.n)
return return
} }
r1 := val - q1*1000 r1 := val - q1*1000
n := writeFirstBuf(stream.buf, digits[q1], stream.n) n := writeFirstBuf(stream.buf, DIGITS[q1], stream.n)
writeBuf(stream.buf, digits[r1], n) writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3 stream.n = n + 3
return return
} }
// WriteInt16 write int16 to stream
func (stream *Stream) WriteInt16(nval int16) { func (stream *Stream) WriteInt16(nval int16) {
stream.ensure(6) stream.ensure(6)
n := stream.n n := stream.n
@ -86,50 +82,48 @@ func (stream *Stream) WriteInt16(nval int16) {
} }
q1 := val / 1000 q1 := val / 1000
if q1 == 0 { if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, digits[val], n) stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
return return
} }
r1 := val - q1*1000 r1 := val - q1*1000
n = writeFirstBuf(stream.buf, digits[q1], n) n = writeFirstBuf(stream.buf, DIGITS[q1], n)
writeBuf(stream.buf, digits[r1], n) writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3 stream.n = n + 3
return return
} }
// WriteUint32 write uint32 to stream
func (stream *Stream) WriteUint32(val uint32) { func (stream *Stream) WriteUint32(val uint32) {
stream.ensure(10) stream.ensure(10)
n := stream.n n := stream.n
q1 := val / 1000 q1 := val / 1000
if q1 == 0 { if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, digits[val], n) stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
return return
} }
r1 := val - q1*1000 r1 := val - q1*1000
q2 := q1 / 1000 q2 := q1 / 1000
if q2 == 0 { if q2 == 0 {
n := writeFirstBuf(stream.buf, digits[q1], n) n := writeFirstBuf(stream.buf, DIGITS[q1], n)
writeBuf(stream.buf, digits[r1], n) writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3 stream.n = n + 3
return return
} }
r2 := q1 - q2*1000 r2 := q1 - q2*1000
q3 := q2 / 1000 q3 := q2 / 1000
if q3 == 0 { if q3 == 0 {
n = writeFirstBuf(stream.buf, digits[q2], n) n = writeFirstBuf(stream.buf, DIGITS[q2], n)
} else { } else {
r3 := q2 - q3*1000 r3 := q2 - q3*1000
stream.buf[n] = byte(q3 + '0') stream.buf[n] = byte(q3 + '0')
n++ n++
writeBuf(stream.buf, digits[r3], n) writeBuf(stream.buf, DIGITS[r3], n)
n += 3 n += 3
} }
writeBuf(stream.buf, digits[r2], n) writeBuf(stream.buf, DIGITS[r2], n)
writeBuf(stream.buf, digits[r1], n+3) writeBuf(stream.buf, DIGITS[r1], n+3)
stream.n = n + 6 stream.n = n + 6
} }
// WriteInt32 write int32 to stream
func (stream *Stream) WriteInt32(nval int32) { func (stream *Stream) WriteInt32(nval int32) {
stream.ensure(11) stream.ensure(11)
n := stream.n n := stream.n
@ -143,99 +137,97 @@ func (stream *Stream) WriteInt32(nval int32) {
} }
q1 := val / 1000 q1 := val / 1000
if q1 == 0 { if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, digits[val], n) stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
return return
} }
r1 := val - q1*1000 r1 := val - q1*1000
q2 := q1 / 1000 q2 := q1 / 1000
if q2 == 0 { if q2 == 0 {
n := writeFirstBuf(stream.buf, digits[q1], n) n := writeFirstBuf(stream.buf, DIGITS[q1], n)
writeBuf(stream.buf, digits[r1], n) writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3 stream.n = n + 3
return return
} }
r2 := q1 - q2*1000 r2 := q1 - q2*1000
q3 := q2 / 1000 q3 := q2 / 1000
if q3 == 0 { if q3 == 0 {
n = writeFirstBuf(stream.buf, digits[q2], n) n = writeFirstBuf(stream.buf, DIGITS[q2], n)
} else { } else {
r3 := q2 - q3*1000 r3 := q2 - q3*1000
stream.buf[n] = byte(q3 + '0') stream.buf[n] = byte(q3 + '0')
n++ n++
writeBuf(stream.buf, digits[r3], n) writeBuf(stream.buf, DIGITS[r3], n)
n += 3 n += 3
} }
writeBuf(stream.buf, digits[r2], n) writeBuf(stream.buf, DIGITS[r2], n)
writeBuf(stream.buf, digits[r1], n+3) writeBuf(stream.buf, DIGITS[r1], n+3)
stream.n = n + 6 stream.n = n + 6
} }
// WriteUint64 write uint64 to stream
func (stream *Stream) WriteUint64(val uint64) { func (stream *Stream) WriteUint64(val uint64) {
stream.ensure(20) stream.ensure(20)
n := stream.n n := stream.n
q1 := val / 1000 q1 := val / 1000
if q1 == 0 { if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, digits[val], n) stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
return return
} }
r1 := val - q1*1000 r1 := val - q1*1000
q2 := q1 / 1000 q2 := q1 / 1000
if q2 == 0 { if q2 == 0 {
n := writeFirstBuf(stream.buf, digits[q1], n) n := writeFirstBuf(stream.buf, DIGITS[q1], n)
writeBuf(stream.buf, digits[r1], n) writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3 stream.n = n + 3
return return
} }
r2 := q1 - q2*1000 r2 := q1 - q2*1000
q3 := q2 / 1000 q3 := q2 / 1000
if q3 == 0 { if q3 == 0 {
n = writeFirstBuf(stream.buf, digits[q2], n) n = writeFirstBuf(stream.buf, DIGITS[q2], n)
writeBuf(stream.buf, digits[r2], n) writeBuf(stream.buf, DIGITS[r2], n)
writeBuf(stream.buf, digits[r1], n+3) writeBuf(stream.buf, DIGITS[r1], n+3)
stream.n = n + 6 stream.n = n + 6
return return
} }
r3 := q2 - q3*1000 r3 := q2 - q3*1000
q4 := q3 / 1000 q4 := q3 / 1000
if q4 == 0 { if q4 == 0 {
n = writeFirstBuf(stream.buf, digits[q3], n) n = writeFirstBuf(stream.buf, DIGITS[q3], n)
writeBuf(stream.buf, digits[r3], n) writeBuf(stream.buf, DIGITS[r3], n)
writeBuf(stream.buf, digits[r2], n+3) writeBuf(stream.buf, DIGITS[r2], n+3)
writeBuf(stream.buf, digits[r1], n+6) writeBuf(stream.buf, DIGITS[r1], n+6)
stream.n = n + 9 stream.n = n + 9
return return
} }
r4 := q3 - q4*1000 r4 := q3 - q4*1000
q5 := q4 / 1000 q5 := q4 / 1000
if q5 == 0 { if q5 == 0 {
n = writeFirstBuf(stream.buf, digits[q4], n) n = writeFirstBuf(stream.buf, DIGITS[q4], n)
writeBuf(stream.buf, digits[r4], n) writeBuf(stream.buf, DIGITS[r4], n)
writeBuf(stream.buf, digits[r3], n+3) writeBuf(stream.buf, DIGITS[r3], n+3)
writeBuf(stream.buf, digits[r2], n+6) writeBuf(stream.buf, DIGITS[r2], n+6)
writeBuf(stream.buf, digits[r1], n+9) writeBuf(stream.buf, DIGITS[r1], n+9)
stream.n = n + 12 stream.n = n + 12
return return
} }
r5 := q4 - q5*1000 r5 := q4 - q5*1000
q6 := q5 / 1000 q6 := q5 / 1000
if q6 == 0 { if q6 == 0 {
n = writeFirstBuf(stream.buf, digits[q5], n) n = writeFirstBuf(stream.buf, DIGITS[q5], n)
} else { } else {
n = writeFirstBuf(stream.buf, digits[q6], n) n = writeFirstBuf(stream.buf, DIGITS[q6], n)
r6 := q5 - q6*1000 r6 := q5 - q6*1000
writeBuf(stream.buf, digits[r6], n) writeBuf(stream.buf, DIGITS[r6], n)
n += 3 n += 3
} }
writeBuf(stream.buf, digits[r5], n) writeBuf(stream.buf, DIGITS[r5], n)
writeBuf(stream.buf, digits[r4], n+3) writeBuf(stream.buf, DIGITS[r4], n+3)
writeBuf(stream.buf, digits[r3], n+6) writeBuf(stream.buf, DIGITS[r3], n+6)
writeBuf(stream.buf, digits[r2], n+9) writeBuf(stream.buf, DIGITS[r2], n+9)
writeBuf(stream.buf, digits[r1], n+12) writeBuf(stream.buf, DIGITS[r1], n+12)
stream.n = n + 15 stream.n = n + 15
} }
// WriteInt64 write int64 to stream
func (stream *Stream) WriteInt64(nval int64) { func (stream *Stream) WriteInt64(nval int64) {
stream.ensure(20) stream.ensure(20)
n := stream.n n := stream.n
@ -249,72 +241,70 @@ func (stream *Stream) WriteInt64(nval int64) {
} }
q1 := val / 1000 q1 := val / 1000
if q1 == 0 { if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, digits[val], n) stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
return return
} }
r1 := val - q1*1000 r1 := val - q1*1000
q2 := q1 / 1000 q2 := q1 / 1000
if q2 == 0 { if q2 == 0 {
n := writeFirstBuf(stream.buf, digits[q1], n) n := writeFirstBuf(stream.buf, DIGITS[q1], n)
writeBuf(stream.buf, digits[r1], n) writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3 stream.n = n + 3
return return
} }
r2 := q1 - q2*1000 r2 := q1 - q2*1000
q3 := q2 / 1000 q3 := q2 / 1000
if q3 == 0 { if q3 == 0 {
n = writeFirstBuf(stream.buf, digits[q2], n) n = writeFirstBuf(stream.buf, DIGITS[q2], n)
writeBuf(stream.buf, digits[r2], n) writeBuf(stream.buf, DIGITS[r2], n)
writeBuf(stream.buf, digits[r1], n+3) writeBuf(stream.buf, DIGITS[r1], n+3)
stream.n = n + 6 stream.n = n + 6
return return
} }
r3 := q2 - q3*1000 r3 := q2 - q3*1000
q4 := q3 / 1000 q4 := q3 / 1000
if q4 == 0 { if q4 == 0 {
n = writeFirstBuf(stream.buf, digits[q3], n) n = writeFirstBuf(stream.buf, DIGITS[q3], n)
writeBuf(stream.buf, digits[r3], n) writeBuf(stream.buf, DIGITS[r3], n)
writeBuf(stream.buf, digits[r2], n+3) writeBuf(stream.buf, DIGITS[r2], n+3)
writeBuf(stream.buf, digits[r1], n+6) writeBuf(stream.buf, DIGITS[r1], n+6)
stream.n = n + 9 stream.n = n + 9
return return
} }
r4 := q3 - q4*1000 r4 := q3 - q4*1000
q5 := q4 / 1000 q5 := q4 / 1000
if q5 == 0 { if q5 == 0 {
n = writeFirstBuf(stream.buf, digits[q4], n) n = writeFirstBuf(stream.buf, DIGITS[q4], n)
writeBuf(stream.buf, digits[r4], n) writeBuf(stream.buf, DIGITS[r4], n)
writeBuf(stream.buf, digits[r3], n+3) writeBuf(stream.buf, DIGITS[r3], n+3)
writeBuf(stream.buf, digits[r2], n+6) writeBuf(stream.buf, DIGITS[r2], n+6)
writeBuf(stream.buf, digits[r1], n+9) writeBuf(stream.buf, DIGITS[r1], n+9)
stream.n = n + 12 stream.n = n + 12
return return
} }
r5 := q4 - q5*1000 r5 := q4 - q5*1000
q6 := q5 / 1000 q6 := q5 / 1000
if q6 == 0 { if q6 == 0 {
n = writeFirstBuf(stream.buf, digits[q5], n) n = writeFirstBuf(stream.buf, DIGITS[q5], n)
} else { } else {
stream.buf[n] = byte(q6 + '0') stream.buf[n] = byte(q6 + '0')
n++ n++
r6 := q5 - q6*1000 r6 := q5 - q6*1000
writeBuf(stream.buf, digits[r6], n) writeBuf(stream.buf, DIGITS[r6], n)
n += 3 n += 3
} }
writeBuf(stream.buf, digits[r5], n) writeBuf(stream.buf, DIGITS[r5], n)
writeBuf(stream.buf, digits[r4], n+3) writeBuf(stream.buf, DIGITS[r4], n+3)
writeBuf(stream.buf, digits[r3], n+6) writeBuf(stream.buf, DIGITS[r3], n+6)
writeBuf(stream.buf, digits[r2], n+9) writeBuf(stream.buf, DIGITS[r2], n+9)
writeBuf(stream.buf, digits[r1], n+12) writeBuf(stream.buf, DIGITS[r1], n+12)
stream.n = n + 15 stream.n = n + 15
} }
// WriteInt write int to stream
func (stream *Stream) WriteInt(val int) { func (stream *Stream) WriteInt(val int) {
stream.WriteInt64(int64(val)) stream.WriteInt64(int64(val))
} }
// WriteUint write uint to stream
func (stream *Stream) WriteUint(val uint) { func (stream *Stream) WriteUint(val uint) {
stream.WriteUint64(uint64(val)) stream.WriteUint64(uint64(val))
} }

View File

@ -1,396 +0,0 @@
package jsoniter
import (
"unicode/utf8"
)
// htmlSafeSet holds the value true if the ASCII character with the given
// array position can be safely represented inside a JSON string, embedded
// inside of HTML <script> tags, without any additional escaping.
//
// All values are true except for the ASCII control characters (0-31), the
// double quote ("), the backslash character ("\"), HTML opening and closing
// tags ("<" and ">"), and the ampersand ("&").
var htmlSafeSet = [utf8.RuneSelf]bool{
' ': true,
'!': true,
'"': false,
'#': true,
'$': true,
'%': true,
'&': false,
'\'': true,
'(': true,
')': true,
'*': true,
'+': true,
',': true,
'-': true,
'.': true,
'/': true,
'0': true,
'1': true,
'2': true,
'3': true,
'4': true,
'5': true,
'6': true,
'7': true,
'8': true,
'9': true,
':': true,
';': true,
'<': false,
'=': true,
'>': false,
'?': true,
'@': true,
'A': true,
'B': true,
'C': true,
'D': true,
'E': true,
'F': true,
'G': true,
'H': true,
'I': true,
'J': true,
'K': true,
'L': true,
'M': true,
'N': true,
'O': true,
'P': true,
'Q': true,
'R': true,
'S': true,
'T': true,
'U': true,
'V': true,
'W': true,
'X': true,
'Y': true,
'Z': true,
'[': true,
'\\': false,
']': true,
'^': true,
'_': true,
'`': true,
'a': true,
'b': true,
'c': true,
'd': true,
'e': true,
'f': true,
'g': true,
'h': true,
'i': true,
'j': true,
'k': true,
'l': true,
'm': true,
'n': true,
'o': true,
'p': true,
'q': true,
'r': true,
's': true,
't': true,
'u': true,
'v': true,
'w': true,
'x': true,
'y': true,
'z': true,
'{': true,
'|': true,
'}': true,
'~': true,
'\u007f': true,
}
// safeSet holds the value true if the ASCII character with the given array
// position can be represented inside a JSON string without any further
// escaping.
//
// All values are true except for the ASCII control characters (0-31), the
// double quote ("), and the backslash character ("\").
var safeSet = [utf8.RuneSelf]bool{
' ': true,
'!': true,
'"': false,
'#': true,
'$': true,
'%': true,
'&': true,
'\'': true,
'(': true,
')': true,
'*': true,
'+': true,
',': true,
'-': true,
'.': true,
'/': true,
'0': true,
'1': true,
'2': true,
'3': true,
'4': true,
'5': true,
'6': true,
'7': true,
'8': true,
'9': true,
':': true,
';': true,
'<': true,
'=': true,
'>': true,
'?': true,
'@': true,
'A': true,
'B': true,
'C': true,
'D': true,
'E': true,
'F': true,
'G': true,
'H': true,
'I': true,
'J': true,
'K': true,
'L': true,
'M': true,
'N': true,
'O': true,
'P': true,
'Q': true,
'R': true,
'S': true,
'T': true,
'U': true,
'V': true,
'W': true,
'X': true,
'Y': true,
'Z': true,
'[': true,
'\\': false,
']': true,
'^': true,
'_': true,
'`': true,
'a': true,
'b': true,
'c': true,
'd': true,
'e': true,
'f': true,
'g': true,
'h': true,
'i': true,
'j': true,
'k': true,
'l': true,
'm': true,
'n': true,
'o': true,
'p': true,
'q': true,
'r': true,
's': true,
't': true,
'u': true,
'v': true,
'w': true,
'x': true,
'y': true,
'z': true,
'{': true,
'|': true,
'}': true,
'~': true,
'\u007f': true,
}
var hex = "0123456789abcdef"
// WriteStringWithHTMLEscaped write string to stream with html special characters escaped
func (stream *Stream) WriteStringWithHTMLEscaped(s string) {
stream.ensure(32)
valLen := len(s)
toWriteLen := valLen
bufLengthMinusTwo := len(stream.buf) - 2 // make room for the quotes
if stream.n+toWriteLen > bufLengthMinusTwo {
toWriteLen = bufLengthMinusTwo - stream.n
}
n := stream.n
stream.buf[n] = '"'
n++
// write string, the fast path, without utf8 and escape support
i := 0
for ; i < toWriteLen; i++ {
c := s[i]
if c < utf8.RuneSelf && htmlSafeSet[c] {
stream.buf[n] = c
n++
} else {
break
}
}
if i == valLen {
stream.buf[n] = '"'
n++
stream.n = n
return
}
stream.n = n
writeStringSlowPathWithHTMLEscaped(stream, i, s, valLen)
}
func writeStringSlowPathWithHTMLEscaped(stream *Stream, i int, s string, valLen int) {
start := i
// for the remaining parts, we process them char by char
for i < valLen {
if b := s[i]; b < utf8.RuneSelf {
if htmlSafeSet[b] {
i++
continue
}
if start < i {
stream.WriteRaw(s[start:i])
}
switch b {
case '\\', '"':
stream.writeTwoBytes('\\', b)
case '\n':
stream.writeTwoBytes('\\', 'n')
case '\r':
stream.writeTwoBytes('\\', 'r')
case '\t':
stream.writeTwoBytes('\\', 't')
default:
// This encodes bytes < 0x20 except for \t, \n and \r.
// If escapeHTML is set, it also escapes <, >, and &
// because they can lead to security holes when
// user-controlled strings are rendered into JSON
// and served to some browsers.
stream.WriteRaw(`\u00`)
stream.writeTwoBytes(hex[b>>4], hex[b&0xF])
}
i++
start = i
continue
}
c, size := utf8.DecodeRuneInString(s[i:])
if c == utf8.RuneError && size == 1 {
if start < i {
stream.WriteRaw(s[start:i])
}
stream.WriteRaw(`\ufffd`)
i++
start = i
continue
}
// 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.
if c == '\u2028' || c == '\u2029' {
if start < i {
stream.WriteRaw(s[start:i])
}
stream.WriteRaw(`\u202`)
stream.writeByte(hex[c&0xF])
i += size
start = i
continue
}
i += size
}
if start < len(s) {
stream.WriteRaw(s[start:])
}
stream.writeByte('"')
}
// WriteString write string to stream without html escape
func (stream *Stream) WriteString(s string) {
stream.ensure(32)
valLen := len(s)
toWriteLen := valLen
bufLengthMinusTwo := len(stream.buf) - 2 // make room for the quotes
if stream.n+toWriteLen > bufLengthMinusTwo {
toWriteLen = bufLengthMinusTwo - stream.n
}
n := stream.n
stream.buf[n] = '"'
n++
// write string, the fast path, without utf8 and escape support
i := 0
for ; i < toWriteLen; i++ {
c := s[i]
if c > 31 && c != '"' && c != '\\' {
stream.buf[n] = c
n++
} else {
break
}
}
if i == valLen {
stream.buf[n] = '"'
n++
stream.n = n
return
}
stream.n = n
writeStringSlowPath(stream, i, s, valLen)
}
func writeStringSlowPath(stream *Stream, i int, s string, valLen int) {
start := i
// for the remaining parts, we process them char by char
for i < valLen {
if b := s[i]; b < utf8.RuneSelf {
if safeSet[b] {
i++
continue
}
if start < i {
stream.WriteRaw(s[start:i])
}
switch b {
case '\\', '"':
stream.writeTwoBytes('\\', b)
case '\n':
stream.writeTwoBytes('\\', 'n')
case '\r':
stream.writeTwoBytes('\\', 'r')
case '\t':
stream.writeTwoBytes('\\', 't')
default:
// This encodes bytes < 0x20 except for \t, \n and \r.
// If escapeHTML is set, it also escapes <, >, and &
// because they can lead to security holes when
// user-controlled strings are rendered into JSON
// and served to some browsers.
stream.WriteRaw(`\u00`)
stream.writeTwoBytes(hex[b>>4], hex[b&0xF])
}
i++
start = i
continue
}
i++
continue
}
if start < len(s) {
stream.WriteRaw(s[start:])
}
stream.writeByte('"')
}

View File

@ -1,7 +0,0 @@
| json type \ dest type | bool | int | uint | float |string|
| --- | --- | --- | --- |--|--|
| number | positive => true <br/> negative => true <br/> zero => false| 23.2 => 23 <br/> -32.1 => -32| 12.1 => 12 <br/> -12.1 => 0|as normal|same as origin|
| string | empty string => false <br/> string "0" => false <br/> other strings => true | "123.32" => 123 <br/> "-123.4" => -123 <br/> "123.23xxxw" => 123 <br/> "abcde12" => 0 <br/> "-32.1" => -32| 13.2 => 13 <br/> -1.1 => 0 |12.1 => 12.1 <br/> -12.3 => -12.3<br/> 12.4xxa => 12.4 <br/> +1.1e2 =>110 |same as origin|
| bool | true => true <br/> false => false| true => 1 <br/> false => 0 | true => 1 <br/> false => 0 |true => 1 <br/>false => 0|true => "true" <br/> false => "false"|
| object | true | 0 | 0 |0|originnal json|
| array | empty array => false <br/> nonempty array => true| [] => 0 <br/> [1,2] => 1 | [] => 0 <br/> [1,2] => 1 |[] => 0<br/>[1,2] => 1|original json|

View File

@ -1,18 +0,0 @@
// Package jsoniter implements encoding and decoding of JSON as defined in
// RFC 4627 and provides interfaces with identical syntax of standard lib encoding/json.
// Converting from encoding/json to jsoniter is no more than replacing the package with jsoniter
// and variable type declarations (if any).
// jsoniter interfaces gives 100% compatibility with code using standard lib.
//
// "JSON and Go"
// (https://golang.org/doc/articles/json_and_go.html)
// gives a description of how Marshal/Unmarshal operate
// between arbitrary or predefined json objects and bytes,
// and it applies to jsoniter.Marshal/Unmarshal as well.
//
// Besides, jsoniter.Iterator provides a different set of interfaces
// iterating given bytes/string/reader
// and yielding parsed elements one by one.
// This set of interfaces reads input as required and gives
// better performance.
package jsoniter

View File

@ -1,45 +0,0 @@
// +build go1.8
package jsoniter
import (
"bytes"
"encoding/json"
"testing"
"unicode/utf8"
"github.com/stretchr/testify/require"
)
func Test_new_encoder(t *testing.T) {
should := require.New(t)
buf1 := &bytes.Buffer{}
encoder1 := json.NewEncoder(buf1)
encoder1.SetEscapeHTML(false)
encoder1.Encode([]int{1})
should.Equal("[1]\n", buf1.String())
buf2 := &bytes.Buffer{}
encoder2 := NewEncoder(buf2)
encoder2.SetEscapeHTML(false)
encoder2.Encode([]int{1})
should.Equal("[1]", buf2.String())
}
func Test_string_encode_with_std_without_html_escape(t *testing.T) {
api := Config{EscapeHTML: false}.Froze()
should := require.New(t)
for i := 0; i < utf8.RuneSelf; i++ {
input := string([]byte{byte(i)})
buf := &bytes.Buffer{}
encoder := json.NewEncoder(buf)
encoder.SetEscapeHTML(false)
err := encoder.Encode(input)
should.Nil(err)
stdOutput := buf.String()
stdOutput = stdOutput[:len(stdOutput)-1]
jsoniterOutputBytes, err := api.Marshal(input)
should.Nil(err)
jsoniterOutput := string(jsoniterOutputBytes)
should.Equal(stdOutput, jsoniterOutput)
}
}

View File

@ -3,7 +3,7 @@ package jsoniter
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/stretchr/testify/require" "github.com/json-iterator/go/require"
"io/ioutil" "io/ioutil"
"testing" "testing"
) )
@ -33,6 +33,18 @@ func Test_new_decoder(t *testing.T) {
should.False(decoder2.More()) should.False(decoder2.More())
} }
func Test_new_encoder(t *testing.T) {
should := require.New(t)
buf1 := &bytes.Buffer{}
encoder1 := json.NewEncoder(buf1)
encoder1.Encode([]int{1})
should.Equal("[1]\n", buf1.String())
buf2 := &bytes.Buffer{}
encoder2 := NewEncoder(buf2)
encoder2.Encode([]int{1})
should.Equal("[1]", buf2.String())
}
func Test_use_number(t *testing.T) { func Test_use_number(t *testing.T) {
should := require.New(t) should := require.New(t)
decoder1 := json.NewDecoder(bytes.NewBufferString(`123`)) decoder1 := json.NewDecoder(bytes.NewBufferString(`123`))
@ -46,39 +58,3 @@ func Test_use_number(t *testing.T) {
should.Nil(decoder2.Decode(&obj2)) should.Nil(decoder2.Decode(&obj2))
should.Equal(json.Number("123"), obj2) should.Equal(json.Number("123"), obj2)
} }
func Test_use_number_for_unmarshal(t *testing.T) {
should := require.New(t)
api := Config{UseNumber: true}.Froze()
var obj interface{}
should.Nil(api.UnmarshalFromString("123", &obj))
should.Equal(json.Number("123"), obj)
}
func Test_marshal_indent(t *testing.T) {
should := require.New(t)
obj := struct {
F1 int
F2 []int
}{1, []int{2, 3, 4}}
output, err := json.MarshalIndent(obj, "", " ")
should.Nil(err)
should.Equal("{\n \"F1\": 1,\n \"F2\": [\n 2,\n 3,\n 4\n ]\n}", string(output))
output, err = MarshalIndent(obj, "", " ")
should.Nil(err)
should.Equal("{\n \"F1\": 1,\n \"F2\": [\n 2,\n 3,\n 4\n ]\n}", string(output))
}
func Test_marshal_indent_map(t *testing.T) {
should := require.New(t)
obj := map[int]int{1: 2}
output, err := json.MarshalIndent(obj, "", " ")
should.Nil(err)
should.Equal("{\n \"1\": 2\n}", string(output))
output, err = MarshalIndent(obj, "", " ")
should.Nil(err)
should.Equal("{\n \"1\": 2\n}", string(output))
output, err = ConfigCompatibleWithStandardLibrary.MarshalIndent(obj, "", " ")
should.Nil(err)
should.Equal("{\n \"1\": 2\n}", string(output))
}

View File

@ -1,62 +0,0 @@
package jsoniter
import (
"testing"
"github.com/stretchr/testify/require"
)
func Test_alias(t *testing.T) {
should := require.New(t)
type myint int
type myint8 int8
type myint16 int16
type myint32 int32
type myint64 int64
type myuint uint
type myuint8 uint8
type myuint16 uint16
type myuint32 uint32
type myuint64 uint64
type myfloat32 float32
type myfloat64 float64
type mystring string
type mybool bool
type myuintptr uintptr
var a struct {
A myint8 `json:"a"`
B myint16 `json:"stream"`
C myint32 `json:"c"`
D myint64 `json:"d"`
E myuint8 `json:"e"`
F myuint16 `json:"f"`
G myuint32 `json:"g"`
H myuint64 `json:"h"`
I myfloat32 `json:"i"`
J myfloat64 `json:"j"`
K mystring `json:"k"`
L myint `json:"l"`
M myuint `json:"m"`
N mybool `json:"n"`
O myuintptr `json:"o"`
}
should.Nil(UnmarshalFromString(`{"a" : 1, "stream" : 1, "c": 1, "d" : 1, "e" : 1, "f" : 1, "g" : 1, "h": 1, "i" : 1, "j" : 1, "k" :"xxxx", "l" : 1, "m":1, "n": true, "o" : 1}`, &a))
should.Equal(myfloat32(1), a.I)
should.Equal(myfloat64(1), a.J)
should.Equal(myint8(1), a.A)
should.Equal(myint16(1), a.B)
should.Equal(myint32(1), a.C)
should.Equal(myint64(1), a.D)
should.Equal(myuint8(1), a.E)
should.Equal(myuint16(1), a.F)
should.Equal(myuint32(1), a.G)
should.Equal(myuint64(1), a.H)
should.Equal(mystring("xxxx"), a.K)
should.Equal(mybool(true), a.N)
should.Equal(myuintptr(1), a.O)
b, err := Marshal(a)
should.Nil(err)
should.Equal(`{"a":1,"stream":1,"c":1,"d":1,"e":1,"f":1,"g":1,"h":1,"i":1,"j":1,"k":"xxxx","l":1,"m":1,"n":true,"o":1}`, string(b))
}

View File

@ -1,122 +0,0 @@
package jsoniter
import (
"testing"
"github.com/stretchr/testify/require"
)
func Test_read_empty_array_as_any(t *testing.T) {
should := require.New(t)
any := Get([]byte("[]"))
should.Equal(ArrayValue, any.Get().ValueType())
should.Equal(InvalidValue, any.Get(0.3).ValueType())
should.Equal(0, any.Size())
should.Equal(ArrayValue, any.ValueType())
should.Nil(any.LastError())
should.Equal(0, any.ToInt())
should.Equal(int32(0), any.ToInt32())
should.Equal(int64(0), any.ToInt64())
should.Equal(uint(0), any.ToUint())
should.Equal(uint32(0), any.ToUint32())
should.Equal(uint64(0), any.ToUint64())
should.Equal(float32(0), any.ToFloat32())
should.Equal(float64(0), any.ToFloat64())
}
func Test_read_one_element_array_as_any(t *testing.T) {
should := require.New(t)
any := Get([]byte("[1]"))
should.Equal(1, any.Size())
}
func Test_read_two_element_array_as_any(t *testing.T) {
should := require.New(t)
any := Get([]byte("[1,2]"))
should.Equal(1, any.Get(0).ToInt())
should.Equal(2, any.Size())
should.True(any.ToBool())
should.Equal(1, any.ToInt())
should.Equal([]interface{}{float64(1), float64(2)}, any.GetInterface())
stream := NewStream(ConfigDefault, nil, 32)
any.WriteTo(stream)
should.Equal("[1,2]", string(stream.Buffer()))
arr := []int{}
any.ToVal(&arr)
should.Equal([]int{1, 2}, arr)
}
func Test_wrap_array_and_convert_to_any(t *testing.T) {
should := require.New(t)
any := Wrap([]int{1, 2, 3})
any2 := Wrap([]int{})
should.Equal("[1,2,3]", any.ToString())
should.True(any.ToBool())
should.False(any2.ToBool())
should.Equal(1, any.ToInt())
should.Equal(0, any2.ToInt())
should.Equal(int32(1), any.ToInt32())
should.Equal(int32(0), any2.ToInt32())
should.Equal(int64(1), any.ToInt64())
should.Equal(int64(0), any2.ToInt64())
should.Equal(uint(1), any.ToUint())
should.Equal(uint(0), any2.ToUint())
should.Equal(uint32(1), any.ToUint32())
should.Equal(uint32(0), any2.ToUint32())
should.Equal(uint64(1), any.ToUint64())
should.Equal(uint64(0), any2.ToUint64())
should.Equal(float32(1), any.ToFloat32())
should.Equal(float32(0), any2.ToFloat32())
should.Equal(float64(1), any.ToFloat64())
should.Equal(float64(0), any2.ToFloat64())
should.Equal(3, any.Size())
should.Equal(0, any2.Size())
var i interface{} = []int{1, 2, 3}
should.Equal(i, any.GetInterface())
}
func Test_array_lazy_any_get(t *testing.T) {
should := require.New(t)
any := Get([]byte("[1,[2,3],4]"))
should.Equal(3, any.Get(1, 1).ToInt())
should.Equal("[1,[2,3],4]", any.ToString())
}
func Test_array_lazy_any_get_all(t *testing.T) {
should := require.New(t)
any := Get([]byte("[[1],[2],[3,4]]"))
should.Equal("[1,2,3]", any.Get('*', 0).ToString())
any = Get([]byte("[[[1],[2],[3,4]]]"), 0, '*', 0)
should.Equal("[1,2,3]", any.ToString())
}
func Test_array_wrapper_any_get_all(t *testing.T) {
should := require.New(t)
any := wrapArray([][]int{
{1, 2},
{3, 4},
{5, 6},
})
should.Equal("[1,3,5]", any.Get('*', 0).ToString())
should.Equal(ArrayValue, any.ValueType())
should.True(any.ToBool())
should.Equal(1, any.Get(0, 0).ToInt())
}
func Test_array_lazy_any_get_invalid(t *testing.T) {
should := require.New(t)
any := Get([]byte("[]"))
should.Equal(InvalidValue, any.Get(1, 1).ValueType())
should.NotNil(any.Get(1, 1).LastError())
should.Equal(InvalidValue, any.Get("1").ValueType())
should.NotNil(any.Get("1").LastError())
}
func Test_invalid_array(t *testing.T) {
should := require.New(t)
any := Get([]byte("["), 0)
should.Equal(InvalidValue, any.ValueType())
}

View File

@ -1,64 +0,0 @@
package jsoniter
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
var boolConvertMap = map[string]bool{
"null": false,
"true": true,
"false": false,
`"true"`: true,
`"false"`: true,
"123": true,
`"123"`: true,
"0": false,
`"0"`: false,
"-1": true,
`"-1"`: true,
"1.1": true,
"0.0": false,
"-1.1": true,
`""`: false,
"[1,2]": true,
"[]": false,
"{}": true,
`{"abc":1}`: true,
}
func Test_read_bool_as_any(t *testing.T) {
should := require.New(t)
var any Any
for k, v := range boolConvertMap {
any = Get([]byte(k))
if v {
should.True(any.ToBool(), fmt.Sprintf("origin val is %v", k))
} else {
should.False(any.ToBool(), fmt.Sprintf("origin val is %v", k))
}
}
}
func Test_write_bool_to_stream(t *testing.T) {
should := require.New(t)
any := Get([]byte("true"))
stream := NewStream(ConfigDefault, nil, 32)
any.WriteTo(stream)
should.Equal("true", string(stream.Buffer()))
should.Equal(any.ValueType(), BoolValue)
any = Get([]byte("false"))
stream = NewStream(ConfigDefault, nil, 32)
any.WriteTo(stream)
should.Equal("false", string(stream.Buffer()))
should.Equal(any.ValueType(), BoolValue)
}

View File

@ -1,102 +0,0 @@
package jsoniter
import (
"testing"
"github.com/stretchr/testify/require"
)
var floatConvertMap = map[string]float64{
"null": 0,
"true": 1,
"false": 0,
`"true"`: 0,
`"false"`: 0,
"1e1": 10,
"1e+1": 10,
"1e-1": .1,
"1E1": 10,
"1E+1": 10,
"1E-1": .1,
"-1e1": -10,
"-1e+1": -10,
"-1e-1": -.1,
"-1E1": -10,
"-1E+1": -10,
"-1E-1": -.1,
`"1e1"`: 10,
`"1e+1"`: 10,
`"1e-1"`: .1,
`"1E1"`: 10,
`"1E+1"`: 10,
`"1E-1"`: .1,
`"-1e1"`: -10,
`"-1e+1"`: -10,
`"-1e-1"`: -.1,
`"-1E1"`: -10,
`"-1E+1"`: -10,
`"-1E-1"`: -.1,
"123": 123,
`"123true"`: 123,
`"+"`: 0,
`"-"`: 0,
`"-123true"`: -123,
`"-99.9true"`: -99.9,
"0": 0,
`"0"`: 0,
"-1": -1,
"1.1": 1.1,
"0.0": 0,
"-1.1": -1.1,
`"+1.1"`: 1.1,
`""`: 0,
"[1,2]": 1,
"[]": 0,
"{}": 0,
`{"abc":1}`: 0,
}
func Test_read_any_to_float(t *testing.T) {
should := require.New(t)
for k, v := range floatConvertMap {
any := Get([]byte(k))
should.Equal(float64(v), any.ToFloat64(), "the original val is "+k)
}
for k, v := range floatConvertMap {
any := Get([]byte(k))
should.Equal(float32(v), any.ToFloat32(), "the original val is "+k)
}
}
func Test_read_float_to_any(t *testing.T) {
should := require.New(t)
any := WrapFloat64(12.3)
anyFloat64 := float64(12.3)
//negaAnyFloat64 := float64(-1.1)
any2 := WrapFloat64(-1.1)
should.Equal(float64(12.3), any.ToFloat64())
//should.Equal("12.3", any.ToString())
should.True(any.ToBool())
should.Equal(float32(anyFloat64), any.ToFloat32())
should.Equal(int(anyFloat64), any.ToInt())
should.Equal(int32(anyFloat64), any.ToInt32())
should.Equal(int64(anyFloat64), any.ToInt64())
should.Equal(uint(anyFloat64), any.ToUint())
should.Equal(uint32(anyFloat64), any.ToUint32())
should.Equal(uint64(anyFloat64), any.ToUint64())
should.Equal(uint(0), any2.ToUint())
should.Equal(uint32(0), any2.ToUint32())
should.Equal(uint64(0), any2.ToUint64())
should.Equal(any.ValueType(), NumberValue)
should.Equal("1.23E+01", any.ToString())
}

View File

@ -1,197 +0,0 @@
package jsoniter
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
var intConvertMap = map[string]int{
"null": 0,
"321.1": 321,
"-321.1": -321,
`"1.1"`: 1,
`"-321.1"`: -321,
"0.0": 0,
"0": 0,
`"0"`: 0,
`"0.0"`: 0,
"-1.1": -1,
"true": 1,
"false": 0,
`"true"`: 0,
`"false"`: 0,
`"true123"`: 0,
`"123true"`: 123,
`"-123true"`: -123,
`"1.2332e6"`: 1,
`""`: 0,
"+": 0,
"-": 0,
"[]": 0,
"[1,2]": 1,
`["1","2"]`: 1,
// object in php cannot convert to int
"{}": 0,
}
func Test_read_any_to_int(t *testing.T) {
should := require.New(t)
// int
for k, v := range intConvertMap {
any := Get([]byte(k))
should.Equal(v, any.ToInt(), fmt.Sprintf("origin val %v", k))
}
// int32
for k, v := range intConvertMap {
any := Get([]byte(k))
should.Equal(int32(v), any.ToInt32(), fmt.Sprintf("original val is %v", k))
}
// int64
for k, v := range intConvertMap {
any := Get([]byte(k))
should.Equal(int64(v), any.ToInt64(), fmt.Sprintf("original val is %v", k))
}
}
var uintConvertMap = map[string]int{
"null": 0,
"321.1": 321,
`"1.1"`: 1,
`"-123.1"`: 0,
"0.0": 0,
"0": 0,
`"0"`: 0,
`"0.0"`: 0,
`"00.0"`: 0,
"true": 1,
"false": 0,
`"true"`: 0,
`"false"`: 0,
`"true123"`: 0,
`"+1"`: 1,
`"123true"`: 123,
`"-123true"`: 0,
`"1.2332e6"`: 1,
`""`: 0,
"+": 0,
"-": 0,
".": 0,
"[]": 0,
"[1,2]": 1,
"{}": 0,
"{1,2}": 0,
"-1.1": 0,
"-321.1": 0,
}
func Test_read_any_to_uint(t *testing.T) {
should := require.New(t)
for k, v := range uintConvertMap {
any := Get([]byte(k))
should.Equal(uint64(v), any.ToUint64(), fmt.Sprintf("origin val %v", k))
}
for k, v := range uintConvertMap {
any := Get([]byte(k))
should.Equal(uint32(v), any.ToUint32(), fmt.Sprintf("origin val %v", k))
}
for k, v := range uintConvertMap {
any := Get([]byte(k))
should.Equal(uint(v), any.ToUint(), fmt.Sprintf("origin val %v", k))
}
}
func Test_read_int64_to_any(t *testing.T) {
should := require.New(t)
any := WrapInt64(12345)
should.Equal(12345, any.ToInt())
should.Equal(int32(12345), any.ToInt32())
should.Equal(int64(12345), any.ToInt64())
should.Equal(uint(12345), any.ToUint())
should.Equal(uint32(12345), any.ToUint32())
should.Equal(uint64(12345), any.ToUint64())
should.Equal(float32(12345), any.ToFloat32())
should.Equal(float64(12345), any.ToFloat64())
should.Equal("12345", any.ToString())
should.Equal(true, any.ToBool())
should.Equal(any.ValueType(), NumberValue)
stream := NewStream(ConfigDefault, nil, 32)
any.WriteTo(stream)
should.Equal("12345", string(stream.Buffer()))
}
func Test_read_int32_to_any(t *testing.T) {
should := require.New(t)
any := WrapInt32(12345)
should.Equal(12345, any.ToInt())
should.Equal(int32(12345), any.ToInt32())
should.Equal(int64(12345), any.ToInt64())
should.Equal(uint(12345), any.ToUint())
should.Equal(uint32(12345), any.ToUint32())
should.Equal(uint64(12345), any.ToUint64())
should.Equal(float32(12345), any.ToFloat32())
should.Equal(float64(12345), any.ToFloat64())
should.Equal("12345", any.ToString())
should.Equal(true, any.ToBool())
should.Equal(any.ValueType(), NumberValue)
stream := NewStream(ConfigDefault, nil, 32)
any.WriteTo(stream)
should.Equal("12345", string(stream.Buffer()))
}
func Test_read_uint32_to_any(t *testing.T) {
should := require.New(t)
any := WrapUint32(12345)
should.Equal(12345, any.ToInt())
should.Equal(int32(12345), any.ToInt32())
should.Equal(int64(12345), any.ToInt64())
should.Equal(uint(12345), any.ToUint())
should.Equal(uint32(12345), any.ToUint32())
should.Equal(uint64(12345), any.ToUint64())
should.Equal(float32(12345), any.ToFloat32())
should.Equal(float64(12345), any.ToFloat64())
should.Equal("12345", any.ToString())
should.Equal(true, any.ToBool())
should.Equal(any.ValueType(), NumberValue)
stream := NewStream(ConfigDefault, nil, 32)
any.WriteTo(stream)
should.Equal("12345", string(stream.Buffer()))
}
func Test_read_uint64_to_any(t *testing.T) {
should := require.New(t)
any := WrapUint64(12345)
should.Equal(12345, any.ToInt())
should.Equal(int32(12345), any.ToInt32())
should.Equal(int64(12345), any.ToInt64())
should.Equal(uint(12345), any.ToUint())
should.Equal(uint32(12345), any.ToUint32())
should.Equal(uint64(12345), any.ToUint64())
should.Equal(float32(12345), any.ToFloat32())
should.Equal(float64(12345), any.ToFloat64())
should.Equal("12345", any.ToString())
should.Equal(true, any.ToBool())
should.Equal(any.ValueType(), NumberValue)
stream := NewStream(ConfigDefault, nil, 32)
any.WriteTo(stream)
should.Equal("12345", string(stream.Buffer()))
stream = NewStream(ConfigDefault, nil, 32)
stream.WriteUint(uint(123))
should.Equal("123", string(stream.Buffer()))
}
func Test_int_lazy_any_get(t *testing.T) {
should := require.New(t)
any := Get([]byte("1234"))
// panic!!
//should.Equal(any.LastError(), io.EOF)
should.Equal(InvalidValue, any.Get(1, "2").ValueType())
}

View File

@ -1,14 +0,0 @@
package jsoniter
import (
"github.com/stretchr/testify/require"
"testing"
)
func Test_wrap_map(t *testing.T) {
should := require.New(t)
any := Wrap(map[string]string{"Field1": "hello"})
should.Equal("hello", any.Get("Field1").ToString())
any = Wrap(map[string]string{"Field1": "hello"})
should.Equal(1, any.Size())
}

View File

@ -1,15 +0,0 @@
package jsoniter
import (
"github.com/stretchr/testify/require"
"testing"
)
func Test_read_null_as_any(t *testing.T) {
should := require.New(t)
any := Get([]byte(`null`))
should.Equal(0, any.ToInt())
should.Equal(float64(0), any.ToFloat64())
should.Equal("", any.ToString())
should.False(any.ToBool())
}

View File

@ -1,107 +0,0 @@
package jsoniter
import (
"testing"
"github.com/stretchr/testify/require"
)
func Test_read_object_as_any(t *testing.T) {
should := require.New(t)
any := Get([]byte(`{"a":"stream","c":"d"}`))
should.Equal(`{"a":"stream","c":"d"}`, any.ToString())
// partial parse
should.Equal("stream", any.Get("a").ToString())
should.Equal("d", any.Get("c").ToString())
should.Equal(2, len(any.Keys()))
any = Get([]byte(`{"a":"stream","c":"d"}`))
// full parse
should.Equal(2, len(any.Keys()))
should.Equal(2, any.Size())
should.True(any.ToBool())
should.Equal(0, any.ToInt())
should.Equal(ObjectValue, any.ValueType())
should.Nil(any.LastError())
obj := struct {
A string
}{}
any.ToVal(&obj)
should.Equal("stream", obj.A)
}
func Test_object_lazy_any_get(t *testing.T) {
should := require.New(t)
any := Get([]byte(`{"a":{"stream":{"c":"d"}}}`))
should.Equal("d", any.Get("a", "stream", "c").ToString())
}
func Test_object_lazy_any_get_all(t *testing.T) {
should := require.New(t)
any := Get([]byte(`{"a":[0],"stream":[1]}`))
should.Contains(any.Get('*', 0).ToString(), `"a":0`)
}
func Test_object_lazy_any_get_invalid(t *testing.T) {
should := require.New(t)
any := Get([]byte(`{}`))
should.Equal(InvalidValue, any.Get("a", "stream", "c").ValueType())
should.Equal(InvalidValue, any.Get(1).ValueType())
}
func Test_wrap_map_and_convert_to_any(t *testing.T) {
should := require.New(t)
any := Wrap(map[string]interface{}{"a": 1})
should.True(any.ToBool())
should.Equal(0, any.ToInt())
should.Equal(int32(0), any.ToInt32())
should.Equal(int64(0), any.ToInt64())
should.Equal(float32(0), any.ToFloat32())
should.Equal(float64(0), any.ToFloat64())
should.Equal(uint(0), any.ToUint())
should.Equal(uint32(0), any.ToUint32())
should.Equal(uint64(0), any.ToUint64())
}
func Test_wrap_object_and_convert_to_any(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
field2 string
}
any := Wrap(TestObject{"hello", "world"})
should.Equal("hello", any.Get("Field1").ToString())
any = Wrap(TestObject{"hello", "world"})
should.Equal(2, any.Size())
should.Equal(`{"Field1":"hello"}`, any.Get('*').ToString())
should.Equal(0, any.ToInt())
should.Equal(int32(0), any.ToInt32())
should.Equal(int64(0), any.ToInt64())
should.Equal(float32(0), any.ToFloat32())
should.Equal(float64(0), any.ToFloat64())
should.Equal(uint(0), any.ToUint())
should.Equal(uint32(0), any.ToUint32())
should.Equal(uint64(0), any.ToUint64())
should.True(any.ToBool())
should.Equal(`{"Field1":"hello"}`, any.ToString())
// cannot pass!
//stream := NewStream(ConfigDefault, nil, 32)
//any.WriteTo(stream)
//should.Equal(`{"Field1":"hello"}`, string(stream.Buffer()))
// cannot pass!
}
func Test_any_within_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 Any
Field2 Any
}
obj := TestObject{}
err := UnmarshalFromString(`{"Field1": "hello", "Field2": [1,2,3]}`, &obj)
should.Nil(err)
should.Equal("hello", obj.Field1.ToString())
should.Equal("[1,2,3]", obj.Field2.ToString())
}

View File

@ -1,56 +0,0 @@
package jsoniter
import (
"testing"
"github.com/stretchr/testify/require"
)
var stringConvertMap = map[string]string{
"null": "",
"321.1": "321.1",
`"1.1"`: "1.1",
`"-123.1"`: "-123.1",
"0.0": "0.0",
"0": "0",
`"0"`: "0",
`"0.0"`: "0.0",
`"00.0"`: "00.0",
"true": "true",
"false": "false",
`"true"`: "true",
`"false"`: "false",
`"true123"`: "true123",
`"+1"`: "+1",
"[]": "[]",
"[1,2]": "[1,2]",
"{}": "{}",
`{"a":1, "stream":true}`: `{"a":1, "stream":true}`,
}
func Test_read_any_to_string(t *testing.T) {
should := require.New(t)
for k, v := range stringConvertMap {
any := Get([]byte(k))
should.Equal(v, any.ToString(), "original val "+k)
}
}
func Test_read_string_as_any(t *testing.T) {
should := require.New(t)
any := Get([]byte(`"hello"`))
should.Equal("hello", any.ToString())
should.True(any.ToBool())
any = Get([]byte(`" "`))
should.False(any.ToBool())
any = Get([]byte(`"false"`))
should.True(any.ToBool())
any = Get([]byte(`"123"`))
should.Equal(123, any.ToInt())
}
func Test_wrap_string(t *testing.T) {
should := require.New(t)
any := WrapString("123")
should.Equal(123, any.ToInt())
}

View File

@ -3,16 +3,17 @@ package jsoniter
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/stretchr/testify/require" "github.com/json-iterator/go/require"
"io"
"testing" "testing"
) )
func Test_empty_array(t *testing.T) { func Test_empty_array(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `[]`) iter := ParseString(`[]`)
cont := iter.ReadArray() cont := iter.ReadArray()
should.False(cont) should.False(cont)
iter = ParseString(ConfigDefault, `[]`) iter = ParseString(`[]`)
iter.ReadArrayCB(func(iter *Iterator) bool { iter.ReadArrayCB(func(iter *Iterator) bool {
should.FailNow("should not call") should.FailNow("should not call")
return true return true
@ -21,11 +22,11 @@ func Test_empty_array(t *testing.T) {
func Test_one_element(t *testing.T) { func Test_one_element(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `[1]`) iter := ParseString(`[1]`)
should.True(iter.ReadArray()) should.True(iter.ReadArray())
should.Equal(1, iter.ReadInt()) should.Equal(1, iter.ReadInt())
should.False(iter.ReadArray()) should.False(iter.ReadArray())
iter = ParseString(ConfigDefault, `[1]`) iter = ParseString(`[1]`)
iter.ReadArrayCB(func(iter *Iterator) bool { iter.ReadArrayCB(func(iter *Iterator) bool {
should.Equal(1, iter.ReadInt()) should.Equal(1, iter.ReadInt())
return true return true
@ -34,18 +35,124 @@ func Test_one_element(t *testing.T) {
func Test_two_elements(t *testing.T) { func Test_two_elements(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `[1,2]`) iter := ParseString(`[1,2]`)
should.True(iter.ReadArray()) should.True(iter.ReadArray())
should.Equal(int64(1), iter.ReadInt64()) should.Equal(int64(1), iter.ReadInt64())
should.True(iter.ReadArray()) should.True(iter.ReadArray())
should.Equal(int64(2), iter.ReadInt64()) should.Equal(int64(2), iter.ReadInt64())
should.False(iter.ReadArray()) should.False(iter.ReadArray())
iter = ParseString(ConfigDefault, `[1,2]`) iter = ParseString(`[1,2]`)
should.Equal([]interface{}{float64(1), float64(2)}, iter.Read()) should.Equal([]interface{}{float64(1), float64(2)}, iter.Read())
} }
func Test_read_empty_array_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[]")
should.Nil(err)
should.Equal(0, any.Size())
}
func Test_read_one_element_array_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[1]")
should.Nil(err)
should.Equal(1, any.Size())
}
func Test_read_two_element_array_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[1,2]")
should.Nil(err)
should.Equal(1, any.Get(0).ToInt())
should.Equal(2, any.Size())
should.True(any.ToBool())
should.Equal(1, any.ToInt())
}
func Test_read_array_with_any_iterator(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[1,2]")
should.Nil(err)
var element Any
var elements []int
for next, hasNext := any.IterateArray(); hasNext; {
element, hasNext = next()
elements = append(elements, element.ToInt())
}
should.Equal([]int{1, 2}, elements)
}
func Test_wrap_array(t *testing.T) {
should := require.New(t)
any := Wrap([]int{1, 2, 3})
should.Equal("[1,2,3]", any.ToString())
var element Any
var elements []int
for next, hasNext := any.IterateArray(); hasNext; {
element, hasNext = next()
elements = append(elements, element.ToInt())
}
should.Equal([]int{1, 2, 3}, elements)
any = Wrap([]int{1, 2, 3})
should.Equal(3, any.Size())
any = Wrap([]int{1, 2, 3})
should.Equal(2, any.Get(1).ToInt())
}
func Test_array_lazy_any_get(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[1,[2,3],4]")
should.Nil(err)
should.Equal(3, any.Get(1, 1).ToInt())
should.Equal("[1,[2,3],4]", any.ToString())
}
func Test_array_lazy_any_get_all(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[[1],[2],[3,4]]")
should.Nil(err)
should.Equal("[1,2,3]", any.Get('*', 0).ToString())
}
func Test_array_wrapper_any_get_all(t *testing.T) {
should := require.New(t)
any := wrapArray([][]int{
{1, 2},
{3, 4},
{5, 6},
})
should.Equal("[1,3,5]", any.Get('*', 0).ToString())
}
func Test_array_lazy_any_get_invalid(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[]")
should.Nil(err)
should.Equal(Invalid, any.Get(1, 1).ValueType())
should.NotNil(any.Get(1, 1).LastError())
should.Equal(Invalid, any.Get("1").ValueType())
should.NotNil(any.Get("1").LastError())
}
func Test_array_lazy_any_set(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[1,[2,3],4]")
should.Nil(err)
any.GetArray()[0] = WrapInt64(2)
str, err := MarshalToString(any)
should.Nil(err)
should.Equal("[2,[2,3],4]", str)
}
func Test_invalid_array(t *testing.T) {
_, err := UnmarshalAnyFromString("[")
if err == nil || err == io.EOF {
t.FailNow()
}
}
func Test_whitespace_in_head(t *testing.T) { func Test_whitespace_in_head(t *testing.T) {
iter := ParseString(ConfigDefault, ` [1]`) iter := ParseString(` [1]`)
cont := iter.ReadArray() cont := iter.ReadArray()
if cont != true { if cont != true {
t.FailNow() t.FailNow()
@ -56,7 +163,7 @@ func Test_whitespace_in_head(t *testing.T) {
} }
func Test_whitespace_after_array_start(t *testing.T) { func Test_whitespace_after_array_start(t *testing.T) {
iter := ParseString(ConfigDefault, `[ 1]`) iter := ParseString(`[ 1]`)
cont := iter.ReadArray() cont := iter.ReadArray()
if cont != true { if cont != true {
t.FailNow() t.FailNow()
@ -67,7 +174,7 @@ func Test_whitespace_after_array_start(t *testing.T) {
} }
func Test_whitespace_before_array_end(t *testing.T) { func Test_whitespace_before_array_end(t *testing.T) {
iter := ParseString(ConfigDefault, `[1 ]`) iter := ParseString(`[1 ]`)
cont := iter.ReadArray() cont := iter.ReadArray()
if cont != true { if cont != true {
t.FailNow() t.FailNow()
@ -82,7 +189,7 @@ func Test_whitespace_before_array_end(t *testing.T) {
} }
func Test_whitespace_before_comma(t *testing.T) { func Test_whitespace_before_comma(t *testing.T) {
iter := ParseString(ConfigDefault, `[1 ,2]`) iter := ParseString(`[1 ,2]`)
cont := iter.ReadArray() cont := iter.ReadArray()
if cont != true { if cont != true {
t.FailNow() t.FailNow()
@ -106,7 +213,8 @@ func Test_whitespace_before_comma(t *testing.T) {
func Test_write_array(t *testing.T) { func Test_write_array(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(Config{IndentionStep: 2}.Froze(), buf, 4096) stream := NewStream(buf, 4096)
stream.IndentionStep = 2
stream.WriteArrayStart() stream.WriteArrayStart()
stream.WriteInt(1) stream.WriteInt(1)
stream.WriteMore() stream.WriteMore()
@ -120,7 +228,7 @@ func Test_write_array(t *testing.T) {
func Test_write_val_array(t *testing.T) { func Test_write_val_array(t *testing.T) {
should := require.New(t) should := require.New(t)
val := []int{1, 2, 3} val := []int{1, 2, 3}
str, err := MarshalToString(&val) str, err := MarshalToString(val)
should.Nil(err) should.Nil(err)
should.Equal("[1,2,3]", str) should.Equal("[1,2,3]", str)
} }
@ -146,6 +254,16 @@ func Test_write_array_of_interface_in_struct(t *testing.T) {
should.Contains(str, `"Field2":""`) should.Contains(str, `"Field2":""`)
} }
func Test_json_RawMessage(t *testing.T) {
should := require.New(t)
var data json.RawMessage
should.Nil(Unmarshal([]byte(`[1,2,3]`), &data))
should.Equal(`[1,2,3]`, string(data))
str, err := MarshalToString(data)
should.Nil(err)
should.Equal(`[1,2,3]`, str)
}
func Test_encode_byte_array(t *testing.T) { func Test_encode_byte_array(t *testing.T) {
should := require.New(t) should := require.New(t)
bytes, err := json.Marshal([]byte{1, 2, 3}) bytes, err := json.Marshal([]byte{1, 2, 3})
@ -156,7 +274,7 @@ func Test_encode_byte_array(t *testing.T) {
should.Equal(`"AQID"`, string(bytes)) should.Equal(`"AQID"`, string(bytes))
} }
func Test_decode_byte_array_from_base64(t *testing.T) { func Test_decode_byte_array(t *testing.T) {
should := require.New(t) should := require.New(t)
data := []byte{} data := []byte{}
err := json.Unmarshal([]byte(`"AQID"`), &data) err := json.Unmarshal([]byte(`"AQID"`), &data)
@ -167,35 +285,10 @@ func Test_decode_byte_array_from_base64(t *testing.T) {
should.Equal([]byte{1, 2, 3}, data) should.Equal([]byte{1, 2, 3}, data)
} }
func Test_decode_byte_array_from_array(t *testing.T) {
should := require.New(t)
data := []byte{}
err := json.Unmarshal([]byte(`[1,2,3]`), &data)
should.Nil(err)
should.Equal([]byte{1, 2, 3}, data)
err = Unmarshal([]byte(`[1,2,3]`), &data)
should.Nil(err)
should.Equal([]byte{1, 2, 3}, data)
}
func Test_decode_slice(t *testing.T) {
should := require.New(t)
slice := make([]string, 0, 5)
UnmarshalFromString(`["hello", "world"]`, &slice)
should.Equal([]string{"hello", "world"}, slice)
}
func Test_decode_large_slice(t *testing.T) {
should := require.New(t)
slice := make([]int, 0, 1)
UnmarshalFromString(`[1,2,3,4,5,6,7,8,9]`, &slice)
should.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}, slice)
}
func Benchmark_jsoniter_array(b *testing.B) { func Benchmark_jsoniter_array(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
input := []byte(`[1,2,3,4,5,6,7,8,9]`) input := []byte(`[1,2,3,4,5,6,7,8,9]`)
iter := ParseBytes(ConfigDefault, input) iter := ParseBytes(input)
b.ResetTimer() b.ResetTimer()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter.ResetBytes(input) iter.ResetBytes(input)

File diff suppressed because one or more lines are too long

View File

@ -2,112 +2,48 @@ package jsoniter
import ( import (
"bytes" "bytes"
"encoding/json" "github.com/json-iterator/go/require"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func Test_true(t *testing.T) { func Test_true(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `true`) iter := ParseString(`true`)
should.True(iter.ReadBool()) should.True(iter.ReadBool())
iter = ParseString(ConfigDefault, `true`) iter = ParseString(`true`)
should.Equal(true, iter.Read()) should.Equal(true, iter.Read())
} }
func Test_false(t *testing.T) { func Test_false(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `false`) iter := ParseString(`false`)
should.False(iter.ReadBool()) should.False(iter.ReadBool())
} }
func Test_read_bool_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("true")
should.Nil(err)
should.True(any.ToBool())
}
func Test_write_true_false(t *testing.T) { func Test_write_true_false(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteTrue() stream.WriteTrue()
stream.WriteFalse() stream.WriteFalse()
stream.WriteBool(false)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
should.Equal("truefalsefalse", buf.String()) should.Equal("truefalse", buf.String())
} }
func Test_write_val_bool(t *testing.T) { func Test_write_val_bool(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(true) stream.WriteVal(true)
should.Equal(stream.Buffered(), 4)
stream.Flush() stream.Flush()
should.Equal(stream.Buffered(), 0)
should.Nil(stream.Error) should.Nil(stream.Error)
should.Equal("true", buf.String()) should.Equal("true", buf.String())
} }
func Test_encode_string_bool(t *testing.T) {
type TestObject struct {
Field bool `json:",omitempty,string"`
}
should := require.New(t)
output, err := json.Marshal(TestObject{true})
should.Nil(err)
should.Equal(`{"Field":"true"}`, string(output))
output, err = Marshal(TestObject{true})
should.Nil(err)
should.Equal(`{"Field":"true"}`, string(output))
}
func Test_decode_string_bool(t *testing.T) {
type TestObject struct {
Field bool `json:",omitempty,string"`
}
should := require.New(t)
obj := TestObject{}
err := json.Unmarshal([]byte(`{"Field":"true"}`), &obj)
should.Nil(err)
should.True(obj.Field)
obj = TestObject{}
err = json.Unmarshal([]byte(`{"Field":true}`), &obj)
should.NotNil(err)
obj = TestObject{}
err = Unmarshal([]byte(`{"Field":"true"}`), &obj)
should.Nil(err)
should.True(obj.Field)
obj = TestObject{}
err = Unmarshal([]byte(`{"Field":true}`), &obj)
should.NotNil(err)
}
func Test_bool_can_be_null(t *testing.T) {
type TestData struct {
Field bool `json:"field"`
}
should := require.New(t)
obj := TestData{}
data1 := []byte(`{"field": true}`)
err := Unmarshal(data1, &obj)
should.NoError(err)
should.Equal(true, obj.Field)
data2 := []byte(`{"field": null}`)
err = Unmarshal(data2, &obj)
should.NoError(err)
// Same behavior as stdlib, not touching the existing value.
should.Equal(true, obj.Field)
// Checking stdlib behavior as well
obj2 := TestData{}
err = json.Unmarshal(data1, &obj2)
should.NoError(err)
should.Equal(true, obj2.Field)
err = json.Unmarshal(data2, &obj2)
should.NoError(err)
should.Equal(true, obj2.Field)
}

View File

@ -2,7 +2,8 @@ package jsoniter
import ( import (
"encoding/json" "encoding/json"
"github.com/stretchr/testify/require" "github.com/json-iterator/go/require"
"reflect"
"strconv" "strconv"
"testing" "testing"
"time" "time"
@ -10,7 +11,7 @@ import (
) )
func Test_customize_type_decoder(t *testing.T) { func Test_customize_type_decoder(t *testing.T) {
RegisterTypeDecoderFunc("time.Time", func(ptr unsafe.Pointer, iter *Iterator) { RegisterTypeDecoder("time.Time", func(ptr unsafe.Pointer, iter *Iterator) {
t, err := time.ParseInLocation("2006-01-02 15:04:05", iter.ReadString(), time.UTC) t, err := time.ParseInLocation("2006-01-02 15:04:05", iter.ReadString(), time.UTC)
if err != nil { if err != nil {
iter.Error = err iter.Error = err
@ -18,7 +19,7 @@ func Test_customize_type_decoder(t *testing.T) {
} }
*((*time.Time)(ptr)) = t *((*time.Time)(ptr)) = t
}) })
defer ConfigDefault.(*frozenConfig).cleanDecoders() defer CleanDecoders()
val := time.Time{} val := time.Time{}
err := Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val) err := Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val)
if err != nil { if err != nil {
@ -32,11 +33,11 @@ func Test_customize_type_decoder(t *testing.T) {
func Test_customize_type_encoder(t *testing.T) { func Test_customize_type_encoder(t *testing.T) {
should := require.New(t) should := require.New(t)
RegisterTypeEncoderFunc("time.Time", func(ptr unsafe.Pointer, stream *Stream) { RegisterTypeEncoder("time.Time", func(ptr unsafe.Pointer, stream *Stream) {
t := *((*time.Time)(ptr)) t := *((*time.Time)(ptr))
stream.WriteString(t.UTC().Format("2006-01-02 15:04:05")) stream.WriteString(t.UTC().Format("2006-01-02 15:04:05"))
}, nil) })
defer ConfigDefault.(*frozenConfig).cleanEncoders() defer CleanEncoders()
val := time.Unix(0, 0) val := time.Unix(0, 0)
str, err := MarshalToString(val) str, err := MarshalToString(val)
should.Nil(err) should.Nil(err)
@ -44,13 +45,13 @@ func Test_customize_type_encoder(t *testing.T) {
} }
func Test_customize_byte_array_encoder(t *testing.T) { func Test_customize_byte_array_encoder(t *testing.T) {
ConfigDefault.(*frozenConfig).cleanEncoders() CleanEncoders()
should := require.New(t) should := require.New(t)
RegisterTypeEncoderFunc("[]uint8", func(ptr unsafe.Pointer, stream *Stream) { RegisterTypeEncoder("[]uint8", func(ptr unsafe.Pointer, stream *Stream) {
t := *((*[]byte)(ptr)) t := *((*[]byte)(ptr))
stream.WriteString(string(t)) stream.WriteString(string(t))
}, nil) })
defer ConfigDefault.(*frozenConfig).cleanEncoders() defer CleanEncoders()
val := []byte("abc") val := []byte("abc")
str, err := MarshalToString(val) str, err := MarshalToString(val)
should.Nil(err) should.Nil(err)
@ -59,8 +60,9 @@ func Test_customize_byte_array_encoder(t *testing.T) {
func Test_customize_float_marshal(t *testing.T) { func Test_customize_float_marshal(t *testing.T) {
should := require.New(t) should := require.New(t)
json := Config{MarshalFloatWith6Digits: true}.Froze() EnableLossyFloatMarshalling()
str, err := json.MarshalToString(float32(1.23456789)) defer CleanEncoders()
str, err := MarshalToString(float32(1.23456789))
should.Nil(err) should.Nil(err)
should.Equal("1.234568", str) should.Equal("1.234568", str)
} }
@ -70,10 +72,10 @@ type Tom struct {
} }
func Test_customize_field_decoder(t *testing.T) { func Test_customize_field_decoder(t *testing.T) {
RegisterFieldDecoderFunc("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *Iterator) { RegisterFieldDecoder("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *Iterator) {
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt()) *((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
}) })
defer ConfigDefault.(*frozenConfig).cleanDecoders() defer CleanDecoders()
tom := Tom{} tom := Tom{}
err := Unmarshal([]byte(`{"field1": 100}`), &tom) err := Unmarshal([]byte(`{"field1": 100}`), &tom)
if err != nil { if err != nil {
@ -85,30 +87,22 @@ type TestObject1 struct {
field1 string field1 string
} }
type testExtension struct {
DummyExtension
}
func (extension *testExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) {
if structDescriptor.Type.String() != "jsoniter.TestObject1" {
return
}
binding := structDescriptor.GetField("field1")
binding.Encoder = &funcEncoder{fun: func(ptr unsafe.Pointer, stream *Stream) {
str := *((*string)(ptr))
val, _ := strconv.Atoi(str)
stream.WriteInt(val)
}}
binding.Decoder = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) {
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
}}
binding.ToNames = []string{"field-1"}
binding.FromNames = []string{"field-1"}
}
func Test_customize_field_by_extension(t *testing.T) { func Test_customize_field_by_extension(t *testing.T) {
should := require.New(t) should := require.New(t)
RegisterExtension(&testExtension{}) RegisterExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, EncoderFunc, DecoderFunc) {
if type_.String() == "jsoniter.TestObject1" && field.Name == "field1" {
encode := func(ptr unsafe.Pointer, stream *Stream) {
str := *((*string)(ptr))
val, _ := strconv.Atoi(str)
stream.WriteInt(val)
}
decode := func(ptr unsafe.Pointer, iter *Iterator) {
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
}
return []string{"field-1"}, encode, decode
}
return nil, nil, nil
})
obj := TestObject1{} obj := TestObject1{}
err := UnmarshalFromString(`{"field-1": 100}`, &obj) err := UnmarshalFromString(`{"field-1": 100}`, &obj)
should.Nil(err) should.Nil(err)
@ -118,42 +112,59 @@ func Test_customize_field_by_extension(t *testing.T) {
should.Equal(`{"field-1":100}`, str) should.Equal(`{"field-1":100}`, str)
} }
type timeImplementedMarshaler time.Time func Test_unexported_fields(t *testing.T) {
EnableUnexportedStructFieldsSupport()
should := require.New(t)
type TestObject struct {
field1 string
field2 string `json:"field-2"`
}
obj := TestObject{}
obj.field1 = "hello"
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("hello", obj.field1)
should.Nil(UnmarshalFromString(`{"field1": "world", "field-2": "abc"}`, &obj))
should.Equal("world", obj.field1)
should.Equal("abc", obj.field2)
str, err := MarshalToString(obj)
should.Nil(err)
should.Contains(str, `"field-2":"abc"`)
}
func (obj timeImplementedMarshaler) MarshalJSON() ([]byte, error) { type ObjectImplementedMarshaler int
seconds := time.Time(obj).Unix()
return []byte(strconv.FormatInt(seconds, 10)), nil func (obj *ObjectImplementedMarshaler) MarshalJSON() ([]byte, error) {
return []byte(`"hello"`), nil
} }
func Test_marshaler(t *testing.T) { func Test_marshaler(t *testing.T) {
type TestObject struct { type TestObject struct {
Field timeImplementedMarshaler Field *ObjectImplementedMarshaler
} }
should := require.New(t) should := require.New(t)
val := timeImplementedMarshaler(time.Unix(123, 0)) val := ObjectImplementedMarshaler(100)
obj := TestObject{val} obj := TestObject{&val}
bytes, err := json.Marshal(obj) bytes, err := json.Marshal(obj)
should.Nil(err) should.Nil(err)
should.Equal(`{"Field":123}`, string(bytes)) should.Equal(`{"Field":"hello"}`, string(bytes))
str, err := MarshalToString(obj) str, err := MarshalToString(obj)
should.Nil(err) should.Nil(err)
should.Equal(`{"Field":123}`, str) should.Equal(`{"Field":"hello"}`, str)
} }
func Test_marshaler_and_encoder(t *testing.T) { func Test_marshaler_and_encoder(t *testing.T) {
type TestObject struct { type TestObject struct {
Field *timeImplementedMarshaler Field *ObjectImplementedMarshaler
} }
ConfigDefault.(*frozenConfig).cleanEncoders()
should := require.New(t) should := require.New(t)
RegisterTypeEncoderFunc("jsoniter.timeImplementedMarshaler", func(ptr unsafe.Pointer, stream *Stream) { RegisterTypeEncoder("jsoniter.ObjectImplementedMarshaler", func(ptr unsafe.Pointer, stream *Stream) {
stream.WriteString("hello from encoder") stream.WriteString("hello from encoder")
}, nil) })
val := timeImplementedMarshaler(time.Unix(123, 0)) val := ObjectImplementedMarshaler(100)
obj := TestObject{&val} obj := TestObject{&val}
bytes, err := json.Marshal(obj) bytes, err := json.Marshal(obj)
should.Nil(err) should.Nil(err)
should.Equal(`{"Field":123}`, string(bytes)) should.Equal(`{"Field":"hello"}`, string(bytes))
str, err := MarshalToString(obj) str, err := MarshalToString(obj)
should.Nil(err) should.Nil(err)
should.Equal(`{"Field":"hello from encoder"}`, str) should.Equal(`{"Field":"hello from encoder"}`, str)
@ -161,22 +172,26 @@ func Test_marshaler_and_encoder(t *testing.T) {
type ObjectImplementedUnmarshaler int type ObjectImplementedUnmarshaler int
func (obj *ObjectImplementedUnmarshaler) UnmarshalJSON(s []byte) error { func (obj *ObjectImplementedUnmarshaler) UnmarshalJSON([]byte) error {
val, _ := strconv.ParseInt(string(s[1:len(s)-1]), 10, 64) *obj = 100
*obj = ObjectImplementedUnmarshaler(val)
return nil return nil
} }
func Test_unmarshaler(t *testing.T) { func Test_unmarshaler(t *testing.T) {
type TestObject struct {
Field *ObjectImplementedUnmarshaler
Field2 string
}
should := require.New(t) should := require.New(t)
var obj ObjectImplementedUnmarshaler obj := TestObject{}
err := json.Unmarshal([]byte(` "100" `), &obj) val := ObjectImplementedUnmarshaler(0)
obj.Field = &val
err := json.Unmarshal([]byte(`{"Field":"hello"}`), &obj)
should.Nil(err) should.Nil(err)
should.Equal(100, int(obj)) should.Equal(100, int(*obj.Field))
iter := ParseString(ConfigDefault, ` "100" `) err = Unmarshal([]byte(`{"Field":"hello"}`), &obj)
iter.ReadVal(&obj)
should.Nil(err) should.Nil(err)
should.Equal(100, int(obj)) should.Equal(100, int(*obj.Field))
} }
func Test_unmarshaler_and_decoder(t *testing.T) { func Test_unmarshaler_and_decoder(t *testing.T) {
@ -184,157 +199,18 @@ func Test_unmarshaler_and_decoder(t *testing.T) {
Field *ObjectImplementedUnmarshaler Field *ObjectImplementedUnmarshaler
Field2 string Field2 string
} }
ConfigDefault.(*frozenConfig).cleanDecoders()
should := require.New(t) should := require.New(t)
RegisterTypeDecoderFunc("jsoniter.ObjectImplementedUnmarshaler", func(ptr unsafe.Pointer, iter *Iterator) { RegisterTypeDecoder("jsoniter.ObjectImplementedUnmarshaler", func(ptr unsafe.Pointer, iter *Iterator) {
*(*ObjectImplementedUnmarshaler)(ptr) = 10 *(*ObjectImplementedUnmarshaler)(ptr) = 10
iter.Skip() iter.Skip()
}) })
obj := TestObject{} obj := TestObject{}
val := ObjectImplementedUnmarshaler(0) val := ObjectImplementedUnmarshaler(0)
obj.Field = &val obj.Field = &val
err := json.Unmarshal([]byte(`{"Field":"100"}`), &obj) err := json.Unmarshal([]byte(`{"Field":"hello"}`), &obj)
should.Nil(err) should.Nil(err)
should.Equal(100, int(*obj.Field)) should.Equal(100, int(*obj.Field))
err = Unmarshal([]byte(`{"Field":"100"}`), &obj) err = Unmarshal([]byte(`{"Field":"hello"}`), &obj)
should.Nil(err) should.Nil(err)
should.Equal(10, int(*obj.Field)) should.Equal(10, int(*obj.Field))
} }
type tmString string
type tmStruct struct {
String tmString
}
func (s tmStruct) MarshalJSON() ([]byte, error) {
var b []byte
b = append(b, '"')
b = append(b, s.String...)
b = append(b, '"')
return b, nil
}
func Test_marshaler_on_struct(t *testing.T) {
fixed := tmStruct{"hello"}
//json.Marshal(fixed)
Marshal(fixed)
}
type withChan struct {
F2 chan []byte
}
func (q withChan) MarshalJSON() ([]byte, error) {
return []byte(`""`), nil
}
func (q *withChan) UnmarshalJSON(value []byte) error {
return nil
}
func Test_marshal_json_with_chan(t *testing.T) {
type TestObject struct {
F1 withChan
}
should := require.New(t)
output, err := MarshalToString(TestObject{})
should.Nil(err)
should.Equal(`{"F1":""}`, output)
}
type withTime struct {
time.Time
}
func (t *withTime) UnmarshalJSON(b []byte) error {
return nil
}
func (t withTime) MarshalJSON() ([]byte, error) {
return []byte(`"fake"`), nil
}
func Test_marshal_json_with_time(t *testing.T) {
type S1 struct {
F1 withTime
F2 *withTime
}
type TestObject struct {
TF1 S1
}
should := require.New(t)
obj := TestObject{
S1{
F1: withTime{
time.Unix(0, 0),
},
F2: &withTime{
time.Unix(0, 0),
},
},
}
output, err := json.Marshal(obj)
should.Nil(err)
should.Equal(`{"TF1":{"F1":"fake","F2":"fake"}}`, string(output))
output, err = Marshal(obj)
should.Nil(err)
should.Equal(`{"TF1":{"F1":"fake","F2":"fake"}}`, string(output))
obj = TestObject{}
should.Nil(json.Unmarshal([]byte(`{"TF1":{"F1":"fake","F2":"fake"}}`), &obj))
should.NotNil(obj.TF1.F2)
obj = TestObject{}
should.Nil(Unmarshal([]byte(`{"TF1":{"F1":"fake","F2":"fake"}}`), &obj))
should.NotNil(obj.TF1.F2)
}
func Test_customize_tag_key(t *testing.T) {
type TestObject struct {
Field string `orm:"field"`
}
should := require.New(t)
json := Config{TagKey: "orm"}.Froze()
str, err := json.MarshalToString(TestObject{"hello"})
should.Nil(err)
should.Equal(`{"field":"hello"}`, str)
}
func Test_recursive_empty_interface_customization(t *testing.T) {
t.Skip()
var obj interface{}
RegisterTypeDecoderFunc("interface {}", func(ptr unsafe.Pointer, iter *Iterator) {
switch iter.WhatIsNext() {
case NumberValue:
*(*interface{})(ptr) = iter.ReadInt64()
default:
*(*interface{})(ptr) = iter.Read()
}
})
should := require.New(t)
Unmarshal([]byte("[100]"), &obj)
should.Equal([]interface{}{int64(100)}, obj)
}
type GeoLocation struct {
Id string `json:"id,omitempty" db:"id"`
}
func (p *GeoLocation) MarshalJSON() ([]byte, error) {
return []byte(`{}`), nil
}
func (p *GeoLocation) UnmarshalJSON(input []byte) error {
p.Id = "hello"
return nil
}
func Test_marshal_and_unmarshal_on_non_pointer(t *testing.T) {
should := require.New(t)
locations := []GeoLocation{{"000"}}
bytes, err := Marshal(locations)
should.Nil(err)
should.Equal("[{}]", string(bytes))
err = Unmarshal([]byte("[1]"), &locations)
should.Nil(err)
should.Equal("hello", locations[0].Id)
}

View File

@ -2,9 +2,9 @@ package jsoniter
import ( import (
"encoding/json" "encoding/json"
"fmt"
"github.com/json-iterator/go/require"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func Test_bind_api_demo(t *testing.T) { func Test_bind_api_demo(t *testing.T) {
@ -16,13 +16,12 @@ func Test_bind_api_demo(t *testing.T) {
} }
func Test_iterator_api_demo(t *testing.T) { func Test_iterator_api_demo(t *testing.T) {
should := require.New(t) iter := ParseString(`[0,1,2,3]`)
iter := ParseString(ConfigDefault, `[0,1,2,3]`)
total := 0 total := 0
for iter.ReadArray() { for iter.ReadArray() {
total += iter.ReadInt() total += iter.ReadInt()
} }
should.Equal(6, total) fmt.Println(total)
} }
type People struct { type People struct {

View File

@ -1,42 +0,0 @@
package jsoniter
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
func Test_encode_interface(t *testing.T) {
should := require.New(t)
var a interface{}
a = int8(10)
str, err := MarshalToString(a)
should.Nil(err)
should.Equal(str, "10")
a = float32(3)
str, err = MarshalToString(a)
should.Nil(err)
should.Equal(str, "3")
a = map[string]interface{}{"abc": 1}
str, err = MarshalToString(a)
should.Nil(err)
should.Equal(str, `{"abc":1}`)
a = uintptr(1)
str, err = MarshalToString(a)
should.Nil(err)
should.Equal(str, "1")
a = uint(1)
str, err = MarshalToString(a)
should.Nil(err)
should.Equal(str, "1")
a = uint8(1)
str, err = MarshalToString(a)
should.Nil(err)
should.Equal(str, "1")
a = json.RawMessage("abc")
MarshalToString(a)
str, err = MarshalToString(a)
should.Nil(err)
should.Equal(str, "abc")
}

View File

@ -1,50 +0,0 @@
package jsoniter
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
type MyEnum int64
const (
MyEnumA MyEnum = iota
MyEnumB
)
func (m *MyEnum) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"foo-%d"`, int(*m))), nil
}
func (m *MyEnum) UnmarshalJSON(jb []byte) error {
switch string(jb) {
case `"foo-1"`:
*m = MyEnumB
default:
*m = MyEnumA
}
return nil
}
func Test_custom_marshaler_on_enum(t *testing.T) {
type Wrapper struct {
Payload interface{}
}
type Wrapper2 struct {
Payload MyEnum
}
should := require.New(t)
w := Wrapper{Payload: MyEnumB}
jb, err := Marshal(w)
should.NoError(err)
should.Equal(`{"Payload":"foo-1"}`, string(jb))
var w2 Wrapper2
err = Unmarshal(jb, &w2)
should.NoError(err)
should.Equal(MyEnumB, w2.Payload)
}

View File

@ -1,64 +1,62 @@
//+build jsoniter-sloppy
package jsoniter package jsoniter
import ( import (
"github.com/stretchr/testify/require" "github.com/json-iterator/go/require"
"io" "io"
"testing" "testing"
) )
func Test_string_end(t *testing.T) { func Test_string_end(t *testing.T) {
end, escaped := ParseString(ConfigDefault, `abc"`).findStringEnd() end, escaped := ParseString(`abc"`).findStringEnd()
if end != 4 { if end != 4 {
t.Fatal(end) t.Fatal(end)
} }
if escaped != false { if escaped != false {
t.Fatal(escaped) t.Fatal(escaped)
} }
end, escaped = ParseString(ConfigDefault, `abc\\"`).findStringEnd() end, escaped = ParseString(`abc\\"`).findStringEnd()
if end != 6 { if end != 6 {
t.Fatal(end) t.Fatal(end)
} }
if escaped != true { if escaped != true {
t.Fatal(escaped) t.Fatal(escaped)
} }
end, escaped = ParseString(ConfigDefault, `abc\\\\"`).findStringEnd() end, escaped = ParseString(`abc\\\\"`).findStringEnd()
if end != 8 { if end != 8 {
t.Fatal(end) t.Fatal(end)
} }
if escaped != true { if escaped != true {
t.Fatal(escaped) t.Fatal(escaped)
} }
end, escaped = ParseString(ConfigDefault, `abc\"`).findStringEnd() end, escaped = ParseString(`abc\"`).findStringEnd()
if end != -1 { if end != -1 {
t.Fatal(end) t.Fatal(end)
} }
if escaped != false { if escaped != false {
t.Fatal(escaped) t.Fatal(escaped)
} }
end, escaped = ParseString(ConfigDefault, `abc\`).findStringEnd() end, escaped = ParseString(`abc\`).findStringEnd()
if end != -1 { if end != -1 {
t.Fatal(end) t.Fatal(end)
} }
if escaped != true { if escaped != true {
t.Fatal(escaped) t.Fatal(escaped)
} }
end, escaped = ParseString(ConfigDefault, `abc\\`).findStringEnd() end, escaped = ParseString(`abc\\`).findStringEnd()
if end != -1 { if end != -1 {
t.Fatal(end) t.Fatal(end)
} }
if escaped != false { if escaped != false {
t.Fatal(escaped) t.Fatal(escaped)
} }
end, escaped = ParseString(ConfigDefault, `\\`).findStringEnd() end, escaped = ParseString(`\\`).findStringEnd()
if end != -1 { if end != -1 {
t.Fatal(end) t.Fatal(end)
} }
if escaped != false { if escaped != false {
t.Fatal(escaped) t.Fatal(escaped)
} }
end, escaped = ParseString(ConfigDefault, `\`).findStringEnd() end, escaped = ParseString(`\`).findStringEnd()
if end != -1 { if end != -1 {
t.Fatal(end) t.Fatal(end)
} }
@ -93,54 +91,54 @@ func (reader *StagedReader) Read(p []byte) (n int, err error) {
func Test_skip_string(t *testing.T) { func Test_skip_string(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `"abc`) iter := ParseString(`"abc`)
iter.skipString() iter.skipString()
should.Equal(1, iter.head) should.Equal(1, iter.head)
iter = ParseString(ConfigDefault, `\""abc`) iter = ParseString(`\""abc`)
iter.skipString() iter.skipString()
should.Equal(3, iter.head) should.Equal(3, iter.head)
reader := &StagedReader{ reader := &StagedReader{
r1: `abc`, r1: `abc`,
r2: `"`, r2: `"`,
} }
iter = Parse(ConfigDefault, reader, 4096) iter = Parse(reader, 4096)
iter.skipString() iter.skipString()
should.Equal(1, iter.head) should.Equal(1, iter.head)
reader = &StagedReader{ reader = &StagedReader{
r1: `abc`, r1: `abc`,
r2: `1"`, r2: `1"`,
} }
iter = Parse(ConfigDefault, reader, 4096) iter = Parse(reader, 4096)
iter.skipString() iter.skipString()
should.Equal(2, iter.head) should.Equal(2, iter.head)
reader = &StagedReader{ reader = &StagedReader{
r1: `abc\`, r1: `abc\`,
r2: `"`, r2: `"`,
} }
iter = Parse(ConfigDefault, reader, 4096) iter = Parse(reader, 4096)
iter.skipString() iter.skipString()
should.NotNil(iter.Error) should.NotNil(iter.Error)
reader = &StagedReader{ reader = &StagedReader{
r1: `abc\`, r1: `abc\`,
r2: `""`, r2: `""`,
} }
iter = Parse(ConfigDefault, reader, 4096) iter = Parse(reader, 4096)
iter.skipString() iter.skipString()
should.Equal(2, iter.head) should.Equal(2, iter.head)
} }
func Test_skip_object(t *testing.T) { func Test_skip_object(t *testing.T) {
iter := ParseString(ConfigDefault, `}`) iter := ParseString(`}`)
iter.skipObject() iter.skipObject()
if iter.head != 1 { if iter.head != 1 {
t.Fatal(iter.head) t.Fatal(iter.head)
} }
iter = ParseString(ConfigDefault, `a}`) iter = ParseString(`a}`)
iter.skipObject() iter.skipObject()
if iter.head != 2 { if iter.head != 2 {
t.Fatal(iter.head) t.Fatal(iter.head)
} }
iter = ParseString(ConfigDefault, `{}}a`) iter = ParseString(`{}}a`)
iter.skipObject() iter.skipObject()
if iter.head != 3 { if iter.head != 3 {
t.Fatal(iter.head) t.Fatal(iter.head)
@ -149,12 +147,12 @@ func Test_skip_object(t *testing.T) {
r1: `{`, r1: `{`,
r2: `}}a`, r2: `}}a`,
} }
iter = Parse(ConfigDefault, reader, 4096) iter = Parse(reader, 4096)
iter.skipObject() iter.skipObject()
if iter.head != 2 { if iter.head != 2 {
t.Fatal(iter.head) t.Fatal(iter.head)
} }
iter = ParseString(ConfigDefault, `"}"}a`) iter = ParseString(`"}"}a`)
iter.skipObject() iter.skipObject()
if iter.head != 4 { if iter.head != 4 {
t.Fatal(iter.head) t.Fatal(iter.head)

View File

@ -1,37 +0,0 @@
package jsoniter
import (
"encoding/json"
"github.com/stretchr/testify/require"
"testing"
)
func Test_encode_fixed_array(t *testing.T) {
should := require.New(t)
type FixedArray [2]float64
fixed := FixedArray{0.1, 1.0}
output, err := MarshalToString(fixed)
should.Nil(err)
should.Equal("[0.1,1]", output)
}
func Test_encode_fixed_array_of_map(t *testing.T) {
should := require.New(t)
type FixedArray [2]map[string]string
fixed := FixedArray{map[string]string{"1": "2"}, map[string]string{"3": "4"}}
output, err := MarshalToString(fixed)
should.Nil(err)
should.Equal(`[{"1":"2"},{"3":"4"}]`, output)
}
func Test_decode_fixed_array(t *testing.T) {
should := require.New(t)
type FixedArray [2]float64
var fixed FixedArray
should.Nil(json.Unmarshal([]byte("[1,2,3]"), &fixed))
should.Equal(float64(1), fixed[0])
should.Equal(float64(2), fixed[1])
should.Nil(Unmarshal([]byte("[1,2,3]"), &fixed))
should.Equal(float64(1), fixed[0])
should.Equal(float64(2), fixed[1])
}

View File

@ -1,20 +1,17 @@
// +build go1.8
package jsoniter package jsoniter
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/json-iterator/go/require"
"strconv" "strconv"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func Test_read_big_float(t *testing.T) { func Test_read_big_float(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `12.3`) iter := ParseString(`12.3`)
val := iter.ReadBigFloat() val := iter.ReadBigFloat()
val64, _ := val.Float64() val64, _ := val.Float64()
should.Equal(12.3, val64) should.Equal(12.3, val64)
@ -22,29 +19,26 @@ func Test_read_big_float(t *testing.T) {
func Test_read_big_int(t *testing.T) { func Test_read_big_int(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `92233720368547758079223372036854775807`) iter := ParseString(`92233720368547758079223372036854775807`)
val := iter.ReadBigInt() val := iter.ReadBigInt()
should.NotNil(val) should.NotNil(val)
should.Equal(`92233720368547758079223372036854775807`, val.String()) should.Equal(`92233720368547758079223372036854775807`, val.String())
} }
func Test_read_float(t *testing.T) { func Test_read_float(t *testing.T) {
inputs := []string{ inputs := []string{`1.1`, `1000`, `9223372036854775807`, `12.3`, `-12.3`, `720368.54775807`, `720368.547758075`}
`1.1`, `1000`, `9223372036854775807`, `12.3`, `-12.3`, `720368.54775807`, `720368.547758075`,
`1e1`, `1e+1`, `1e-1`, `1E1`, `1E+1`, `1E-1`, `-1e1`, `-1e+1`, `-1e-1`,
}
for _, input := range inputs { for _, input := range inputs {
// non-streaming // non-streaming
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, input+",") iter := ParseString(input + ",")
expected, err := strconv.ParseFloat(input, 32) expected, err := strconv.ParseFloat(input, 32)
should.Nil(err) should.Nil(err)
should.Equal(float32(expected), iter.ReadFloat32()) should.Equal(float32(expected), iter.ReadFloat32())
}) })
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, input+",") iter := ParseString(input + ",")
expected, err := strconv.ParseFloat(input, 64) expected, err := strconv.ParseFloat(input, 64)
should.Nil(err) should.Nil(err)
should.Equal(expected, iter.ReadFloat64()) should.Equal(expected, iter.ReadFloat64())
@ -52,28 +46,36 @@ func Test_read_float(t *testing.T) {
// streaming // streaming
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := Parse(ConfigDefault, bytes.NewBufferString(input+","), 2) iter := Parse(bytes.NewBufferString(input+","), 2)
expected, err := strconv.ParseFloat(input, 32) expected, err := strconv.ParseFloat(input, 32)
should.Nil(err) should.Nil(err)
should.Equal(float32(expected), iter.ReadFloat32()) should.Equal(float32(expected), iter.ReadFloat32())
}) })
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := Parse(ConfigDefault, bytes.NewBufferString(input+","), 2) iter := Parse(bytes.NewBufferString(input+","), 2)
val := float64(0) expected, err := strconv.ParseFloat(input, 64)
err := json.Unmarshal([]byte(input), &val)
should.Nil(err) should.Nil(err)
should.Equal(val, iter.ReadFloat64()) should.Equal(expected, iter.ReadFloat64())
}) })
} }
} }
func Test_read_float_as_interface(t *testing.T) { func Test_read_float_as_interface(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `12.3`) iter := ParseString(`12.3`)
should.Equal(float64(12.3), iter.Read()) should.Equal(float64(12.3), iter.Read())
} }
func Test_read_float_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("12.3")
should.Nil(err)
should.Equal(float64(12.3), any.ToFloat64())
should.Equal("12.3", any.ToString())
should.True(any.ToBool())
}
func Test_wrap_float(t *testing.T) { func Test_wrap_float(t *testing.T) {
should := require.New(t) should := require.New(t)
str, err := MarshalToString(WrapFloat64(12.3)) str, err := MarshalToString(WrapFloat64(12.3))
@ -88,38 +90,30 @@ func Test_write_float32(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteFloat32Lossy(val) stream.WriteFloat32Lossy(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
output, err := json.Marshal(val) should.Equal(strconv.FormatFloat(float64(val), 'f', -1, 32), buf.String())
should.Nil(err)
should.Equal(string(output), buf.String())
}) })
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(val) stream.WriteVal(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
output, err := json.Marshal(val) should.Equal(strconv.FormatFloat(float64(val), 'f', -1, 32), buf.String())
should.Nil(err)
should.Equal(string(output), buf.String())
}) })
} }
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 10) stream := NewStream(buf, 10)
stream.WriteRaw("abcdefg") stream.WriteRaw("abcdefg")
stream.WriteFloat32Lossy(1.123456) stream.WriteFloat32Lossy(1.123456)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
should.Equal("abcdefg1.123456", buf.String()) should.Equal("abcdefg1.123456", buf.String())
stream = NewStream(ConfigDefault, nil, 0)
stream.WriteFloat32(float32(0.0000001))
should.Equal("1e-07", string(stream.buf))
} }
func Test_write_float64(t *testing.T) { func Test_write_float64(t *testing.T) {
@ -129,7 +123,7 @@ func Test_write_float64(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteFloat64Lossy(val) stream.WriteFloat64Lossy(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -138,7 +132,7 @@ func Test_write_float64(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(val) stream.WriteVal(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -147,21 +141,17 @@ func Test_write_float64(t *testing.T) {
} }
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 10) stream := NewStream(buf, 10)
stream.WriteRaw("abcdefg") stream.WriteRaw("abcdefg")
stream.WriteFloat64Lossy(1.123456) stream.WriteFloat64Lossy(1.123456)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
should.Equal("abcdefg1.123456", buf.String()) should.Equal("abcdefg1.123456", buf.String())
stream = NewStream(ConfigDefault, nil, 0)
stream.WriteFloat64(float64(0.0000001))
should.Equal("1e-07", string(stream.buf))
} }
func Test_read_float64_cursor(t *testing.T) { func Test_read_float64_cursor(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, "[1.23456789\n,2,3]") iter := ParseString("[1.23456789\n,2,3]")
should.True(iter.ReadArray()) should.True(iter.ReadArray())
should.Equal(1.23456789, iter.Read()) should.Equal(1.23456789, iter.Read())
should.True(iter.ReadArray()) should.True(iter.ReadArray())
@ -181,21 +171,10 @@ func Test_read_float_scientific(t *testing.T) {
should.Equal(float64(10), obj) should.Equal(float64(10), obj)
} }
func Test_lossy_float_marshal(t *testing.T) {
should := require.New(t)
api := Config{MarshalFloatWith6Digits: true}.Froze()
output, err := api.MarshalToString(float64(0.1234567))
should.Nil(err)
should.Equal("0.123457", output)
output, err = api.MarshalToString(float32(0.1234567))
should.Nil(err)
should.Equal("0.123457", output)
}
func Benchmark_jsoniter_float(b *testing.B) { func Benchmark_jsoniter_float(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
input := []byte(`1.1123,`) input := []byte(`1.1123,`)
iter := NewIterator(ConfigDefault) iter := NewIterator()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter.ResetBytes(input) iter.ResetBytes(input)
iter.ReadFloat64() iter.ReadFloat64()

View File

@ -1,69 +1,29 @@
// +build go1.8
package jsoniter package jsoniter
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/json-iterator/go/require"
"io"
"io/ioutil" "io/ioutil"
"strconv" "strconv"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func Test_read_uint64_invalid(t *testing.T) { func Test_read_uint64_invalid(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, ",") iter := ParseString(",")
iter.ReadUint64() iter.ReadUint64()
should.NotNil(iter.Error) should.NotNil(iter.Error)
} }
func Test_read_int_from_null(t *testing.T) { func Test_read_int8(t *testing.T) {
type TestObject struct {
F1 int8
F2 int16
F3 int32
F4 int64
F5 int
F6 uint8
F7 uint16
F8 uint32
F9 uint64
F10 uint
F11 float32
F12 float64
F13 uintptr
}
should := require.New(t)
obj := TestObject{}
err := Unmarshal([]byte(`{
"f1":null,
"f2":null,
"f3":null,
"f4":null,
"f5":null,
"f6":null,
"f7":null,
"f8":null,
"f9":null,
"f10":null,
"f11":null,
"f12":null,
"f13":null
}`), &obj)
should.Nil(err)
}
func _int8(t *testing.T) {
inputs := []string{`127`, `-128`} inputs := []string{`127`, `-128`}
for _, input := range inputs { for _, input := range inputs {
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, input) iter := ParseString(input)
expected, err := strconv.ParseInt(input, 10, 8) expected, err := strconv.ParseInt(input, 10, 8)
should.Nil(err) should.Nil(err)
should.Equal(int8(expected), iter.ReadInt8()) should.Equal(int8(expected), iter.ReadInt8())
@ -76,7 +36,7 @@ func Test_read_int16(t *testing.T) {
for _, input := range inputs { for _, input := range inputs {
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, input) iter := ParseString(input)
expected, err := strconv.ParseInt(input, 10, 16) expected, err := strconv.ParseInt(input, 10, 16)
should.Nil(err) should.Nil(err)
should.Equal(int16(expected), iter.ReadInt16()) should.Equal(int16(expected), iter.ReadInt16())
@ -89,14 +49,14 @@ func Test_read_int32(t *testing.T) {
for _, input := range inputs { for _, input := range inputs {
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, input) iter := ParseString(input)
expected, err := strconv.ParseInt(input, 10, 32) expected, err := strconv.ParseInt(input, 10, 32)
should.Nil(err) should.Nil(err)
should.Equal(int32(expected), iter.ReadInt32()) should.Equal(int32(expected), iter.ReadInt32())
}) })
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := Parse(ConfigDefault, bytes.NewBufferString(input), 2) iter := Parse(bytes.NewBufferString(input), 2)
expected, err := strconv.ParseInt(input, 10, 32) expected, err := strconv.ParseInt(input, 10, 32)
should.Nil(err) should.Nil(err)
should.Equal(int32(expected), iter.ReadInt32()) should.Equal(int32(expected), iter.ReadInt32())
@ -120,52 +80,12 @@ func Test_read_int64_array(t *testing.T) {
should.Equal(3, len(val)) should.Equal(3, len(val))
} }
func Test_read_int_overflow(t *testing.T) { func Test_read_int32_overflow(t *testing.T) {
should := require.New(t) should := require.New(t)
inputArr := []string{"123451", "-123451"} input := "123456789123456789,"
for _, s := range inputArr { iter := ParseString(input)
iter := ParseString(ConfigDefault, s) iter.ReadInt32()
iter.ReadInt8() should.NotNil(iter.Error)
should.NotNil(iter.Error)
iterU := ParseString(ConfigDefault, s)
iterU.ReadUint8()
should.NotNil(iterU.Error)
}
inputArr = []string{"12345678912", "-12345678912"}
for _, s := range inputArr {
iter := ParseString(ConfigDefault, s)
iter.ReadInt16()
should.NotNil(iter.Error)
iterUint := ParseString(ConfigDefault, s)
iterUint.ReadUint16()
should.NotNil(iterUint.Error)
}
inputArr = []string{"3111111111", "-3111111111", "1234232323232323235678912", "-1234567892323232323212"}
for _, s := range inputArr {
iter := ParseString(ConfigDefault, s)
iter.ReadInt32()
should.NotNil(iter.Error)
iterUint := ParseString(ConfigDefault, s)
iterUint.ReadUint32()
should.NotNil(iterUint.Error)
}
inputArr = []string{"9223372036854775811", "-9523372036854775807", "1234232323232323235678912", "-1234567892323232323212"}
for _, s := range inputArr {
iter := ParseString(ConfigDefault, s)
iter.ReadInt64()
should.NotNil(iter.Error)
iterUint := ParseString(ConfigDefault, s)
iterUint.ReadUint64()
should.NotNil(iterUint.Error)
}
} }
func Test_read_int64(t *testing.T) { func Test_read_int64(t *testing.T) {
@ -173,14 +93,14 @@ func Test_read_int64(t *testing.T) {
for _, input := range inputs { for _, input := range inputs {
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, input) iter := ParseString(input)
expected, err := strconv.ParseInt(input, 10, 64) expected, err := strconv.ParseInt(input, 10, 64)
should.Nil(err) should.Nil(err)
should.Equal(expected, iter.ReadInt64()) should.Equal(expected, iter.ReadInt64())
}) })
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := Parse(ConfigDefault, bytes.NewBufferString(input), 2) iter := Parse(bytes.NewBufferString(input), 2)
expected, err := strconv.ParseInt(input, 10, 64) expected, err := strconv.ParseInt(input, 10, 64)
should.Nil(err) should.Nil(err)
should.Equal(expected, iter.ReadInt64()) should.Equal(expected, iter.ReadInt64())
@ -191,11 +111,28 @@ func Test_read_int64(t *testing.T) {
func Test_read_int64_overflow(t *testing.T) { func Test_read_int64_overflow(t *testing.T) {
should := require.New(t) should := require.New(t)
input := "123456789123456789123456789123456789," input := "123456789123456789123456789123456789,"
iter := ParseString(ConfigDefault, input) iter := ParseString(input)
iter.ReadInt64() iter.ReadInt64()
should.NotNil(iter.Error) should.NotNil(iter.Error)
} }
func Test_read_int64_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("1234")
should.Nil(err)
should.Equal(1234, any.ToInt())
should.Equal(io.EOF, any.LastError())
should.Equal("1234", any.ToString())
should.True(any.ToBool())
}
func Test_int_lazy_any_get(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("1234")
should.Nil(err)
should.Equal(Invalid, any.Get(1, "2").ValueType())
}
func Test_wrap_int(t *testing.T) { func Test_wrap_int(t *testing.T) {
should := require.New(t) should := require.New(t)
str, err := MarshalToString(WrapInt64(100)) str, err := MarshalToString(WrapInt64(100))
@ -209,7 +146,7 @@ func Test_write_uint8(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteUint8(val) stream.WriteUint8(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -218,7 +155,7 @@ func Test_write_uint8(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(val) stream.WriteVal(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -227,7 +164,7 @@ func Test_write_uint8(t *testing.T) {
} }
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 3) stream := NewStream(buf, 3)
stream.WriteRaw("a") stream.WriteRaw("a")
stream.WriteUint8(100) // should clear buffer stream.WriteUint8(100) // should clear buffer
stream.Flush() stream.Flush()
@ -241,7 +178,7 @@ func Test_write_int8(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteInt8(val) stream.WriteInt8(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -250,7 +187,7 @@ func Test_write_int8(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(val) stream.WriteVal(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -259,7 +196,7 @@ func Test_write_int8(t *testing.T) {
} }
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4) stream := NewStream(buf, 4)
stream.WriteRaw("a") stream.WriteRaw("a")
stream.WriteInt8(-100) // should clear buffer stream.WriteInt8(-100) // should clear buffer
stream.Flush() stream.Flush()
@ -273,7 +210,7 @@ func Test_write_uint16(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteUint16(val) stream.WriteUint16(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -282,7 +219,7 @@ func Test_write_uint16(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(val) stream.WriteVal(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -291,7 +228,7 @@ func Test_write_uint16(t *testing.T) {
} }
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 5) stream := NewStream(buf, 5)
stream.WriteRaw("a") stream.WriteRaw("a")
stream.WriteUint16(10000) // should clear buffer stream.WriteUint16(10000) // should clear buffer
stream.Flush() stream.Flush()
@ -305,7 +242,7 @@ func Test_write_int16(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteInt16(val) stream.WriteInt16(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -314,7 +251,7 @@ func Test_write_int16(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(val) stream.WriteVal(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -323,7 +260,7 @@ func Test_write_int16(t *testing.T) {
} }
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 6) stream := NewStream(buf, 6)
stream.WriteRaw("a") stream.WriteRaw("a")
stream.WriteInt16(-10000) // should clear buffer stream.WriteInt16(-10000) // should clear buffer
stream.Flush() stream.Flush()
@ -337,7 +274,7 @@ func Test_write_uint32(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteUint32(val) stream.WriteUint32(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -346,7 +283,7 @@ func Test_write_uint32(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(val) stream.WriteVal(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -355,7 +292,7 @@ func Test_write_uint32(t *testing.T) {
} }
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 10) stream := NewStream(buf, 10)
stream.WriteRaw("a") stream.WriteRaw("a")
stream.WriteUint32(0xffffffff) // should clear buffer stream.WriteUint32(0xffffffff) // should clear buffer
stream.Flush() stream.Flush()
@ -369,7 +306,7 @@ func Test_write_int32(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteInt32(val) stream.WriteInt32(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -378,7 +315,7 @@ func Test_write_int32(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(val) stream.WriteVal(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -387,7 +324,7 @@ func Test_write_int32(t *testing.T) {
} }
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 11) stream := NewStream(buf, 11)
stream.WriteRaw("a") stream.WriteRaw("a")
stream.WriteInt32(-0x7fffffff) // should clear buffer stream.WriteInt32(-0x7fffffff) // should clear buffer
stream.Flush() stream.Flush()
@ -403,7 +340,7 @@ func Test_write_uint64(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteUint64(val) stream.WriteUint64(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -412,7 +349,7 @@ func Test_write_uint64(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(val) stream.WriteVal(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -421,7 +358,7 @@ func Test_write_uint64(t *testing.T) {
} }
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 10) stream := NewStream(buf, 10)
stream.WriteRaw("a") stream.WriteRaw("a")
stream.WriteUint64(0xffffffff) // should clear buffer stream.WriteUint64(0xffffffff) // should clear buffer
stream.Flush() stream.Flush()
@ -437,7 +374,7 @@ func Test_write_int64(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteInt64(val) stream.WriteInt64(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -446,7 +383,7 @@ func Test_write_int64(t *testing.T) {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) { t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(val) stream.WriteVal(val)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -455,7 +392,7 @@ func Test_write_int64(t *testing.T) {
} }
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 10) stream := NewStream(buf, 10)
stream.WriteRaw("a") stream.WriteRaw("a")
stream.WriteInt64(0xffffffff) // should clear buffer stream.WriteInt64(0xffffffff) // should clear buffer
stream.Flush() stream.Flush()
@ -466,7 +403,7 @@ func Test_write_int64(t *testing.T) {
func Test_write_val_int(t *testing.T) { func Test_write_val_int(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal(1001) stream.WriteVal(1001)
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -476,7 +413,7 @@ func Test_write_val_int(t *testing.T) {
func Test_write_val_int_ptr(t *testing.T) { func Test_write_val_int_ptr(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
val := 1001 val := 1001
stream.WriteVal(&val) stream.WriteVal(&val)
stream.Flush() stream.Flush()
@ -495,19 +432,8 @@ func Test_json_number(t *testing.T) {
should.Equal(`[1]`, str) should.Equal(`[1]`, str)
} }
func Test_jsoniter_number(t *testing.T) {
should := require.New(t)
var arr []Number
err := Unmarshal([]byte(`[1]`), &arr)
should.Nil(err)
should.Equal(Number("1"), arr[0])
str, isNumber := CastJsonNumber(arr[0])
should.True(isNumber)
should.Equal("1", str)
}
func Benchmark_jsoniter_encode_int(b *testing.B) { func Benchmark_jsoniter_encode_int(b *testing.B) {
stream := NewStream(ConfigDefault, ioutil.Discard, 64) stream := NewStream(ioutil.Discard, 64)
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
stream.n = 0 stream.n = 0
stream.WriteUint64(0xffffffff) stream.WriteUint64(0xffffffff)
@ -521,7 +447,7 @@ func Benchmark_itoa(b *testing.B) {
} }
func Benchmark_jsoniter_int(b *testing.B) { func Benchmark_jsoniter_int(b *testing.B) {
iter := NewIterator(ConfigDefault) iter := NewIterator()
input := []byte(`100`) input := []byte(`100`)
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter.ResetBytes(input) iter.ResetBytes(input)

View File

@ -1,12 +1,10 @@
package jsoniter package jsoniter
import ( import (
"encoding/json" "github.com/json-iterator/go/require"
"fmt"
"testing" "testing"
"unsafe" "unsafe"
"encoding/json"
"github.com/stretchr/testify/require"
) )
func Test_write_array_of_interface(t *testing.T) { func Test_write_array_of_interface(t *testing.T) {
@ -83,21 +81,12 @@ func Test_read_interface(t *testing.T) {
err := UnmarshalFromString(`"hello"`, &val) err := UnmarshalFromString(`"hello"`, &val)
should.Nil(err) should.Nil(err)
should.Equal("hello", val) should.Equal("hello", val)
err = UnmarshalFromString(`1e1`, &val)
should.Nil(err)
should.Equal(float64(10), val)
err = UnmarshalFromString(`1.0e1`, &val)
should.Nil(err)
should.Equal(float64(10), val)
err = json.Unmarshal([]byte(`1.0e1`), &val)
should.Nil(err)
should.Equal(float64(10), val)
} }
func Test_read_custom_interface(t *testing.T) { func Test_read_custom_interface(t *testing.T) {
should := require.New(t) should := require.New(t)
var val MyInterface var val MyInterface
RegisterTypeDecoderFunc("jsoniter.MyInterface", func(ptr unsafe.Pointer, iter *Iterator) { RegisterTypeDecoder("jsoniter.MyInterface", func(ptr unsafe.Pointer, iter *Iterator) {
*((*MyInterface)(ptr)) = MyString(iter.ReadString()) *((*MyInterface)(ptr)) = MyString(iter.ReadString())
}) })
err := UnmarshalFromString(`"hello"`, &val) err := UnmarshalFromString(`"hello"`, &val)
@ -151,9 +140,10 @@ func Test_encode_object_contain_non_empty_interface(t *testing.T) {
should.Equal(`{"Field":"hello"}`, str) should.Equal(`{"Field":"hello"}`, str)
} }
func Test_nil_non_empty_interface(t *testing.T) { func Test_nil_non_empty_interface(t *testing.T) {
ConfigDefault.(*frozenConfig).cleanEncoders() CleanEncoders()
ConfigDefault.(*frozenConfig).cleanDecoders() CleanDecoders()
type TestObject struct { type TestObject struct {
Field []MyInterface Field []MyInterface
} }
@ -162,399 +152,4 @@ func Test_nil_non_empty_interface(t *testing.T) {
b := []byte(`{"Field":["AAA"]}`) b := []byte(`{"Field":["AAA"]}`)
should.NotNil(json.Unmarshal(b, &obj)) should.NotNil(json.Unmarshal(b, &obj))
should.NotNil(Unmarshal(b, &obj)) should.NotNil(Unmarshal(b, &obj))
} }
func Test_read_large_number_as_interface(t *testing.T) {
should := require.New(t)
var val interface{}
err := Config{UseNumber: true}.Froze().UnmarshalFromString(`123456789123456789123456789`, &val)
should.Nil(err)
output, err := MarshalToString(val)
should.Nil(err)
should.Equal(`123456789123456789123456789`, output)
}
func Test_nested_one_field_struct(t *testing.T) {
should := require.New(t)
type YetYetAnotherObject struct {
Field string
}
type YetAnotherObject struct {
Field *YetYetAnotherObject
}
type AnotherObject struct {
Field *YetAnotherObject
}
type TestObject struct {
Me *AnotherObject
}
obj := TestObject{&AnotherObject{&YetAnotherObject{&YetYetAnotherObject{"abc"}}}}
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
str, err = MarshalToString(&obj)
should.Nil(err)
should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
}
func Test_struct_with_embedded_ptr_with_tag(t *testing.T) {
type O1 struct {
O1F string
}
type Option struct {
O1 *O1
}
type T struct {
Option `json:","`
}
var obj T
should := require.New(t)
output, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"O1":null}`, output)
}
func Test_struct_with_one_nil(t *testing.T) {
type TestObject struct {
F *float64
}
var obj TestObject
should := require.New(t)
output, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"F":null}`, output)
}
func Test_struct_with_one_nil_embedded(t *testing.T) {
type Parent struct {
Field1 string
Field2 string
}
type TestObject struct {
*Parent
}
obj := TestObject{}
should := require.New(t)
bytes, err := json.Marshal(obj)
should.Nil(err)
should.Equal("{}", string(bytes))
output, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{}`, output)
}
func Test_struct_with_not_nil_embedded(t *testing.T) {
type Parent struct {
Field0 string
Field1 []string
Field2 map[string]interface{}
}
type TestObject struct {
*Parent
}
should := require.New(t)
var obj TestObject
err := UnmarshalFromString(`{"Field0":"1","Field1":null,"Field2":{"K":"V"}}`, &obj)
should.Nil(err)
should.Nil(obj.Field1)
should.Equal(map[string]interface{}{"K": "V"}, obj.Field2)
should.Equal("1", obj.Field0)
}
func Test_array_with_one_nil_ptr(t *testing.T) {
obj := [1]*float64{nil}
should := require.New(t)
output, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`[null]`, output)
}
func Test_array_with_one_not_nil_ptr(t *testing.T) {
two := float64(2)
obj := [1]*float64{&two}
should := require.New(t)
output, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`[2]`, output)
}
func Test_embedded_array_with_one_nil(t *testing.T) {
type TestObject struct {
Field1 int
Field2 [1]*float64
}
var obj TestObject
should := require.New(t)
output, err := MarshalToString(obj)
should.Nil(err)
should.Contains(output, `"Field2":[null]`)
}
func Test_array_with_nothing(t *testing.T) {
var obj [2]*float64
should := require.New(t)
output, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`[null,null]`, output)
}
func Test_unmarshal_ptr_to_interface(t *testing.T) {
type TestData struct {
Name string `json:"name"`
}
should := require.New(t)
var obj interface{} = &TestData{}
err := json.Unmarshal([]byte(`{"name":"value"}`), &obj)
should.Nil(err)
should.Equal("&{value}", fmt.Sprintf("%v", obj))
obj = interface{}(&TestData{})
err = Unmarshal([]byte(`{"name":"value"}`), &obj)
should.Nil(err)
should.Equal("&{value}", fmt.Sprintf("%v", obj))
}
func Test_nil_out_null_interface(t *testing.T) {
type TestData struct {
Field interface{} `json:"field"`
}
should := require.New(t)
var boolVar bool
obj := TestData{
Field: &boolVar,
}
data1 := []byte(`{"field": true}`)
err := Unmarshal(data1, &obj)
should.NoError(err)
should.Equal(true, *(obj.Field.(*bool)))
data2 := []byte(`{"field": null}`)
err = Unmarshal(data2, &obj)
should.NoError(err)
should.Equal(nil, obj.Field)
// Checking stdlib behavior matches.
obj2 := TestData{
Field: &boolVar,
}
err = json.Unmarshal(data1, &obj2)
should.NoError(err)
should.Equal(true, *(obj2.Field.(*bool)))
err = json.Unmarshal(data2, &obj2)
should.NoError(err)
should.Equal(nil, obj2.Field)
}
func Test_omitempty_nil_interface(t *testing.T) {
type TestData struct {
Field interface{} `json:"field,omitempty"`
}
should := require.New(t)
obj := TestData{
Field: nil,
}
js, err := json.Marshal(obj)
should.NoError(err)
should.Equal("{}", string(js))
str, err := MarshalToString(obj)
should.NoError(err)
should.Equal(string(js), str)
}
func Test_omitempty_nil_nonempty_interface(t *testing.T) {
type TestData struct {
Field MyInterface `json:"field,omitempty"`
}
should := require.New(t)
obj := TestData{
Field: nil,
}
js, err := json.Marshal(obj)
should.NoError(err)
should.Equal("{}", string(js))
str, err := MarshalToString(obj)
should.NoError(err)
should.Equal(string(js), str)
obj.Field = MyString("hello")
err = UnmarshalFromString(`{"field":null}`, &obj)
should.NoError(err)
should.Equal(nil, obj.Field)
}
func Test_marshal_nil_marshaler_interface(t *testing.T) {
type TestData struct {
Field json.Marshaler `json:"field"`
}
should := require.New(t)
obj := TestData{
Field: nil,
}
js, err := json.Marshal(obj)
should.NoError(err)
should.Equal(`{"field":null}`, string(js))
str, err := MarshalToString(obj)
should.NoError(err)
should.Equal(string(js), str)
}
func Test_marshal_nil_nonempty_interface(t *testing.T) {
type TestData struct {
Field MyInterface `json:"field"`
}
should := require.New(t)
obj := TestData{
Field: nil,
}
js, err := json.Marshal(obj)
should.NoError(err)
should.Equal(`{"field":null}`, string(js))
str, err := MarshalToString(obj)
should.NoError(err)
should.Equal(string(js), str)
obj.Field = MyString("hello")
err = Unmarshal(js, &obj)
should.NoError(err)
should.Equal(nil, obj.Field)
}
func Test_overwrite_interface_ptr_value_with_nil(t *testing.T) {
type Wrapper struct {
Payload interface{} `json:"payload,omitempty"`
}
type Payload struct {
Value int `json:"val,omitempty"`
}
should := require.New(t)
payload := &Payload{}
wrapper := &Wrapper{
Payload: &payload,
}
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Equal(nil, err)
should.Equal(&payload, wrapper.Payload)
should.Equal(42, (*(wrapper.Payload.(**Payload))).Value)
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Equal(nil, err)
should.Equal(&payload, wrapper.Payload)
should.Equal((*Payload)(nil), payload)
payload = &Payload{}
wrapper = &Wrapper{
Payload: &payload,
}
err = Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Equal(nil, err)
should.Equal(&payload, wrapper.Payload)
should.Equal(42, (*(wrapper.Payload.(**Payload))).Value)
err = Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Equal(nil, err)
should.Equal(&payload, wrapper.Payload)
should.Equal((*Payload)(nil), payload)
}
func Test_overwrite_interface_value_with_nil(t *testing.T) {
type Wrapper struct {
Payload interface{} `json:"payload,omitempty"`
}
type Payload struct {
Value int `json:"val,omitempty"`
}
should := require.New(t)
payload := &Payload{}
wrapper := &Wrapper{
Payload: payload,
}
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Equal(nil, err)
should.Equal(42, (*(wrapper.Payload.(*Payload))).Value)
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Equal(nil, err)
should.Equal(nil, wrapper.Payload)
should.Equal(42, payload.Value)
payload = &Payload{}
wrapper = &Wrapper{
Payload: payload,
}
err = Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Equal(nil, err)
should.Equal(42, (*(wrapper.Payload.(*Payload))).Value)
err = Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Equal(nil, err)
should.Equal(nil, wrapper.Payload)
should.Equal(42, payload.Value)
}
func Test_unmarshal_into_nil(t *testing.T) {
type Payload struct {
Value int `json:"val,omitempty"`
}
type Wrapper struct {
Payload interface{} `json:"payload,omitempty"`
}
should := require.New(t)
var payload *Payload
wrapper := &Wrapper{
Payload: payload,
}
err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Nil(err)
should.NotNil(wrapper.Payload)
should.Nil(payload)
err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Nil(err)
should.Nil(wrapper.Payload)
should.Nil(payload)
payload = nil
wrapper = &Wrapper{
Payload: payload,
}
err = Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
should.Nil(err)
should.NotNil(wrapper.Payload)
should.Nil(payload)
err = Unmarshal([]byte(`{"payload": null}`), &wrapper)
should.Nil(err)
should.Nil(wrapper.Payload)
should.Nil(payload)
}

View File

@ -1,132 +0,0 @@
package jsoniter
import (
"bytes"
"encoding/json"
"github.com/stretchr/testify/require"
"io"
"testing"
)
func Test_missing_object_end(t *testing.T) {
should := require.New(t)
type TestObject struct {
Metric string `json:"metric"`
Tags map[string]interface{} `json:"tags"`
}
obj := TestObject{}
should.NotNil(UnmarshalFromString(`{"metric": "sys.777","tags": {"a":"123"}`, &obj))
}
func Test_missing_array_end(t *testing.T) {
should := require.New(t)
should.NotNil(UnmarshalFromString(`[1,2,3`, &[]int{}))
}
func Test_invalid_any(t *testing.T) {
should := require.New(t)
any := Get([]byte("[]"))
should.Equal(InvalidValue, any.Get(0.3).ValueType())
// is nil correct ?
should.Equal(nil, any.Get(0.3).GetInterface())
any = any.Get(0.3)
should.Equal(false, any.ToBool())
should.Equal(int(0), any.ToInt())
should.Equal(int32(0), any.ToInt32())
should.Equal(int64(0), any.ToInt64())
should.Equal(uint(0), any.ToUint())
should.Equal(uint32(0), any.ToUint32())
should.Equal(uint64(0), any.ToUint64())
should.Equal(float32(0), any.ToFloat32())
should.Equal(float64(0), any.ToFloat64())
should.Equal("", any.ToString())
should.Equal(InvalidValue, any.Get(0.1).Get(1).ValueType())
}
func Test_invalid_struct_input(t *testing.T) {
should := require.New(t)
type TestObject struct{}
input := []byte{54, 141, 30}
obj := TestObject{}
should.NotNil(Unmarshal(input, &obj))
}
func Test_invalid_slice_input(t *testing.T) {
should := require.New(t)
type TestObject struct{}
input := []byte{93}
obj := []string{}
should.NotNil(Unmarshal(input, &obj))
}
func Test_invalid_array_input(t *testing.T) {
should := require.New(t)
type TestObject struct{}
input := []byte{93}
obj := [0]string{}
should.NotNil(Unmarshal(input, &obj))
}
func Test_invalid_float(t *testing.T) {
inputs := []string{
`1.e1`, // dot without following digit
`1.`, // dot can not be the last char
``, // empty number
`01`, // extra leading zero
`-`, // negative without digit
`--`, // double negative
`--2`, // double negative
}
for _, input := range inputs {
t.Run(input, func(t *testing.T) {
should := require.New(t)
iter := ParseString(ConfigDefault, input+",")
iter.Skip()
should.NotEqual(io.EOF, iter.Error)
should.NotNil(iter.Error)
v := float64(0)
should.NotNil(json.Unmarshal([]byte(input), &v))
iter = ParseString(ConfigDefault, input+",")
iter.ReadFloat64()
should.NotEqual(io.EOF, iter.Error)
should.NotNil(iter.Error)
iter = ParseString(ConfigDefault, input+",")
iter.ReadFloat32()
should.NotEqual(io.EOF, iter.Error)
should.NotNil(iter.Error)
})
}
}
func Test_chan(t *testing.T) {
t.Skip("do not support chan")
type TestObject struct {
MyChan chan bool
MyField int
}
should := require.New(t)
obj := TestObject{}
str, err := json.Marshal(obj)
should.Nil(err)
should.Equal(``, str)
}
func Test_invalid_number(t *testing.T) {
type Message struct {
Number int `json:"number"`
}
obj := Message{}
decoder := ConfigCompatibleWithStandardLibrary.NewDecoder(bytes.NewBufferString(`{"number":"5"}`))
err := decoder.Decode(&obj)
invalidStr := err.Error()
result, err := ConfigCompatibleWithStandardLibrary.Marshal(invalidStr)
should := require.New(t)
should.Nil(err)
result2, err := json.Marshal(invalidStr)
should.Nil(err)
should.Equal(string(result2), string(result))
}

View File

@ -2,13 +2,12 @@ package jsoniter
import ( import (
"bytes" "bytes"
"github.com/stretchr/testify/require"
"io" "io"
"testing" "testing"
) )
func Test_read_by_one(t *testing.T) { func Test_read_by_one(t *testing.T) {
iter := Parse(ConfigDefault, bytes.NewBufferString("abc"), 1) iter := Parse(bytes.NewBufferString("abc"), 1)
b := iter.readByte() b := iter.readByte()
if iter.Error != nil { if iter.Error != nil {
t.Fatal(iter.Error) t.Fatal(iter.Error)
@ -20,6 +19,11 @@ func Test_read_by_one(t *testing.T) {
if iter.Error != nil { if iter.Error != nil {
t.Fatal(iter.Error) t.Fatal(iter.Error)
} }
iter.unreadByte()
if iter.Error == nil {
t.FailNow()
}
iter.Error = nil
b = iter.readByte() b = iter.readByte()
if iter.Error != nil { if iter.Error != nil {
t.Fatal(iter.Error) t.Fatal(iter.Error)
@ -30,25 +34,40 @@ func Test_read_by_one(t *testing.T) {
} }
func Test_read_by_two(t *testing.T) { func Test_read_by_two(t *testing.T) {
should := require.New(t) iter := Parse(bytes.NewBufferString("abc"), 2)
iter := Parse(ConfigDefault, bytes.NewBufferString("abc"), 2)
b := iter.readByte() b := iter.readByte()
should.Nil(iter.Error) if iter.Error != nil {
should.Equal(byte('a'), b) t.Fatal(iter.Error)
}
if b != 'a' {
t.Fatal(b)
}
b = iter.readByte() b = iter.readByte()
should.Nil(iter.Error) if iter.Error != nil {
should.Equal(byte('b'), b) t.Fatal(iter.Error)
}
if b != 'b' {
t.Fatal(b)
}
iter.unreadByte() iter.unreadByte()
should.Nil(iter.Error) if iter.Error != nil {
t.Fatal(iter.Error)
}
iter.unreadByte() iter.unreadByte()
should.Nil(iter.Error) if iter.Error != nil {
t.Fatal(iter.Error)
}
b = iter.readByte() b = iter.readByte()
should.Nil(iter.Error) if iter.Error != nil {
should.Equal(byte('a'), b) t.Fatal(iter.Error)
}
if b != 'a' {
t.Fatal(b)
}
} }
func Test_read_until_eof(t *testing.T) { func Test_read_until_eof(t *testing.T) {
iter := Parse(ConfigDefault, bytes.NewBufferString("abc"), 2) iter := Parse(bytes.NewBufferString("abc"), 2)
iter.readByte() iter.readByte()
iter.readByte() iter.readByte()
b := iter.readByte() b := iter.readByte()

View File

@ -23,122 +23,17 @@ import (
// } // }
//} //}
func init() {
ioutil.WriteFile("/tmp/large-file.json", []byte(`[{
"person": {
"id": "d50887ca-a6ce-4e59-b89f-14f0b5d03b03",
"name": {
"fullName": "Leonid Bugaev",
"givenName": "Leonid",
"familyName": "Bugaev"
},
"email": "leonsbox@gmail.com",
"gender": "male",
"location": "Saint Petersburg, Saint Petersburg, RU",
"geo": {
"city": "Saint Petersburg",
"state": "Saint Petersburg",
"country": "Russia",
"lat": 59.9342802,
"lng": 30.3350986
},
"bio": "Senior engineer at Granify.com",
"site": "http://flickfaver.com",
"avatar": "https://d1ts43dypk8bqh.cloudfront.net/v1/avatars/d50887ca-a6ce-4e59-b89f-14f0b5d03b03",
"employment": {
"name": "www.latera.ru",
"title": "Software Engineer",
"domain": "gmail.com"
},
"facebook": {
"handle": "leonid.bugaev"
},
"github": {
"handle": "buger",
"id": 14009,
"avatar": "https://avatars.githubusercontent.com/u/14009?v=3",
"company": "Granify",
"blog": "http://leonsbox.com",
"followers": 95,
"following": 10
},
"twitter": {
"handle": "flickfaver",
"id": 77004410,
"bio": null,
"followers": 2,
"following": 1,
"statuses": 5,
"favorites": 0,
"location": "",
"site": "http://flickfaver.com",
"avatar": null
},
"linkedin": {
"handle": "in/leonidbugaev"
},
"googleplus": {
"handle": null
},
"angellist": {
"handle": "leonid-bugaev",
"id": 61541,
"bio": "Senior engineer at Granify.com",
"blog": "http://buger.github.com",
"site": "http://buger.github.com",
"followers": 41,
"avatar": "https://d1qb2nb5cznatu.cloudfront.net/users/61541-medium_jpg?1405474390"
},
"klout": {
"handle": null,
"score": null
},
"foursquare": {
"handle": null
},
"aboutme": {
"handle": "leonid.bugaev",
"bio": null,
"avatar": null
},
"gravatar": {
"handle": "buger",
"urls": [
],
"avatar": "http://1.gravatar.com/avatar/f7c8edd577d13b8930d5522f28123510",
"avatars": [
{
"url": "http://1.gravatar.com/avatar/f7c8edd577d13b8930d5522f28123510",
"type": "thumbnail"
}
]
},
"fuzzy": false
},
"company": "hello"
}]`), 0666)
}
/*
200000 8886 ns/op 4336 B/op 6 allocs/op
50000 34244 ns/op 6744 B/op 14 allocs/op
*/
func Benchmark_jsoniter_large_file(b *testing.B) { func Benchmark_jsoniter_large_file(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
file, _ := os.Open("/tmp/large-file.json") file, _ := os.Open("/tmp/large-file.json")
iter := Parse(ConfigDefault, file, 4096) iter := Parse(file, 4096)
count := 0 count := 0
iter.ReadArrayCB(func(iter *Iterator) bool { for iter.ReadArray() {
// Skip() is strict by default, use --tags jsoniter-sloppy to skip without validation
iter.Skip() iter.Skip()
count++ count++
return true
})
file.Close()
if iter.Error != nil {
b.Error(iter.Error)
} }
file.Close()
} }
} }
@ -149,9 +44,6 @@ func Benchmark_json_large_file(b *testing.B) {
bytes, _ := ioutil.ReadAll(file) bytes, _ := ioutil.ReadAll(file)
file.Close() file.Close()
result := []struct{}{} result := []struct{}{}
err := json.Unmarshal(bytes, &result) json.Unmarshal(bytes, &result)
if err != nil {
b.Error(err)
}
} }
} }

View File

@ -1,17 +1,15 @@
package jsoniter package jsoniter
import ( import (
"encoding/json" "github.com/json-iterator/go/require"
"math/big" "math/big"
"testing" "testing"
"encoding/json"
"github.com/stretchr/testify/require"
"strings"
) )
func Test_read_map(t *testing.T) { func Test_read_map(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `{"hello": "world"}`) iter := ParseString(`{"hello": "world"}`)
m := map[string]string{"1": "2"} m := map[string]string{"1": "2"}
iter.ReadVal(&m) iter.ReadVal(&m)
copy(iter.buf, []byte{0, 0, 0, 0, 0, 0}) copy(iter.buf, []byte{0, 0, 0, 0, 0, 0})
@ -20,25 +18,37 @@ func Test_read_map(t *testing.T) {
func Test_read_map_of_interface(t *testing.T) { func Test_read_map_of_interface(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `{"hello": "world"}`) iter := ParseString(`{"hello": "world"}`)
m := map[string]interface{}{"1": "2"} m := map[string]interface{}{"1": "2"}
iter.ReadVal(&m) iter.ReadVal(&m)
should.Equal(map[string]interface{}{"1": "2", "hello": "world"}, m) should.Equal(map[string]interface{}{"1": "2", "hello": "world"}, m)
iter = ParseString(ConfigDefault, `{"hello": "world"}`) iter = ParseString(`{"hello": "world"}`)
should.Equal(map[string]interface{}{"hello": "world"}, iter.Read()) should.Equal(map[string]interface{}{"hello": "world"}, iter.Read())
} }
func Test_wrap_map(t *testing.T) {
should := require.New(t)
any := Wrap(map[string]string{"Field1": "hello"})
should.Equal("hello", any.Get("Field1").ToString())
any = Wrap(map[string]string{"Field1": "hello"})
should.Equal(1, any.Size())
any = Wrap(map[string]string{"Field1": "hello"})
vals := map[string]string{}
var k string
var v Any
for next, hasNext := any.IterateObject(); hasNext; {
k, v, hasNext = next()
if v.ValueType() == String {
vals[k] = v.ToString()
}
}
should.Equal(map[string]string{"Field1": "hello"}, vals)
}
func Test_map_wrapper_any_get_all(t *testing.T) { func Test_map_wrapper_any_get_all(t *testing.T) {
should := require.New(t) should := require.New(t)
any := Wrap(map[string][]int{"Field1": {1, 2}}) any := Wrap(map[string][]int{"Field1": {1, 2}})
should.Equal(`{"Field1":1}`, any.Get('*', 0).ToString()) should.Equal(`{"Field1":1}`, any.Get('*', 0).ToString())
should.Contains(any.Keys(), "Field1")
// map write to
stream := NewStream(ConfigDefault, nil, 0)
any.WriteTo(stream)
// TODO cannot pass
//should.Equal(string(stream.buf), "")
} }
func Test_write_val_map(t *testing.T) { func Test_write_val_map(t *testing.T) {
@ -93,6 +103,8 @@ func Test_decode_TextMarshaler_key_map(t *testing.T) {
should.Equal(`{"1":"2"}`, str) should.Equal(`{"1":"2"}`, str)
} }
func Test_map_key_with_escaped_char(t *testing.T) { func Test_map_key_with_escaped_char(t *testing.T) {
type Ttest struct { type Ttest struct {
Map map[string]string Map map[string]string
@ -107,54 +119,11 @@ func Test_map_key_with_escaped_char(t *testing.T) {
{ {
var obj Ttest var obj Ttest
should.Nil(json.Unmarshal(jsonBytes, &obj)) should.Nil(json.Unmarshal(jsonBytes, &obj))
should.Equal(map[string]string{"k\"ey": "val"}, obj.Map) should.Equal(map[string]string{"k\"ey":"val"}, obj.Map)
} }
{ {
var obj Ttest var obj Ttest
should.Nil(Unmarshal(jsonBytes, &obj)) should.Nil(Unmarshal(jsonBytes, &obj))
should.Equal(map[string]string{"k\"ey": "val"}, obj.Map) should.Equal(map[string]string{"k\"ey":"val"}, obj.Map)
} }
} }
func Test_encode_map_with_sorted_keys(t *testing.T) {
should := require.New(t)
m := map[string]interface{}{
"3": 3,
"1": 1,
"2": 2,
}
bytes, err := json.Marshal(m)
should.Nil(err)
output, err := ConfigCompatibleWithStandardLibrary.MarshalToString(m)
should.Nil(err)
should.Equal(string(bytes), output)
}
func Test_encode_map_uint_keys(t *testing.T) {
should := require.New(t)
m := map[uint64]interface{}{
uint64(1): "a",
uint64(2): "a",
uint64(4): "a",
}
bytes, err := json.Marshal(m)
should.Nil(err)
output, err := ConfigCompatibleWithStandardLibrary.MarshalToString(m)
should.Nil(err)
should.Equal(string(bytes), output)
}
func Test_read_map_with_reader(t *testing.T) {
should := require.New(t)
input := `{"branch":"beta","change_log":"add the rows{10}","channel":"fros","create_time":"2017-06-13 16:39:08","firmware_list":"","md5":"80dee2bf7305bcf179582088e29fd7b9","note":{"CoreServices":{"md5":"d26975c0a8c7369f70ed699f2855cc2e","package_name":"CoreServices","version_code":"76","version_name":"1.0.76"},"FrDaemon":{"md5":"6b1f0626673200bc2157422cd2103f5d","package_name":"FrDaemon","version_code":"390","version_name":"1.0.390"},"FrGallery":{"md5":"90d767f0f31bcd3c1d27281ec979ba65","package_name":"FrGallery","version_code":"349","version_name":"1.0.349"},"FrLocal":{"md5":"f15a215b2c070a80a01f07bde4f219eb","package_name":"FrLocal","version_code":"791","version_name":"1.0.791"}},"pack_region_urls":{"CN":"https://s3.cn-north-1.amazonaws.com.cn/xxx-os/ttt_xxx_android_1.5.3.344.393.zip","default":"http://192.168.8.78/ttt_xxx_android_1.5.3.344.393.zip","local":"http://192.168.8.78/ttt_xxx_android_1.5.3.344.393.zip"},"pack_version":"1.5.3.344.393","pack_version_code":393,"region":"all","release_flag":0,"revision":62,"size":38966875,"status":3}`
reader := strings.NewReader(input)
decoder := ConfigCompatibleWithStandardLibrary.NewDecoder(reader)
m1 := map[string]interface{}{}
should.Nil(decoder.Decode(&m1))
m2 := map[string]interface{}{}
should.Nil(json.Unmarshal([]byte(input), &m2))
should.Equal(m2, m1)
should.Equal("1.0.76", m1["note"].(map[string]interface{})["CoreServices"].(map[string]interface{})["version_name"])
}

View File

@ -1,71 +0,0 @@
package jsoniter
import (
"testing"
"github.com/stretchr/testify/require"
)
// if must be valid is useless, just drop this test
func Test_must_be_valid(t *testing.T) {
should := require.New(t)
any := Get([]byte("123"))
should.Equal(any.MustBeValid().ToInt(), 123)
any = Wrap(int8(10))
should.Equal(any.MustBeValid().ToInt(), 10)
any = Wrap(int16(10))
should.Equal(any.MustBeValid().ToInt(), 10)
any = Wrap(int32(10))
should.Equal(any.MustBeValid().ToInt(), 10)
any = Wrap(int64(10))
should.Equal(any.MustBeValid().ToInt(), 10)
any = Wrap(uint(10))
should.Equal(any.MustBeValid().ToInt(), 10)
any = Wrap(uint8(10))
should.Equal(any.MustBeValid().ToInt(), 10)
any = Wrap(uint16(10))
should.Equal(any.MustBeValid().ToInt(), 10)
any = Wrap(uint32(10))
should.Equal(any.MustBeValid().ToInt(), 10)
any = Wrap(uint64(10))
should.Equal(any.MustBeValid().ToInt(), 10)
any = Wrap(float32(10))
should.Equal(any.MustBeValid().ToFloat64(), float64(10))
any = Wrap(float64(10))
should.Equal(any.MustBeValid().ToFloat64(), float64(10))
any = Wrap(true)
should.Equal(any.MustBeValid().ToFloat64(), float64(1))
any = Wrap(false)
should.Equal(any.MustBeValid().ToFloat64(), float64(0))
any = Wrap(nil)
should.Equal(any.MustBeValid().ToFloat64(), float64(0))
any = Wrap(struct{ age int }{age: 1})
should.Equal(any.MustBeValid().ToFloat64(), float64(0))
any = Wrap(map[string]interface{}{"abc": 1})
should.Equal(any.MustBeValid().ToFloat64(), float64(0))
any = Wrap("abc")
should.Equal(any.MustBeValid().ToFloat64(), float64(0))
any = Wrap([]int{})
should.Equal(any.MustBeValid().ToFloat64(), float64(0))
any = Wrap([]int{1, 2})
should.Equal(any.MustBeValid().ToFloat64(), float64(1))
}

View File

@ -15,7 +15,7 @@ type Level2 struct {
} }
func Test_nested(t *testing.T) { func Test_nested(t *testing.T) {
iter := ParseString(ConfigDefault, `{"hello": [{"world": "value1"}, {"world": "value2"}]}`) iter := ParseString(`{"hello": [{"world": "value1"}, {"world": "value2"}]}`)
l1 := Level1{} l1 := Level1{}
for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() { for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
switch l1Field { switch l1Field {
@ -28,14 +28,14 @@ func Test_nested(t *testing.T) {
case "world": case "world":
l2.World = iter.ReadString() l2.World = iter.ReadString()
default: default:
iter.ReportError("bind l2", "unexpected field: "+l2Field) iter.reportError("bind l2", "unexpected field: "+l2Field)
} }
} }
l2Array = append(l2Array, l2) l2Array = append(l2Array, l2)
} }
l1.Hello = l2Array l1.Hello = l2Array
default: default:
iter.ReportError("bind l1", "unexpected field: "+l1Field) iter.reportError("bind l1", "unexpected field: "+l1Field)
} }
} }
if !reflect.DeepEqual(l1, Level1{ if !reflect.DeepEqual(l1, Level1{
@ -50,7 +50,7 @@ func Test_nested(t *testing.T) {
func Benchmark_jsoniter_nested(b *testing.B) { func Benchmark_jsoniter_nested(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter := ParseString(ConfigDefault, `{"hello": [{"world": "value1"}, {"world": "value2"}]}`) iter := ParseString(`{"hello": [{"world": "value1"}, {"world": "value2"}]}`)
l1 := Level1{} l1 := Level1{}
for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() { for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
switch l1Field { switch l1Field {

View File

@ -2,31 +2,29 @@ package jsoniter
import ( import (
"bytes" "bytes"
"encoding/json" "github.com/json-iterator/go/require"
"io"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func Test_read_null(t *testing.T) { func Test_read_null(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `null`) iter := ParseString(`null`)
should.True(iter.ReadNil()) should.True(iter.ReadNil())
iter = ParseString(ConfigDefault, `null`) iter = ParseString(`null`)
should.Nil(iter.Read()) should.Nil(iter.Read())
iter = ParseString(ConfigDefault, `navy`) iter = ParseString(`null`)
iter.Read() any, err := UnmarshalAnyFromString(`null`)
should.True(iter.Error != nil && iter.Error != io.EOF) should.Nil(err)
iter = ParseString(ConfigDefault, `navy`) should.Equal(0, any.ToInt())
iter.ReadNil() should.Equal(float64(0), any.ToFloat64())
should.True(iter.Error != nil && iter.Error != io.EOF) should.Equal("", any.ToString())
should.False(any.ToBool())
} }
func Test_write_null(t *testing.T) { func Test_write_null(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteNil() stream.WriteNil()
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -40,9 +38,9 @@ func Test_encode_null(t *testing.T) {
should.Equal("null", str) should.Equal("null", str)
} }
func Test_decode_null_object_field(t *testing.T) { func Test_decode_null_object(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `[null,"a"]`) iter := ParseString(`[null,"a"]`)
iter.ReadArray() iter.ReadArray()
if iter.ReadObject() != "" { if iter.ReadObject() != "" {
t.FailNow() t.FailNow()
@ -59,32 +57,21 @@ func Test_decode_null_object_field(t *testing.T) {
should.Len(objs, 1) should.Len(objs, 1)
} }
func Test_decode_null_array_element(t *testing.T) {
should := require.New(t)
iter := ParseString(ConfigDefault, `[null,"a"]`)
should.True(iter.ReadArray())
should.True(iter.ReadNil())
should.True(iter.ReadArray())
should.Equal("a", iter.ReadString())
}
func Test_decode_null_array(t *testing.T) { func Test_decode_null_array(t *testing.T) {
should := require.New(t) iter := ParseString(`[null,"a"]`)
arr := []string{} iter.ReadArray()
should.Nil(UnmarshalFromString("null", &arr)) if iter.ReadArray() != false {
should.Nil(arr) t.FailNow()
} }
iter.ReadArray()
func Test_decode_null_map(t *testing.T) { if iter.ReadString() != "a" {
should := require.New(t) t.FailNow()
arr := map[string]string{} }
should.Nil(UnmarshalFromString("null", &arr))
should.Nil(arr)
} }
func Test_decode_null_string(t *testing.T) { func Test_decode_null_string(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `[null,"a"]`) iter := ParseString(`[null,"a"]`)
should.True(iter.ReadArray()) should.True(iter.ReadArray())
should.Equal("", iter.ReadString()) should.Equal("", iter.ReadString())
should.True(iter.ReadArray()) should.True(iter.ReadArray())
@ -92,7 +79,7 @@ func Test_decode_null_string(t *testing.T) {
} }
func Test_decode_null_skip(t *testing.T) { func Test_decode_null_skip(t *testing.T) {
iter := ParseString(ConfigDefault, `[null,"a"]`) iter := ParseString(`[null,"a"]`)
iter.ReadArray() iter.ReadArray()
iter.Skip() iter.Skip()
iter.ReadArray() iter.ReadArray()
@ -100,69 +87,3 @@ func Test_decode_null_skip(t *testing.T) {
t.FailNow() t.FailNow()
} }
} }
func Test_encode_nil_map(t *testing.T) {
should := require.New(t)
type Ttest map[string]string
var obj1 Ttest
output, err := json.Marshal(obj1)
should.Nil(err)
should.Equal("null", string(output))
output, err = json.Marshal(&obj1)
should.Nil(err)
should.Equal("null", string(output))
output, err = Marshal(obj1)
should.Nil(err)
should.Equal("null", string(output))
output, err = Marshal(&obj1)
should.Nil(err)
should.Equal("null", string(output))
}
func Test_encode_nil_array(t *testing.T) {
should := require.New(t)
type Ttest []string
var obj1 Ttest
output, err := json.Marshal(obj1)
should.Nil(err)
should.Equal("null", string(output))
output, err = json.Marshal(&obj1)
should.Nil(err)
should.Equal("null", string(output))
output, err = Marshal(obj1)
should.Nil(err)
should.Equal("null", string(output))
output, err = Marshal(&obj1)
should.Nil(err)
should.Equal("null", string(output))
}
func Test_decode_nil_num(t *testing.T) {
type TestData struct {
Field int `json:"field"`
}
should := require.New(t)
data1 := []byte(`{"field": 42}`)
data2 := []byte(`{"field": null}`)
// Checking stdlib behavior as well
obj2 := TestData{}
err := json.Unmarshal(data1, &obj2)
should.Equal(nil, err)
should.Equal(42, obj2.Field)
err = json.Unmarshal(data2, &obj2)
should.Equal(nil, err)
should.Equal(42, obj2.Field)
obj := TestData{}
err = Unmarshal(data1, &obj)
should.Equal(nil, err)
should.Equal(42, obj.Field)
err = Unmarshal(data2, &obj)
should.Equal(nil, err)
should.Equal(42, obj.Field)
}

View File

@ -2,18 +2,17 @@ package jsoniter
import ( import (
"bytes" "bytes"
"fmt" "encoding/json"
"github.com/json-iterator/go/require"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func Test_empty_object(t *testing.T) { func Test_empty_object(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `{}`) iter := ParseString(`{}`)
field := iter.ReadObject() field := iter.ReadObject()
should.Equal("", field) should.Equal("", field)
iter = ParseString(ConfigDefault, `{}`) iter = ParseString(`{}`)
iter.ReadObjectCB(func(iter *Iterator, field string) bool { iter.ReadObjectCB(func(iter *Iterator, field string) bool {
should.FailNow("should not call") should.FailNow("should not call")
return true return true
@ -22,36 +21,34 @@ func Test_empty_object(t *testing.T) {
func Test_one_field(t *testing.T) { func Test_one_field(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `{"a": "stream"}`) iter := ParseString(`{"a": "b"}`)
field := iter.ReadObject() field := iter.ReadObject()
should.Equal("a", field) should.Equal("a", field)
value := iter.ReadString() value := iter.ReadString()
should.Equal("stream", value) should.Equal("b", value)
field = iter.ReadObject() field = iter.ReadObject()
should.Equal("", field) should.Equal("", field)
iter = ParseString(ConfigDefault, `{"a": "stream"}`) iter = ParseString(`{"a": "b"}`)
should.True(iter.ReadObjectCB(func(iter *Iterator, field string) bool { should.True(iter.ReadObjectCB(func(iter *Iterator, field string) bool {
should.Equal("a", field) should.Equal("a", field)
iter.Skip()
return true return true
})) }))
} }
func Test_two_field(t *testing.T) { func Test_two_field(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `{ "a": "stream" , "c": "d" }`) iter := ParseString(`{ "a": "b" , "c": "d" }`)
field := iter.ReadObject() field := iter.ReadObject()
should.Equal("a", field) should.Equal("a", field)
value := iter.ReadString() value := iter.ReadString()
should.Equal("stream", value) should.Equal("b", value)
field = iter.ReadObject() field = iter.ReadObject()
should.Equal("c", field) should.Equal("c", field)
value = iter.ReadString() value = iter.ReadString()
should.Equal("d", value) should.Equal("d", value)
field = iter.ReadObject() field = iter.ReadObject()
should.Equal("", field) should.Equal("", field)
iter = ParseString(ConfigDefault, `{"field1": "1", "field2": 2}`) iter = ParseString(`{"field1": "1", "field2": 2}`)
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
switch field { switch field {
case "field1": case "field1":
@ -59,11 +56,147 @@ func Test_two_field(t *testing.T) {
case "field2": case "field2":
iter.ReadInt64() iter.ReadInt64()
default: default:
iter.ReportError("bind object", "unexpected field") iter.reportError("bind object", "unexpected field")
} }
} }
} }
func Test_read_object_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{"a":"b","c":"d"}`)
should.Nil(err)
should.Equal(`{"a":"b","c":"d"}`, any.ToString())
// partial parse
should.Equal("b", any.Get("a").ToString())
should.Equal("d", any.Get("c").ToString())
should.Equal(2, len(any.Keys()))
any, err = UnmarshalAnyFromString(`{"a":"b","c":"d"}`)
// full parse
should.Equal(2, len(any.Keys()))
should.Equal(2, any.Size())
should.True(any.ToBool())
should.Equal(1, any.ToInt())
}
func Test_object_any_lazy_iterator(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{"a":"b","c":"d"}`)
should.Nil(err)
// iterator parse
vals := map[string]string{}
var k string
var v Any
next, hasNext := any.IterateObject()
should.True(hasNext)
k, v, hasNext = next()
should.True(hasNext)
vals[k] = v.ToString()
// trigger full parse
should.Equal(2, len(any.Keys()))
k, v, hasNext = next()
should.False(hasNext)
vals[k] = v.ToString()
should.Equal(map[string]string{"a": "b", "c": "d"}, vals)
vals = map[string]string{}
for next, hasNext := any.IterateObject(); hasNext; {
k, v, hasNext = next()
if v.ValueType() == String {
vals[k] = v.ToString()
}
}
should.Equal(map[string]string{"a": "b", "c": "d"}, vals)
}
func Test_object_any_with_two_lazy_iterators(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{"a":"b","c":"d","e":"f"}`)
should.Nil(err)
var k string
var v Any
next1, hasNext1 := any.IterateObject()
next2, hasNext2 := any.IterateObject()
should.True(hasNext1)
k, v, hasNext1 = next1()
should.True(hasNext1)
should.Equal("a", k)
should.Equal("b", v.ToString())
should.True(hasNext2)
k, v, hasNext2 = next2()
should.True(hasNext2)
should.Equal("a", k)
should.Equal("b", v.ToString())
k, v, hasNext1 = next1()
should.True(hasNext1)
should.Equal("c", k)
should.Equal("d", v.ToString())
k, v, hasNext2 = next2()
should.True(hasNext2)
should.Equal("c", k)
should.Equal("d", v.ToString())
}
func Test_object_lazy_any_get(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{"a":{"b":{"c":"d"}}}`)
should.Nil(err)
should.Equal("d", any.Get("a", "b", "c").ToString())
}
func Test_object_lazy_any_get_all(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{"a":[0],"b":[1]}`)
should.Nil(err)
should.Contains(any.Get('*', 0).ToString(), `"a":0`)
}
func Test_object_lazy_any_get_invalid(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{}`)
should.Nil(err)
should.Equal(Invalid, any.Get("a", "b", "c").ValueType())
should.Equal(Invalid, any.Get(1).ValueType())
}
func Test_object_lazy_any_set(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{"a":{"b":{"c":"d"}}}`)
should.Nil(err)
any.GetObject()["a"] = WrapInt64(1)
str, err := MarshalToString(any)
should.Nil(err)
should.Equal(`{"a":1}`, str)
}
func Test_wrap_object(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
field2 string
}
any := Wrap(TestObject{"hello", "world"})
should.Equal("hello", any.Get("Field1").ToString())
any = Wrap(TestObject{"hello", "world"})
should.Equal(2, any.Size())
any = Wrap(TestObject{"hello", "world"})
vals := map[string]string{}
var k string
var v Any
for next, hasNext := any.IterateObject(); hasNext; {
k, v, hasNext = next()
if v.ValueType() == String {
vals[k] = v.ToString()
}
}
should.Equal(map[string]string{"Field1": "hello"}, vals)
}
func Test_object_wrapper_any_get_all(t *testing.T) { func Test_object_wrapper_any_get_all(t *testing.T) {
should := require.New(t) should := require.New(t)
type TestObject struct { type TestObject struct {
@ -72,17 +205,13 @@ func Test_object_wrapper_any_get_all(t *testing.T) {
} }
any := Wrap(TestObject{[]int{1, 2}, []int{3, 4}}) any := Wrap(TestObject{[]int{1, 2}, []int{3, 4}})
should.Contains(any.Get('*', 0).ToString(), `"Field2":3`) should.Contains(any.Get('*', 0).ToString(), `"Field2":3`)
should.Contains(any.Keys(), "Field1")
should.Contains(any.Keys(), "Field2")
should.NotContains(any.Keys(), "Field3")
//should.Contains(any.GetObject()["Field1"].GetArray()[0], 1)
} }
func Test_write_object(t *testing.T) { func Test_write_object(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(Config{IndentionStep: 2}.Froze(), buf, 4096) stream := NewStream(buf, 4096)
stream.IndentionStep = 2
stream.WriteObjectStart() stream.WriteObjectStart()
stream.WriteObjectField("hello") stream.WriteObjectField("hello")
stream.WriteInt(1) stream.WriteInt(1)
@ -92,239 +221,37 @@ func Test_write_object(t *testing.T) {
stream.WriteObjectEnd() stream.WriteObjectEnd()
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
should.Equal("{\n \"hello\": 1,\n \"world\": 2\n}", buf.String()) should.Equal("{\n \"hello\":1,\n \"world\":2\n}", buf.String())
} }
func Test_write_val_zero_field_struct(t *testing.T) { func Benchmark_jsoniter_object(b *testing.B) {
should := require.New(t) type TestObj struct {
type TestObject struct {
}
obj := TestObject{}
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{}`, str)
}
func Test_write_val_one_field_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string `json:"field-1"`
}
obj := TestObject{"hello"}
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"field-1":"hello"}`, str)
}
func Test_mixed(t *testing.T) {
should := require.New(t)
type AA struct {
ID int `json:"id"`
Payload map[string]interface{} `json:"payload"`
buf *bytes.Buffer
}
aa := AA{}
err := UnmarshalFromString(` {"id":1, "payload":{"account":"123","password":"456"}}`, &aa)
should.Nil(err)
should.Equal(1, aa.ID)
should.Equal("123", aa.Payload["account"])
}
func Test_omit_empty(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string `json:"field-1,omitempty"`
Field2 string `json:"field-2,omitempty"`
Field3 string `json:"field-3,omitempty"`
}
obj := TestObject{}
obj.Field2 = "hello"
str, err := MarshalToString(&obj)
should.Nil(err)
should.Equal(`{"field-2":"hello"}`, str)
}
func Test_ignore_field_on_not_valid_type(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string `json:"field-1,omitempty"`
Field2 func() `json:"-"`
}
obj := TestObject{}
obj.Field1 = "hello world"
obj.Field2 = func() {}
str, err := MarshalToString(&obj)
should.Nil(err)
should.Equal(`{"field-1":"hello world"}`, str)
}
func Test_recursive_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string Field1 string
Me *TestObject Field2 uint64
}
for n := 0; n < b.N; n++ {
iter := ParseString(`{"field1": "1", "field2": 2}`)
obj := TestObj{}
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
switch field {
case "field1":
obj.Field1 = iter.ReadString()
case "field2":
obj.Field2 = iter.ReadUint64()
default:
iter.reportError("bind object", "unexpected field")
}
}
} }
obj := TestObject{}
str, err := MarshalToString(obj)
should.Nil(err)
should.Contains(str, `"Field1":""`)
should.Contains(str, `"Me":null`)
err = UnmarshalFromString(str, &obj)
should.Nil(err)
} }
func Test_encode_anonymous_struct(t *testing.T) { func Benchmark_json_object(b *testing.B) {
should := require.New(t) type TestObj struct {
type TestObject struct {
Field string
}
str, err := MarshalToString(struct {
TestObject
Field int
}{
Field: 100,
})
should.Nil(err)
should.Equal(`{"Field":100}`, str)
}
func Test_decode_anonymous_struct(t *testing.T) {
should := require.New(t)
type Inner struct {
Key string `json:"key"`
}
type Outer struct {
Inner
}
var outer Outer
j := []byte("{\"key\":\"value\"}")
should.Nil(Unmarshal(j, &outer))
should.Equal("value", outer.Key)
}
func Test_multiple_level_anonymous_struct(t *testing.T) {
type Level1 struct {
Field1 string Field1 string
Field2 uint64
} }
type Level2 struct { for n := 0; n < b.N; n++ {
Level1 result := TestObj{}
Field2 string json.Unmarshal([]byte(`{"field1": "1", "field2": 2}`), &result)
}
type Level3 struct {
Level2
Field3 string
}
should := require.New(t)
obj := Level3{Level2{Level1{"1"}, "2"}, "3"}
output, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Field1":"1","Field2":"2","Field3":"3"}`, output)
}
func Test_multiple_level_anonymous_struct_with_ptr(t *testing.T) {
type Level1 struct {
Field1 string
Field2 string
Field4 string
}
type Level2 struct {
*Level1
Field2 string
Field3 string
}
type Level3 struct {
*Level2
Field3 string
}
should := require.New(t)
obj := Level3{&Level2{&Level1{"1", "", "4"}, "2", ""}, "3"}
output, err := MarshalToString(obj)
should.Nil(err)
should.Contains(output, `"Field1":"1"`)
should.Contains(output, `"Field2":"2"`)
should.Contains(output, `"Field3":"3"`)
should.Contains(output, `"Field4":"4"`)
}
func Test_shadow_struct_field(t *testing.T) {
should := require.New(t)
type omit *struct{}
type CacheItem struct {
Key string `json:"key"`
MaxAge int `json:"cacheAge"`
}
output, err := MarshalToString(struct {
*CacheItem
// Omit bad keys
OmitMaxAge omit `json:"cacheAge,omitempty"`
// Add nice keys
MaxAge int `json:"max_age"`
}{
CacheItem: &CacheItem{
Key: "value",
MaxAge: 100,
},
MaxAge: 20,
})
should.Nil(err)
should.Contains(output, `"key":"value"`)
should.Contains(output, `"max_age":20`)
}
func Test_embedded_order(t *testing.T) {
type A struct {
Field2 string
}
type C struct {
Field5 string
}
type B struct {
Field4 string
C
Field6 string
}
type TestObject struct {
Field1 string
A
Field3 string
B
Field7 string
}
should := require.New(t)
s := TestObject{}
output, err := MarshalToString(s)
should.Nil(err)
should.Equal(`{"Field1":"","Field2":"","Field3":"","Field4":"","Field5":"","Field6":"","Field7":""}`, output)
}
func Test_decode_nested(t *testing.T) {
type StructOfString struct {
Field1 string
Field2 string
}
iter := ParseString(ConfigDefault, `[{"field1": "hello"}, null, {"field2": "world"}]`)
slice := []*StructOfString{}
iter.ReadVal(&slice)
if len(slice) != 3 {
fmt.Println(iter.Error)
t.Fatal(len(slice))
}
if slice[0].Field1 != "hello" {
fmt.Println(iter.Error)
t.Fatal(slice[0])
}
if slice[1] != nil {
fmt.Println(iter.Error)
t.Fatal(slice[1])
}
if slice[2].Field2 != "world" {
fmt.Println(iter.Error)
t.Fatal(slice[2])
} }
} }

View File

@ -1,7 +1,7 @@
package jsoniter package jsoniter
import ( import (
"github.com/stretchr/testify/require" "github.com/json-iterator/go/require"
"testing" "testing"
) )
@ -21,26 +21,26 @@ func Test_encode_optional_int_pointer(t *testing.T) {
func Test_decode_struct_with_optional_field(t *testing.T) { func Test_decode_struct_with_optional_field(t *testing.T) {
should := require.New(t) should := require.New(t)
type TestObject struct { type TestObject struct {
Field1 *string field1 *string
Field2 *string field2 *string
} }
obj := TestObject{} obj := TestObject{}
UnmarshalFromString(`{"field1": null, "field2": "world"}`, &obj) UnmarshalFromString(`{"field1": null, "field2": "world"}`, &obj)
should.Nil(obj.Field1) should.Nil(obj.field1)
should.Equal("world", *obj.Field2) should.Equal("world", *obj.field2)
} }
func Test_encode_struct_with_optional_field(t *testing.T) { func Test_encode_struct_with_optional_field(t *testing.T) {
should := require.New(t) should := require.New(t)
type TestObject struct { type TestObject struct {
Field1 *string field1 *string
Field2 *string field2 *string
} }
obj := TestObject{} obj := TestObject{}
world := "world" world := "world"
obj.Field2 = &world obj.field2 = &world
str, err := MarshalToString(obj) str, err := MarshalToString(obj)
should.Nil(err) should.Nil(err)
should.Contains(str, `"Field1":null`) should.Contains(str, `"field1":null`)
should.Contains(str, `"Field2":"world"`) should.Contains(str, `"field2":"world"`)
} }

View File

@ -1,88 +0,0 @@
package jsoniter
import (
"encoding/json"
"github.com/stretchr/testify/require"
"testing"
)
func Test_json_RawMessage(t *testing.T) {
should := require.New(t)
var data json.RawMessage
should.Nil(Unmarshal([]byte(`[1,2,3]`), &data))
should.Equal(`[1,2,3]`, string(data))
str, err := MarshalToString(data)
should.Nil(err)
should.Equal(`[1,2,3]`, str)
}
func Test_jsoniter_RawMessage(t *testing.T) {
should := require.New(t)
var data RawMessage
should.Nil(Unmarshal([]byte(`[1,2,3]`), &data))
should.Equal(`[1,2,3]`, string(data))
str, err := MarshalToString(data)
should.Nil(err)
should.Equal(`[1,2,3]`, str)
}
func Test_json_RawMessage_in_struct(t *testing.T) {
type TestObject struct {
Field1 string
Field2 json.RawMessage
}
should := require.New(t)
var data TestObject
should.Nil(Unmarshal([]byte(`{"field1": "hello", "field2": [1,2,3]}`), &data))
should.Equal(` [1,2,3]`, string(data.Field2))
should.Equal(`hello`, data.Field1)
}
func Test_decode_map_of_raw_message(t *testing.T) {
should := require.New(t)
type RawMap map[string]*json.RawMessage
b := []byte("{\"test\":[{\"key\":\"value\"}]}")
var rawMap RawMap
should.Nil(Unmarshal(b, &rawMap))
should.Equal(`[{"key":"value"}]`, string(*rawMap["test"]))
type Inner struct {
Key string `json:"key"`
}
var inner []Inner
Unmarshal(*rawMap["test"], &inner)
should.Equal("value", inner[0].Key)
}
func Test_encode_map_of_raw_message(t *testing.T) {
should := require.New(t)
type RawMap map[string]*json.RawMessage
value := json.RawMessage("[]")
rawMap := RawMap{"hello": &value}
output, err := MarshalToString(rawMap)
should.Nil(err)
should.Equal(`{"hello":[]}`, output)
}
func Test_encode_map_of_jsoniter_raw_message(t *testing.T) {
should := require.New(t)
type RawMap map[string]*RawMessage
value := RawMessage("[]")
rawMap := RawMap{"hello": &value}
output, err := MarshalToString(rawMap)
should.Nil(err)
should.Equal(`{"hello":[]}`, output)
}
func Test_marshal_invalid_json_raw_message(t *testing.T) {
type A struct {
Raw json.RawMessage `json:"raw"`
}
message := []byte(`{}`)
a := A{}
should := require.New(t)
should.Nil(ConfigCompatibleWithStandardLibrary.Unmarshal(message, &a))
aout, aouterr := ConfigCompatibleWithStandardLibrary.Marshal(&a)
should.Equal(`{"raw":null}`, string(aout))
should.Nil(aouterr)
}

View File

@ -1,57 +0,0 @@
package jsoniter
import (
"github.com/stretchr/testify/require"
"strings"
"testing"
"time"
)
func Test_reader_and_load_more(t *testing.T) {
should := require.New(t)
type TestObject struct {
CreatedAt time.Time
}
reader := strings.NewReader(`
{
"agency": null,
"candidateId": 0,
"candidate": "Blah Blah",
"bookingId": 0,
"shiftId": 1,
"shiftTypeId": 0,
"shift": "Standard",
"bonus": 0,
"bonusNI": 0,
"days": [],
"totalHours": 27,
"expenses": [],
"weekEndingDateSystem": "2016-10-09",
"weekEndingDateClient": "2016-10-09",
"submittedAt": null,
"submittedById": null,
"approvedAt": "2016-10-10T18:38:04Z",
"approvedById": 0,
"authorisedAt": "2016-10-10T18:38:04Z",
"authorisedById": 0,
"invoicedAt": "2016-10-10T20:00:00Z",
"revokedAt": null,
"revokedById": null,
"revokeReason": null,
"rejectedAt": null,
"rejectedById": null,
"rejectReasonCode": null,
"rejectReason": null,
"createdAt": "2016-10-03T00:00:00Z",
"updatedAt": "2016-11-09T10:26:13Z",
"updatedById": null,
"overrides": [],
"bookingApproverId": null,
"bookingApprover": null,
"status": "approved"
}
`)
decoder := ConfigCompatibleWithStandardLibrary.NewDecoder(reader)
obj := TestObject{}
should.Nil(decoder.Decode(&obj))
}

View File

@ -6,7 +6,7 @@ import (
) )
func Test_reflect_str(t *testing.T) { func Test_reflect_str(t *testing.T) {
iter := ParseString(ConfigDefault, `"hello"`) iter := ParseString(`"hello"`)
str := "" str := ""
iter.ReadVal(&str) iter.ReadVal(&str)
if str != "hello" { if str != "hello" {
@ -16,7 +16,7 @@ func Test_reflect_str(t *testing.T) {
} }
func Test_reflect_ptr_str(t *testing.T) { func Test_reflect_ptr_str(t *testing.T) {
iter := ParseString(ConfigDefault, `"hello"`) iter := ParseString(`"hello"`)
var str *string var str *string
iter.ReadVal(&str) iter.ReadVal(&str)
if *str != "hello" { if *str != "hello" {
@ -25,7 +25,7 @@ func Test_reflect_ptr_str(t *testing.T) {
} }
func Test_reflect_int(t *testing.T) { func Test_reflect_int(t *testing.T) {
iter := ParseString(ConfigDefault, `123`) iter := ParseString(`123`)
val := int(0) val := int(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 123 { if val != 123 {
@ -34,7 +34,7 @@ func Test_reflect_int(t *testing.T) {
} }
func Test_reflect_int8(t *testing.T) { func Test_reflect_int8(t *testing.T) {
iter := ParseString(ConfigDefault, `123`) iter := ParseString(`123`)
val := int8(0) val := int8(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 123 { if val != 123 {
@ -43,7 +43,7 @@ func Test_reflect_int8(t *testing.T) {
} }
func Test_reflect_int16(t *testing.T) { func Test_reflect_int16(t *testing.T) {
iter := ParseString(ConfigDefault, `123`) iter := ParseString(`123`)
val := int16(0) val := int16(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 123 { if val != 123 {
@ -52,7 +52,7 @@ func Test_reflect_int16(t *testing.T) {
} }
func Test_reflect_int32(t *testing.T) { func Test_reflect_int32(t *testing.T) {
iter := ParseString(ConfigDefault, `123`) iter := ParseString(`123`)
val := int32(0) val := int32(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 123 { if val != 123 {
@ -61,7 +61,7 @@ func Test_reflect_int32(t *testing.T) {
} }
func Test_reflect_int64(t *testing.T) { func Test_reflect_int64(t *testing.T) {
iter := ParseString(ConfigDefault, `123`) iter := ParseString(`123`)
val := int64(0) val := int64(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 123 { if val != 123 {
@ -70,7 +70,7 @@ func Test_reflect_int64(t *testing.T) {
} }
func Test_reflect_uint(t *testing.T) { func Test_reflect_uint(t *testing.T) {
iter := ParseString(ConfigDefault, `123`) iter := ParseString(`123`)
val := uint(0) val := uint(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 123 { if val != 123 {
@ -79,7 +79,7 @@ func Test_reflect_uint(t *testing.T) {
} }
func Test_reflect_uint8(t *testing.T) { func Test_reflect_uint8(t *testing.T) {
iter := ParseString(ConfigDefault, `123`) iter := ParseString(`123`)
val := uint8(0) val := uint8(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 123 { if val != 123 {
@ -88,7 +88,7 @@ func Test_reflect_uint8(t *testing.T) {
} }
func Test_reflect_uint16(t *testing.T) { func Test_reflect_uint16(t *testing.T) {
iter := ParseString(ConfigDefault, `123`) iter := ParseString(`123`)
val := uint16(0) val := uint16(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 123 { if val != 123 {
@ -97,7 +97,7 @@ func Test_reflect_uint16(t *testing.T) {
} }
func Test_reflect_uint32(t *testing.T) { func Test_reflect_uint32(t *testing.T) {
iter := ParseString(ConfigDefault, `123`) iter := ParseString(`123`)
val := uint32(0) val := uint32(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 123 { if val != 123 {
@ -106,7 +106,7 @@ func Test_reflect_uint32(t *testing.T) {
} }
func Test_reflect_uint64(t *testing.T) { func Test_reflect_uint64(t *testing.T) {
iter := ParseString(ConfigDefault, `123`) iter := ParseString(`123`)
val := uint64(0) val := uint64(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 123 { if val != 123 {
@ -115,7 +115,7 @@ func Test_reflect_uint64(t *testing.T) {
} }
func Test_reflect_byte(t *testing.T) { func Test_reflect_byte(t *testing.T) {
iter := ParseString(ConfigDefault, `123`) iter := ParseString(`123`)
val := byte(0) val := byte(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 123 { if val != 123 {
@ -124,7 +124,7 @@ func Test_reflect_byte(t *testing.T) {
} }
func Test_reflect_float32(t *testing.T) { func Test_reflect_float32(t *testing.T) {
iter := ParseString(ConfigDefault, `1.23`) iter := ParseString(`1.23`)
val := float32(0) val := float32(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 1.23 { if val != 1.23 {
@ -134,7 +134,7 @@ func Test_reflect_float32(t *testing.T) {
} }
func Test_reflect_float64(t *testing.T) { func Test_reflect_float64(t *testing.T) {
iter := ParseString(ConfigDefault, `1.23`) iter := ParseString(`1.23`)
val := float64(0) val := float64(0)
iter.ReadVal(&val) iter.ReadVal(&val)
if val != 1.23 { if val != 1.23 {
@ -144,7 +144,7 @@ func Test_reflect_float64(t *testing.T) {
} }
func Test_reflect_bool(t *testing.T) { func Test_reflect_bool(t *testing.T) {
iter := ParseString(ConfigDefault, `true`) iter := ParseString(`true`)
val := false val := false
iter.ReadVal(&val) iter.ReadVal(&val)
if val != true { if val != true {

View File

@ -0,0 +1,241 @@
package jsoniter
import (
"bytes"
"github.com/json-iterator/go/require"
"testing"
)
func Test_decode_one_field_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"field1": "hello"}`, &obj))
should.Equal("hello", obj.Field1)
}
func Test_decode_two_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("b", obj.Field2)
}
func Test_decode_three_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("b", obj.Field2)
should.Equal("c", obj.Field3)
}
func Test_decode_four_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
Field4 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("b", obj.Field2)
should.Equal("c", obj.Field3)
should.Equal("d", obj.Field4)
}
func Test_decode_five_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
Field4 string
Field5 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("b", obj.Field2)
should.Equal("c", obj.Field3)
should.Equal("d", obj.Field4)
should.Equal("e", obj.Field5)
}
func Test_decode_ten_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
Field4 string
Field5 string
Field6 string
Field7 string
Field8 string
Field9 string
Field10 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("b", obj.Field2)
should.Equal("c", obj.Field3)
should.Equal("d", obj.Field4)
should.Equal("e", obj.Field5)
}
func Test_decode_struct_field_with_tag(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string `json:"field-1"`
Field2 string `json:"-"`
Field3 int `json:",string"`
}
obj := TestObject{Field2: "world"}
UnmarshalFromString(`{"field-1": "hello", "field2": "", "Field3": "100"}`, &obj)
should.Equal("hello", obj.Field1)
should.Equal("world", obj.Field2)
should.Equal(100, obj.Field3)
}
func Test_write_val_zero_field_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
}
obj := TestObject{}
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{}`, str)
}
func Test_write_val_one_field_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string `json:"field-1"`
}
obj := TestObject{"hello"}
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"field-1":"hello"}`, str)
}
func Test_mixed(t *testing.T) {
should := require.New(t)
type AA struct {
ID int `json:"id"`
Payload map[string]interface{} `json:"payload"`
buf *bytes.Buffer `json:"-"`
}
aa := AA{}
err := UnmarshalFromString(` {"id":1, "payload":{"account":"123","password":"456"}}`, &aa)
should.Nil(err)
should.Equal(1, aa.ID)
should.Equal("123", aa.Payload["account"])
}
func Test_omit_empty(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string `json:"field-1,omitempty"`
Field2 string `json:"field-2,omitempty"`
Field3 string `json:"field-3,omitempty"`
}
obj := TestObject{}
obj.Field2 = "hello"
str, err := MarshalToString(&obj)
should.Nil(err)
should.Equal(`{"field-2":"hello"}`, str)
}
func Test_any_within_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 Any
Field2 Any
}
obj := TestObject{}
err := UnmarshalFromString(`{"Field1": "hello", "Field2": [1,2,3]}`, &obj)
should.Nil(err)
should.Equal("hello", obj.Field1.ToString())
should.Equal("[1,2,3]", obj.Field2.ToString())
}
func Test_recursive_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Me *TestObject
}
obj := TestObject{}
str, err := MarshalToString(obj)
should.Nil(err)
should.Contains(str, `"Field1":""`)
should.Contains(str, `"Me":null`)
err = UnmarshalFromString(str, &obj)
should.Nil(err)
}
func Test_one_field_struct(t *testing.T) {
should := require.New(t)
type YetYetAnotherObject struct {
Field string
}
type YetAnotherObject struct {
Field *YetYetAnotherObject
}
type AnotherObject struct {
Field *YetAnotherObject
}
type TestObject struct {
Me *AnotherObject
}
obj := TestObject{&AnotherObject{&YetAnotherObject{&YetYetAnotherObject{"abc"}}}}
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
str, err = MarshalToString(&obj)
should.Nil(err)
should.Equal(`{"Me":{"Field":{"Field":{"Field":"abc"}}}}`, str)
}
func Test_anonymous_struct_marshal(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field string
}
str, err := MarshalToString(struct {
TestObject
Field int
}{
Field: 100,
})
should.Nil(err)
should.Equal(`{"Field":100}`, str)
}

115
jsoniter_reflect_test.go Normal file
View File

@ -0,0 +1,115 @@
package jsoniter
import (
"encoding/json"
"fmt"
"github.com/json-iterator/go/require"
"testing"
"unsafe"
)
func Test_decode_slice(t *testing.T) {
should := require.New(t)
slice := make([]string, 0, 5)
UnmarshalFromString(`["hello", "world"]`, &slice)
should.Equal([]string{"hello", "world"}, slice)
}
func Test_decode_large_slice(t *testing.T) {
should := require.New(t)
slice := make([]int, 0, 1)
UnmarshalFromString(`[1,2,3,4,5,6,7,8,9]`, &slice)
should.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}, slice)
}
func Test_decode_nested(t *testing.T) {
type StructOfString struct {
field1 string
field2 string
}
iter := ParseString(`[{"field1": "hello"}, null, {"field2": "world"}]`)
slice := []*StructOfString{}
iter.ReadVal(&slice)
if len(slice) != 3 {
fmt.Println(iter.Error)
t.Fatal(len(slice))
}
if slice[0].field1 != "hello" {
fmt.Println(iter.Error)
t.Fatal(slice[0])
}
if slice[1] != nil {
fmt.Println(iter.Error)
t.Fatal(slice[1])
}
if slice[2].field2 != "world" {
fmt.Println(iter.Error)
t.Fatal(slice[2])
}
}
func Test_decode_base64(t *testing.T) {
iter := ParseString(`"YWJj"`)
val := []byte{}
RegisterTypeDecoder("[]uint8", func(ptr unsafe.Pointer, iter *Iterator) {
*((*[]byte)(ptr)) = iter.ReadBase64()
})
defer CleanDecoders()
iter.ReadVal(&val)
if "abc" != string(val) {
t.Fatal(string(val))
}
}
type StructOfTagOne struct {
Field1 string `json:"field1"`
Field2 string `json:"field2"`
Field3 int `json:"field3,string"`
Field4 int `json:"field4,string"`
}
func Benchmark_jsoniter_reflect(b *testing.B) {
b.ReportAllocs()
iter := NewIterator()
Struct := &StructOfTagOne{}
//var Struct *StructOfTagOne
input := []byte(`{"field3": "100", "field4": "100"}`)
//input := []byte(`null`)
for n := 0; n < b.N; n++ {
iter.ResetBytes(input)
iter.ReadVal(&Struct)
}
}
func Benchmark_jsoniter_direct(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
//iter := ParseString(`{"field1": "hello", "field2": "world"}`)
//struct_ := StructOfString{}
//for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
// switch field {
// case "field1":
// struct_.Field1 = iter.ReadString()
// case "field2":
// struct_.Field2 = iter.ReadString()
// default:
// iter.Skip()
// }
//}
iter := ParseString(`["hello", "world"]`)
array := make([]string, 0, 2)
for iter.ReadArray() {
array = append(array, iter.ReadString())
}
}
}
func Benchmark_json_reflect(b *testing.B) {
b.ReportAllocs()
for n := 0; n < b.N; n++ {
Struct := StructOfTagOne{}
json.Unmarshal([]byte(`{"field3": "100"}`), &Struct)
//array := make([]string, 0, 2)
//json.Unmarshal([]byte(`["hello", "world"]`), &array)
}
}

View File

@ -1,109 +1,80 @@
package jsoniter package jsoniter
import ( import (
"bytes"
"encoding/json" "encoding/json"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func Test_skip_number_in_array(t *testing.T) { func Test_skip_number(t *testing.T) {
should := require.New(t) iter := ParseString(`[-0.12, "b"]`)
iter := ParseString(ConfigDefault, `[-0.12, "stream"]`)
iter.ReadArray() iter.ReadArray()
iter.Skip() iter.Skip()
iter.ReadArray() iter.ReadArray()
should.Nil(iter.Error) if iter.ReadString() != "b" {
should.Equal("stream", iter.ReadString()) t.FailNow()
} }
func Test_skip_string_in_array(t *testing.T) {
should := require.New(t)
iter := ParseString(ConfigDefault, `["hello", "stream"]`)
iter.ReadArray()
iter.Skip()
iter.ReadArray()
should.Nil(iter.Error)
should.Equal("stream", iter.ReadString())
} }
func Test_skip_null(t *testing.T) { func Test_skip_null(t *testing.T) {
iter := ParseString(ConfigDefault, `[null , "stream"]`) iter := ParseString(`[null , "b"]`)
iter.ReadArray() iter.ReadArray()
iter.Skip() iter.Skip()
iter.ReadArray() iter.ReadArray()
if iter.ReadString() != "stream" { if iter.ReadString() != "b" {
t.FailNow() t.FailNow()
} }
} }
func Test_skip_true(t *testing.T) { func Test_skip_true(t *testing.T) {
iter := ParseString(ConfigDefault, `[true , "stream"]`) iter := ParseString(`[true , "b"]`)
iter.ReadArray() iter.ReadArray()
iter.Skip() iter.Skip()
iter.ReadArray() iter.ReadArray()
if iter.ReadString() != "stream" { if iter.ReadString() != "b" {
t.FailNow() t.FailNow()
} }
} }
func Test_skip_false(t *testing.T) { func Test_skip_false(t *testing.T) {
iter := ParseString(ConfigDefault, `[false , "stream"]`) iter := ParseString(`[false , "b"]`)
iter.ReadArray() iter.ReadArray()
iter.Skip() iter.Skip()
iter.ReadArray() iter.ReadArray()
if iter.ReadString() != "stream" { if iter.ReadString() != "b" {
t.FailNow() t.FailNow()
} }
} }
func Test_skip_array(t *testing.T) { func Test_skip_array(t *testing.T) {
iter := ParseString(ConfigDefault, `[[1, [2, [3], 4]], "stream"]`) iter := ParseString(`[[1, [2, [3], 4]], "b"]`)
iter.ReadArray() iter.ReadArray()
iter.Skip() iter.Skip()
iter.ReadArray() iter.ReadArray()
if iter.ReadString() != "stream" { if iter.ReadString() != "b" {
t.FailNow() t.FailNow()
} }
} }
func Test_skip_empty_array(t *testing.T) { func Test_skip_empty_array(t *testing.T) {
iter := ParseString(ConfigDefault, `[ [ ], "stream"]`) iter := ParseString(`[ [ ], "b"]`)
iter.ReadArray() iter.ReadArray()
iter.Skip() iter.Skip()
iter.ReadArray() iter.ReadArray()
if iter.ReadString() != "stream" { if iter.ReadString() != "b" {
t.FailNow() t.FailNow()
} }
} }
func Test_skip_nested(t *testing.T) { func Test_skip_nested(t *testing.T) {
iter := ParseString(ConfigDefault, `[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`) iter := ParseString(`[ {"a" : [{"b": "c"}], "d": 102 }, "b"]`)
iter.ReadArray() iter.ReadArray()
iter.Skip() iter.Skip()
iter.ReadArray() iter.ReadArray()
if iter.ReadString() != "stream" { if iter.ReadString() != "b" {
t.FailNow() t.FailNow()
} }
} }
func Test_skip_and_return_bytes(t *testing.T) {
should := require.New(t)
iter := ParseString(ConfigDefault, `[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`)
iter.ReadArray()
skipped := iter.SkipAndReturnBytes()
should.Equal(`{"a" : [{"stream": "c"}], "d": 102 }`, string(skipped))
}
func Test_skip_and_return_bytes_with_reader(t *testing.T) {
should := require.New(t)
iter := Parse(ConfigDefault, bytes.NewBufferString(`[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`), 4)
iter.ReadArray()
skipped := iter.SkipAndReturnBytes()
should.Equal(`{"a" : [{"stream": "c"}], "d": 102 }`, string(skipped))
}
type TestResp struct { type TestResp struct {
Code uint64 Code uint64
} }
@ -135,7 +106,7 @@ func Benchmark_jsoniter_skip(b *testing.B) {
}`) }`)
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
result := TestResp{} result := TestResp{}
iter := ParseBytes(ConfigDefault, input) iter := ParseBytes(input)
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
switch field { switch field {
case "code": case "code":

View File

@ -1,13 +1,13 @@
package jsoniter package jsoniter
import ( import (
"github.com/stretchr/testify/require" "github.com/json-iterator/go/require"
"testing" "testing"
) )
func Test_writeByte_should_grow_buffer(t *testing.T) { func Test_writeByte_should_grow_buffer(t *testing.T) {
should := require.New(t) should := require.New(t)
stream := NewStream(ConfigDefault, nil, 1) stream := NewStream(nil, 1)
stream.writeByte('1') stream.writeByte('1')
should.Equal("1", string(stream.Buffer())) should.Equal("1", string(stream.Buffer()))
should.Equal(1, len(stream.buf)) should.Equal(1, len(stream.buf))
@ -20,7 +20,7 @@ func Test_writeByte_should_grow_buffer(t *testing.T) {
func Test_writeBytes_should_grow_buffer(t *testing.T) { func Test_writeBytes_should_grow_buffer(t *testing.T) {
should := require.New(t) should := require.New(t)
stream := NewStream(ConfigDefault, nil, 1) stream := NewStream(nil, 1)
stream.Write([]byte{'1', '2'}) stream.Write([]byte{'1', '2'})
should.Equal("12", string(stream.Buffer())) should.Equal("12", string(stream.Buffer()))
should.Equal(3, len(stream.buf)) should.Equal(3, len(stream.buf))
@ -31,14 +31,15 @@ func Test_writeBytes_should_grow_buffer(t *testing.T) {
func Test_writeIndention_should_grow_buffer(t *testing.T) { func Test_writeIndention_should_grow_buffer(t *testing.T) {
should := require.New(t) should := require.New(t)
stream := NewStream(Config{IndentionStep: 2}.Froze(), nil, 1) stream := NewStream(nil, 1)
stream.IndentionStep = 2
stream.WriteVal([]int{1, 2, 3}) stream.WriteVal([]int{1, 2, 3})
should.Equal("[\n 1,\n 2,\n 3\n]", string(stream.Buffer())) should.Equal("[\n 1,\n 2,\n 3\n]", string(stream.Buffer()))
} }
func Test_writeRaw_should_grow_buffer(t *testing.T) { func Test_writeRaw_should_grow_buffer(t *testing.T) {
should := require.New(t) should := require.New(t)
stream := NewStream(ConfigDefault, nil, 1) stream := NewStream(nil, 1)
stream.WriteRaw("123") stream.WriteRaw("123")
should.Nil(stream.Error) should.Nil(stream.Error)
should.Equal("123", string(stream.Buffer())) should.Equal("123", string(stream.Buffer()))
@ -46,7 +47,7 @@ func Test_writeRaw_should_grow_buffer(t *testing.T) {
func Test_writeString_should_grow_buffer(t *testing.T) { func Test_writeString_should_grow_buffer(t *testing.T) {
should := require.New(t) should := require.New(t)
stream := NewStream(ConfigDefault, nil, 0) stream := NewStream(nil, 0)
stream.WriteString("123") stream.WriteString("123")
should.Nil(stream.Error) should.Nil(stream.Error)
should.Equal(`"123"`, string(stream.Buffer())) should.Equal(`"123"`, string(stream.Buffer()))

View File

@ -1,73 +1,13 @@
// +build go1.8
package jsoniter package jsoniter
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/json-iterator/go/require"
"testing" "testing"
"unicode/utf8"
"github.com/stretchr/testify/require"
) )
func Test_read_string(t *testing.T) {
badInputs := []string{
``,
`"`,
`"\"`,
`"\\\"`,
"\"\n\"",
`"\U0001f64f"`,
`"\uD83D\u00"`,
}
for i := 0; i < 32; i++ {
// control characters are invalid
badInputs = append(badInputs, string([]byte{'"', byte(i), '"'}))
}
for _, input := range badInputs {
testReadString(t, input, "", true, "json.Unmarshal", json.Unmarshal)
testReadString(t, input, "", true, "jsoniter.Unmarshal", Unmarshal)
testReadString(t, input, "", true, "jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal", ConfigCompatibleWithStandardLibrary.Unmarshal)
}
goodInputs := []struct {
input string
expectValue string
}{
{`""`, ""},
{`"a"`, "a"},
{`null`, ""},
{`"Iñtërnâtiônàlizætiøn,💝🐹🌇⛔"`, "Iñtërnâtiônàlizætiøn,💝🐹🌇⛔"},
{`"\uD83D"`, string([]byte{239, 191, 189})},
{`"\uD83D\\"`, string([]byte{239, 191, 189, '\\'})},
{`"\uD83D\ub000"`, string([]byte{239, 191, 189, 235, 128, 128})},
{`"\uD83D\ude04"`, "😄"},
{`"\uDEADBEEF"`, string([]byte{239, 191, 189, 66, 69, 69, 70})},
}
for _, tc := range goodInputs {
testReadString(t, tc.input, tc.expectValue, false, "json.Unmarshal", json.Unmarshal)
testReadString(t, tc.input, tc.expectValue, false, "jsoniter.Unmarshal", Unmarshal)
testReadString(t, tc.input, tc.expectValue, false, "jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal", ConfigCompatibleWithStandardLibrary.Unmarshal)
}
}
func testReadString(t *testing.T, input string, expectValue string, expectError bool, marshalerName string, marshaler func([]byte, interface{}) error) {
var value string
err := marshaler([]byte(input), &value)
if expectError != (err != nil) {
t.Errorf("%q: %s: expected error %v, got %v", input, marshalerName, expectError, err)
return
}
if value != expectValue {
t.Errorf("%q: %s: expected %q, got %q", input, marshalerName, expectValue, value)
return
}
}
func Test_read_normal_string(t *testing.T) { func Test_read_normal_string(t *testing.T) {
cases := map[string]string{ cases := map[string]string{
`"0123456789012345678901234567890123456789"`: `0123456789012345678901234567890123456789`, `"0123456789012345678901234567890123456789"`: `0123456789012345678901234567890123456789`,
@ -77,22 +17,22 @@ func Test_read_normal_string(t *testing.T) {
for input, output := range cases { for input, output := range cases {
t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) { t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, input) iter := ParseString(input)
should.Equal(output, iter.ReadString()) should.Equal(output, iter.ReadString())
}) })
t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) { t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := Parse(ConfigDefault, bytes.NewBufferString(input), 2) iter := Parse(bytes.NewBufferString(input), 2)
should.Equal(output, iter.ReadString()) should.Equal(output, iter.ReadString())
}) })
t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) { t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, input) iter := ParseString(input)
should.Equal(output, string(iter.ReadStringAsSlice())) should.Equal(output, string(iter.ReadStringAsSlice()))
}) })
t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) { t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := Parse(ConfigDefault, bytes.NewBufferString(input), 2) iter := Parse(bytes.NewBufferString(input), 2)
should.Equal(output, string(iter.ReadStringAsSlice())) should.Equal(output, string(iter.ReadStringAsSlice()))
}) })
} }
@ -101,30 +41,19 @@ func Test_read_normal_string(t *testing.T) {
func Test_read_exotic_string(t *testing.T) { func Test_read_exotic_string(t *testing.T) {
cases := map[string]string{ cases := map[string]string{
`"hel\"lo"`: `hel"lo`, `"hel\"lo"`: `hel"lo`,
`"hel\\\/lo"`: `hel\/lo`, `"hel\nlo"`: "hel\nlo",
`"hel\\blo"`: `hel\blo`,
`"hel\\\blo"`: "hel\\\blo",
`"hel\\nlo"`: `hel\nlo`,
`"hel\\\nlo"`: "hel\\\nlo",
`"hel\\tlo"`: `hel\tlo`,
`"hel\\flo"`: `hel\flo`,
`"hel\\\flo"`: "hel\\\flo",
`"hel\\\rlo"`: "hel\\\rlo",
`"hel\\\tlo"`: "hel\\\tlo",
`"\u4e2d\u6587"`: "中文", `"\u4e2d\u6587"`: "中文",
`"\ud83d\udc4a"`: "\xf0\x9f\x91\x8a", // surrogate `"\ud83d\udc4a"`: "\xf0\x9f\x91\x8a", // surrogate
} }
for input, output := range cases { for input, output := range cases {
t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) { t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, input) iter := ParseString(input)
var v string should.Equal(output, iter.ReadString())
should.Nil(json.Unmarshal([]byte(input), &v))
should.Equal(v, iter.ReadString())
}) })
t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) { t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := Parse(ConfigDefault, bytes.NewBufferString(input), 2) iter := Parse(bytes.NewBufferString(input), 2)
should.Equal(output, iter.ReadString()) should.Equal(output, iter.ReadString())
}) })
} }
@ -132,10 +61,30 @@ func Test_read_exotic_string(t *testing.T) {
func Test_read_string_as_interface(t *testing.T) { func Test_read_string_as_interface(t *testing.T) {
should := require.New(t) should := require.New(t)
iter := ParseString(ConfigDefault, `"hello"`) iter := ParseString(`"hello"`)
should.Equal("hello", iter.Read()) should.Equal("hello", iter.Read())
} }
func Test_read_string_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`"hello"`)
should.Nil(err)
should.Equal("hello", any.ToString())
should.True(any.ToBool())
any, err = UnmarshalAnyFromString(`" "`)
should.False(any.ToBool())
any, err = UnmarshalAnyFromString(`"false"`)
should.False(any.ToBool())
any, err = UnmarshalAnyFromString(`"123"`)
should.Equal(123, any.ToInt())
}
func Test_wrap_string(t *testing.T) {
should := require.New(t)
any := WrapString("123")
should.Equal(123, any.ToInt())
}
func Test_write_string(t *testing.T) { func Test_write_string(t *testing.T) {
should := require.New(t) should := require.New(t)
str, err := MarshalToString("hello") str, err := MarshalToString("hello")
@ -149,7 +98,7 @@ func Test_write_string(t *testing.T) {
func Test_write_val_string(t *testing.T) { func Test_write_val_string(t *testing.T) {
should := require.New(t) should := require.New(t)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
stream := NewStream(ConfigDefault, buf, 4096) stream := NewStream(buf, 4096)
stream.WriteVal("hello") stream.WriteVal("hello")
stream.Flush() stream.Flush()
should.Nil(stream.Error) should.Nil(stream.Error)
@ -163,72 +112,15 @@ func Test_decode_slash(t *testing.T) {
should.NotNil(UnmarshalFromString("\\", &obj)) should.NotNil(UnmarshalFromString("\\", &obj))
} }
func Test_html_escape(t *testing.T) {
should := require.New(t)
output, err := json.Marshal(`>`)
should.Nil(err)
should.Equal(`"\u003e"`, string(output))
output, err = ConfigCompatibleWithStandardLibrary.Marshal(`>`)
should.Nil(err)
should.Equal(`"\u003e"`, string(output))
type MyString string
output, err = ConfigCompatibleWithStandardLibrary.Marshal(MyString(`>`))
should.Nil(err)
should.Equal(`"\u003e"`, string(output))
}
func Test_string_encode_with_std(t *testing.T) {
should := require.New(t)
for i := 0; i < utf8.RuneSelf; i++ {
input := string([]byte{byte(i)})
stdOutputBytes, err := json.Marshal(input)
should.Nil(err)
stdOutput := string(stdOutputBytes)
jsoniterOutputBytes, err := ConfigCompatibleWithStandardLibrary.Marshal(input)
should.Nil(err)
jsoniterOutput := string(jsoniterOutputBytes)
should.Equal(stdOutput, jsoniterOutput)
}
}
func Test_unicode(t *testing.T) {
should := require.New(t)
output, _ := MarshalToString(map[string]interface{}{"a": "数字山谷"})
should.Equal(`{"a":"数字山谷"}`, output)
output, _ = Config{EscapeHTML: false}.Froze().MarshalToString(map[string]interface{}{"a": "数字山谷"})
should.Equal(`{"a":"数字山谷"}`, output)
}
func Test_unicode_and_escape(t *testing.T) {
should := require.New(t)
output, err := MarshalToString(`"数字山谷"`)
should.Nil(err)
should.Equal(`"\"数字山谷\""`, output)
output, err = ConfigFastest.MarshalToString(`"数字山谷"`)
should.Nil(err)
should.Equal(`"\"数字山谷\""`, output)
}
func Test_unsafe_unicode(t *testing.T) {
ConfigDefault.(*frozenConfig).cleanEncoders()
should := require.New(t)
output, err := ConfigDefault.MarshalToString("he\u2029\u2028he")
should.Nil(err)
should.Equal(`"he\u2029\u2028he"`, output)
output, err = ConfigFastest.MarshalToString("he\u2029\u2028he")
should.Nil(err)
should.Equal("\"he\u2029\u2028he\"", output)
}
func Benchmark_jsoniter_unicode(b *testing.B) { func Benchmark_jsoniter_unicode(b *testing.B) {
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter := ParseString(ConfigDefault, `"\ud83d\udc4a"`) iter := ParseString(`"\ud83d\udc4a"`)
iter.ReadString() iter.ReadString()
} }
} }
func Benchmark_jsoniter_ascii(b *testing.B) { func Benchmark_jsoniter_ascii(b *testing.B) {
iter := NewIterator(ConfigDefault) iter := NewIterator()
input := []byte(`"hello, world! hello, world!"`) input := []byte(`"hello, world! hello, world!"`)
b.ResetTimer() b.ResetTimer()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
@ -238,7 +130,7 @@ func Benchmark_jsoniter_ascii(b *testing.B) {
} }
func Benchmark_jsoniter_string_as_bytes(b *testing.B) { func Benchmark_jsoniter_string_as_bytes(b *testing.B) {
iter := ParseString(ConfigDefault, `"hello, world!"`) iter := ParseString(`"hello, world!"`)
b.ResetTimer() b.ResetTimer()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter.ResetBytes(iter.buf) iter.ResetBytes(iter.buf)

View File

@ -1,267 +0,0 @@
package jsoniter
import (
"github.com/stretchr/testify/require"
"testing"
)
func Test_decode_one_field_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"field1": "hello"}`, &obj))
should.Equal("hello", obj.Field1)
}
func Test_decode_two_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "stream"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("stream", obj.Field2)
}
func Test_decode_three_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "stream", "Field3": "c"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("stream", obj.Field2)
should.Equal("c", obj.Field3)
}
func Test_decode_four_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
Field4 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("stream", obj.Field2)
should.Equal("c", obj.Field3)
should.Equal("d", obj.Field4)
}
func Test_decode_five_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
Field4 string
Field5 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("stream", obj.Field2)
should.Equal("c", obj.Field3)
should.Equal("d", obj.Field4)
should.Equal("e", obj.Field5)
}
func Test_decode_six_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
Field4 string
Field5 string
Field6 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e", "Field6": "x"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("stream", obj.Field2)
should.Equal("c", obj.Field3)
should.Equal("d", obj.Field4)
should.Equal("e", obj.Field5)
should.Equal("x", obj.Field6)
}
func Test_decode_seven_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
Field4 string
Field5 string
Field6 string
Field7 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e", "Field6": "x", "Field7":"y"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("stream", obj.Field2)
should.Equal("c", obj.Field3)
should.Equal("d", obj.Field4)
should.Equal("e", obj.Field5)
should.Equal("x", obj.Field6)
should.Equal("y", obj.Field7)
}
func Test_decode_eight_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
Field4 string
Field5 string
Field6 string
Field7 string
Field8 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field8":"1", "Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e", "Field6": "x", "Field7":"y"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("stream", obj.Field2)
should.Equal("c", obj.Field3)
should.Equal("d", obj.Field4)
should.Equal("e", obj.Field5)
should.Equal("x", obj.Field6)
should.Equal("y", obj.Field7)
should.Equal("1", obj.Field8)
}
func Test_decode_nine_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
Field4 string
Field5 string
Field6 string
Field7 string
Field8 string
Field9 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field8" : "zzzzzzzzzzz", "Field7": "zz", "Field6" : "xx", "Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e", "Field9":"f"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("stream", obj.Field2)
should.Equal("c", obj.Field3)
should.Equal("d", obj.Field4)
should.Equal("e", obj.Field5)
should.Equal("xx", obj.Field6)
should.Equal("zz", obj.Field7)
should.Equal("zzzzzzzzzzz", obj.Field8)
should.Equal("f", obj.Field9)
}
func Test_decode_ten_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
Field4 string
Field5 string
Field6 string
Field7 string
Field8 string
Field9 string
Field10 string
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"Field10":"x", "Field9": "x", "Field8":"x", "Field7":"x", "Field6":"x", "Field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("stream", obj.Field2)
should.Equal("c", obj.Field3)
should.Equal("d", obj.Field4)
should.Equal("e", obj.Field5)
should.Equal("x", obj.Field6)
should.Equal("x", obj.Field7)
should.Equal("x", obj.Field8)
should.Equal("x", obj.Field9)
should.Equal("x", obj.Field10)
}
func Test_decode_more_than_ten_fields_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
Field2 string
Field3 string
Field4 string
Field5 string
Field6 string
Field7 string
Field8 string
Field9 string
Field10 string
Field11 int
}
obj := TestObject{}
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("", obj.Field1)
should.Nil(UnmarshalFromString(`{"field11":1, "field1": "a", "Field2": "stream", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
should.Equal("a", obj.Field1)
should.Equal("stream", obj.Field2)
should.Equal("c", obj.Field3)
should.Equal("d", obj.Field4)
should.Equal("e", obj.Field5)
should.Equal(1, obj.Field11)
}
func Test_decode_struct_field_with_tag(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string `json:"field-1"`
Field2 string `json:"-"`
Field3 int `json:",string"`
}
obj := TestObject{Field2: "world"}
UnmarshalFromString(`{"field-1": "hello", "field2": "", "Field3": "100"}`, &obj)
should.Equal("hello", obj.Field1)
should.Equal("world", obj.Field2)
should.Equal(100, obj.Field3)
}
func Test_decode_struct_field_with_tag_string(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 int `json:",string"`
}
obj := TestObject{Field1: 100}
should.Nil(UnmarshalFromString(`{"Field1": "100"}`, &obj))
should.Equal(100, obj.Field1)
}

View File

@ -1,118 +0,0 @@
package jsoniter
import (
"testing"
"github.com/stretchr/testify/require"
)
func Test_wrap_and_valuetype_everything(t *testing.T) {
should := require.New(t)
var i interface{}
any := Get([]byte("123"))
// default of number type is float64
i = float64(123)
should.Equal(i, any.GetInterface())
any = Wrap(int8(10))
should.Equal(any.ValueType(), NumberValue)
should.Equal(any.LastError(), nil)
// get interface is not int8 interface
// i = int8(10)
// should.Equal(i, any.GetInterface())
any = Wrap(int16(10))
should.Equal(any.ValueType(), NumberValue)
should.Equal(any.LastError(), nil)
//i = int16(10)
//should.Equal(i, any.GetInterface())
any = Wrap(int32(10))
should.Equal(any.ValueType(), NumberValue)
should.Equal(any.LastError(), nil)
i = int32(10)
should.Equal(i, any.GetInterface())
any = Wrap(int64(10))
should.Equal(any.ValueType(), NumberValue)
should.Equal(any.LastError(), nil)
i = int64(10)
should.Equal(i, any.GetInterface())
any = Wrap(uint(10))
should.Equal(any.ValueType(), NumberValue)
should.Equal(any.LastError(), nil)
// not equal
//i = uint(10)
//should.Equal(i, any.GetInterface())
any = Wrap(uint8(10))
should.Equal(any.ValueType(), NumberValue)
should.Equal(any.LastError(), nil)
// not equal
// i = uint8(10)
// should.Equal(i, any.GetInterface())
any = Wrap(uint16(10))
should.Equal(any.ValueType(), NumberValue)
should.Equal(any.LastError(), nil)
any = Wrap(uint32(10))
should.Equal(any.ValueType(), NumberValue)
should.Equal(any.LastError(), nil)
i = uint32(10)
should.Equal(i, any.GetInterface())
any = Wrap(uint64(10))
should.Equal(any.ValueType(), NumberValue)
should.Equal(any.LastError(), nil)
i = uint64(10)
should.Equal(i, any.GetInterface())
any = Wrap(float32(10))
should.Equal(any.ValueType(), NumberValue)
should.Equal(any.LastError(), nil)
// not equal
//i = float32(10)
//should.Equal(i, any.GetInterface())
any = Wrap(float64(10))
should.Equal(any.ValueType(), NumberValue)
should.Equal(any.LastError(), nil)
i = float64(10)
should.Equal(i, any.GetInterface())
any = Wrap(true)
should.Equal(any.ValueType(), BoolValue)
should.Equal(any.LastError(), nil)
i = true
should.Equal(i, any.GetInterface())
any = Wrap(false)
should.Equal(any.ValueType(), BoolValue)
should.Equal(any.LastError(), nil)
i = false
should.Equal(i, any.GetInterface())
any = Wrap(nil)
should.Equal(any.ValueType(), NilValue)
should.Equal(any.LastError(), nil)
i = nil
should.Equal(i, any.GetInterface())
stream := NewStream(ConfigDefault, nil, 32)
any.WriteTo(stream)
should.Equal("null", string(stream.Buffer()))
should.Equal(any.LastError(), nil)
any = Wrap(struct{ age int }{age: 1})
should.Equal(any.ValueType(), ObjectValue)
should.Equal(any.LastError(), nil)
i = struct{ age int }{age: 1}
should.Equal(i, any.GetInterface())
any = Wrap(map[string]interface{}{"abc": 1})
should.Equal(any.ValueType(), ObjectValue)
should.Equal(any.LastError(), nil)
i = map[string]interface{}{"abc": 1}
should.Equal(i, any.GetInterface())
any = Wrap("abc")
i = "abc"
should.Equal(i, any.GetInterface())
should.Equal(nil, any.LastError())
}

View File

@ -1,152 +0,0 @@
package test
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"testing"
"github.com/davecgh/go-spew/spew"
fuzz "github.com/google/gofuzz"
jsoniter "github.com/json-iterator/go"
)
func Test_Roundtrip(t *testing.T) {
fz := fuzz.New().MaxDepth(10).NilChance(0.3)
for i := 0; i < 100; i++ {
var before typeForTest
fz.Fuzz(&before)
jbStd, err := json.Marshal(before)
if err != nil {
t.Fatalf("failed to marshal with stdlib: %v", err)
}
if len(strings.TrimSpace(string(jbStd))) == 0 {
t.Fatal("stdlib marshal produced empty result and no error")
}
jbIter, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(before)
if err != nil {
t.Fatalf("failed to marshal with jsoniter: %v", err)
}
if len(strings.TrimSpace(string(jbIter))) == 0 {
t.Fatal("jsoniter marshal produced empty result and no error")
}
if string(jbStd) != string(jbIter) {
t.Fatalf("marshal expected:\n %s\ngot:\n %s\nobj:\n %s",
indent(jbStd, " "), indent(jbIter, " "), dump(before))
}
var afterStd typeForTest
err = json.Unmarshal(jbIter, &afterStd)
if err != nil {
t.Fatalf("failed to unmarshal with stdlib: %v\nvia:\n %s",
err, indent(jbIter, " "))
}
var afterIter typeForTest
err = jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(jbIter, &afterIter)
if err != nil {
t.Fatalf("failed to unmarshal with jsoniter: %v\nvia:\n %s",
err, indent(jbIter, " "))
}
if fingerprint(afterStd) != fingerprint(afterIter) {
t.Fatalf("unmarshal expected:\n %s\ngot:\n %s\nvia:\n %s",
dump(afterStd), dump(afterIter), indent(jbIter, " "))
}
}
}
const indentStr = "> "
func fingerprint(obj interface{}) string {
c := spew.ConfigState{
SortKeys: true,
SpewKeys: true,
}
return c.Sprintf("%v", obj)
}
func dump(obj interface{}) string {
cfg := spew.ConfigState{
Indent: indentStr,
}
return cfg.Sdump(obj)
}
func indent(src []byte, prefix string) string {
var buf bytes.Buffer
err := json.Indent(&buf, src, prefix, indentStr)
if err != nil {
return fmt.Sprintf("!!! %v", err)
}
return buf.String()
}
func benchmarkMarshal(t *testing.B, name string, fn func(interface{}) ([]byte, error)) {
t.ReportAllocs()
t.ResetTimer()
var obj typeForTest
fz := fuzz.NewWithSeed(0).MaxDepth(10).NilChance(0.3)
fz.Fuzz(&obj)
for i := 0; i < t.N; i++ {
jb, err := fn(obj)
if err != nil {
t.Fatalf("%s failed to marshal:\n input: %s\n error: %v", name, dump(obj), err)
}
_ = jb
}
}
func benchmarkUnmarshal(t *testing.B, name string, fn func(data []byte, v interface{}) error) {
t.ReportAllocs()
t.ResetTimer()
var before typeForTest
fz := fuzz.NewWithSeed(0).MaxDepth(10).NilChance(0.3)
fz.Fuzz(&before)
jb, err := json.Marshal(before)
if err != nil {
t.Fatalf("failed to marshal: %v", err)
}
for i := 0; i < t.N; i++ {
var after typeForTest
err = fn(jb, &after)
if err != nil {
t.Fatalf("%s failed to unmarshal:\n input: %q\n error: %v", name, string(jb), err)
}
}
}
func BenchmarkStandardMarshal(t *testing.B) {
benchmarkMarshal(t, "stdlib", json.Marshal)
}
func BenchmarkStandardUnmarshal(t *testing.B) {
benchmarkUnmarshal(t, "stdlib", json.Unmarshal)
}
func BenchmarkJSONIterMarshalFastest(t *testing.B) {
benchmarkMarshal(t, "jsoniter-fastest", jsoniter.ConfigFastest.Marshal)
}
func BenchmarkJSONIterUnmarshalFastest(t *testing.B) {
benchmarkUnmarshal(t, "jsoniter-fastest", jsoniter.ConfigFastest.Unmarshal)
}
func BenchmarkJSONIterMarshalDefault(t *testing.B) {
benchmarkMarshal(t, "jsoniter-default", jsoniter.Marshal)
}
func BenchmarkJSONIterUnmarshalDefault(t *testing.B) {
benchmarkUnmarshal(t, "jsoniter-default", jsoniter.Unmarshal)
}
func BenchmarkJSONIterMarshalCompatible(t *testing.B) {
benchmarkMarshal(t, "jsoniter-compat", jsoniter.ConfigCompatibleWithStandardLibrary.Marshal)
}
func BenchmarkJSONIterUnmarshalCompatible(t *testing.B) {
benchmarkUnmarshal(t, "jsoniter-compat", jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal)
}

View File

@ -1,3 +0,0 @@
package test
type typeForTest [4][4]bool

View File

@ -1,152 +0,0 @@
package test
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"testing"
"github.com/davecgh/go-spew/spew"
fuzz "github.com/google/gofuzz"
jsoniter "github.com/json-iterator/go"
)
func Test_Roundtrip(t *testing.T) {
fz := fuzz.New().MaxDepth(10).NilChance(0.3)
for i := 0; i < 100; i++ {
var before typeForTest
fz.Fuzz(&before)
jbStd, err := json.Marshal(before)
if err != nil {
t.Fatalf("failed to marshal with stdlib: %v", err)
}
if len(strings.TrimSpace(string(jbStd))) == 0 {
t.Fatal("stdlib marshal produced empty result and no error")
}
jbIter, err := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(before)
if err != nil {
t.Fatalf("failed to marshal with jsoniter: %v", err)
}
if len(strings.TrimSpace(string(jbIter))) == 0 {
t.Fatal("jsoniter marshal produced empty result and no error")
}
if string(jbStd) != string(jbIter) {
t.Fatalf("marshal expected:\n %s\ngot:\n %s\nobj:\n %s",
indent(jbStd, " "), indent(jbIter, " "), dump(before))
}
var afterStd typeForTest
err = json.Unmarshal(jbIter, &afterStd)
if err != nil {
t.Fatalf("failed to unmarshal with stdlib: %v\nvia:\n %s",
err, indent(jbIter, " "))
}
var afterIter typeForTest
err = jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(jbIter, &afterIter)
if err != nil {
t.Fatalf("failed to unmarshal with jsoniter: %v\nvia:\n %s",
err, indent(jbIter, " "))
}
if fingerprint(afterStd) != fingerprint(afterIter) {
t.Fatalf("unmarshal expected:\n %s\ngot:\n %s\nvia:\n %s",
dump(afterStd), dump(afterIter), indent(jbIter, " "))
}
}
}
const indentStr = "> "
func fingerprint(obj interface{}) string {
c := spew.ConfigState{
SortKeys: true,
SpewKeys: true,
}
return c.Sprintf("%v", obj)
}
func dump(obj interface{}) string {
cfg := spew.ConfigState{
Indent: indentStr,
}
return cfg.Sdump(obj)
}
func indent(src []byte, prefix string) string {
var buf bytes.Buffer
err := json.Indent(&buf, src, prefix, indentStr)
if err != nil {
return fmt.Sprintf("!!! %v", err)
}
return buf.String()
}
func benchmarkMarshal(t *testing.B, name string, fn func(interface{}) ([]byte, error)) {
t.ReportAllocs()
t.ResetTimer()
var obj typeForTest
fz := fuzz.NewWithSeed(0).MaxDepth(10).NilChance(0.3)
fz.Fuzz(&obj)
for i := 0; i < t.N; i++ {
jb, err := fn(obj)
if err != nil {
t.Fatalf("%s failed to marshal:\n input: %s\n error: %v", name, dump(obj), err)
}
_ = jb
}
}
func benchmarkUnmarshal(t *testing.B, name string, fn func(data []byte, v interface{}) error) {
t.ReportAllocs()
t.ResetTimer()
var before typeForTest
fz := fuzz.NewWithSeed(0).MaxDepth(10).NilChance(0.3)
fz.Fuzz(&before)
jb, err := json.Marshal(before)
if err != nil {
t.Fatalf("failed to marshal: %v", err)
}
for i := 0; i < t.N; i++ {
var after typeForTest
err = fn(jb, &after)
if err != nil {
t.Fatalf("%s failed to unmarshal:\n input: %q\n error: %v", name, string(jb), err)
}
}
}
func BenchmarkStandardMarshal(t *testing.B) {
benchmarkMarshal(t, "stdlib", json.Marshal)
}
func BenchmarkStandardUnmarshal(t *testing.B) {
benchmarkUnmarshal(t, "stdlib", json.Unmarshal)
}
func BenchmarkJSONIterMarshalFastest(t *testing.B) {
benchmarkMarshal(t, "jsoniter-fastest", jsoniter.ConfigFastest.Marshal)
}
func BenchmarkJSONIterUnmarshalFastest(t *testing.B) {
benchmarkUnmarshal(t, "jsoniter-fastest", jsoniter.ConfigFastest.Unmarshal)
}
func BenchmarkJSONIterMarshalDefault(t *testing.B) {
benchmarkMarshal(t, "jsoniter-default", jsoniter.Marshal)
}
func BenchmarkJSONIterUnmarshalDefault(t *testing.B) {
benchmarkUnmarshal(t, "jsoniter-default", jsoniter.Unmarshal)
}
func BenchmarkJSONIterMarshalCompatible(t *testing.B) {
benchmarkMarshal(t, "jsoniter-compat", jsoniter.ConfigCompatibleWithStandardLibrary.Marshal)
}
func BenchmarkJSONIterUnmarshalCompatible(t *testing.B) {
benchmarkUnmarshal(t, "jsoniter-compat", jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal)
}

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