You've already forked json-iterator
mirror of
https://github.com/json-iterator/go.git
synced 2025-06-15 22:50:24 +02:00
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
6ed27152e0 | |||
3c298d8a76 | |||
9f6e5962a9 | |||
c463aa12c4 | |||
b5d2607a6d | |||
48cc4d965a | |||
c59c42fda0 | |||
8324374402 | |||
2017f3866b | |||
ddc5af4512 | |||
2f7e5c8dd7 | |||
92772579dd | |||
ae57d167e8 | |||
eef35e549b | |||
005d86dc44 | |||
e658f6597a | |||
f8eb43eda3 | |||
18a241d40b | |||
0fdf883ac0 | |||
34fbec74ad | |||
90574c5ca3 | |||
6a4ba7bfa9 | |||
0828e559d0 | |||
2c67d0f68a | |||
f29a0391bc | |||
374e68a144 | |||
b134d86290 | |||
bc3221879d | |||
8c7fc7584a | |||
db32ee8c2d | |||
d80309af3b |
@ -2,6 +2,7 @@ language: go
|
|||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.8.x
|
- 1.8.x
|
||||||
|
- 1.x
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- go get -t -v ./...
|
- go get -t -v ./...
|
||||||
|
@ -76,5 +76,7 @@ Contributors
|
|||||||
* [thockin](https://github.com/thockin)
|
* [thockin](https://github.com/thockin)
|
||||||
* [mattn](https://github.com/mattn)
|
* [mattn](https://github.com/mattn)
|
||||||
* [cch123](https://github.com/cch123)
|
* [cch123](https://github.com/cch123)
|
||||||
|
* [Oleg Shaldybin](https://github.com/olegshaldybin)
|
||||||
|
* [Jason Toffaletti](https://github.com/toffaletti)
|
||||||
|
|
||||||
Report issue or pull request, or email taowen@gmail.com, or [](https://gitter.im/json-iterator/Lobby)
|
Report issue or pull request, or email taowen@gmail.com, or [](https://gitter.im/json-iterator/Lobby)
|
||||||
|
@ -2,11 +2,13 @@ package extra
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/json-iterator/go"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/json-iterator/go"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxUint = ^uint(0)
|
const maxUint = ^uint(0)
|
||||||
@ -199,6 +201,12 @@ func (decoder *fuzzyIntegerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It
|
|||||||
str = string(number)
|
str = string(number)
|
||||||
case jsoniter.StringValue:
|
case jsoniter.StringValue:
|
||||||
str = iter.ReadString()
|
str = iter.ReadString()
|
||||||
|
case jsoniter.BoolValue:
|
||||||
|
if iter.ReadBool() {
|
||||||
|
str = "1"
|
||||||
|
} else {
|
||||||
|
str = "0"
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
iter.ReportError("fuzzyIntegerDecoder", "not number or string")
|
iter.ReportError("fuzzyIntegerDecoder", "not number or string")
|
||||||
}
|
}
|
||||||
@ -206,7 +214,7 @@ func (decoder *fuzzyIntegerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It
|
|||||||
defer iter.Pool().ReturnIterator(newIter)
|
defer iter.Pool().ReturnIterator(newIter)
|
||||||
isFloat := strings.IndexByte(str, '.') != -1
|
isFloat := strings.IndexByte(str, '.') != -1
|
||||||
decoder.fun(isFloat, ptr, newIter)
|
decoder.fun(isFloat, ptr, newIter)
|
||||||
if newIter.Error != nil {
|
if newIter.Error != nil && newIter.Error != io.EOF {
|
||||||
iter.Error = newIter.Error
|
iter.Error = newIter.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,9 +233,16 @@ func (decoder *fuzzyFloat32Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It
|
|||||||
newIter := iter.Pool().BorrowIterator([]byte(str))
|
newIter := iter.Pool().BorrowIterator([]byte(str))
|
||||||
defer iter.Pool().ReturnIterator(newIter)
|
defer iter.Pool().ReturnIterator(newIter)
|
||||||
*((*float32)(ptr)) = newIter.ReadFloat32()
|
*((*float32)(ptr)) = newIter.ReadFloat32()
|
||||||
if newIter.Error != nil {
|
if newIter.Error != nil && newIter.Error != io.EOF {
|
||||||
iter.Error = newIter.Error
|
iter.Error = newIter.Error
|
||||||
}
|
}
|
||||||
|
case jsoniter.BoolValue:
|
||||||
|
// support bool to float32
|
||||||
|
if iter.ReadBool() {
|
||||||
|
*((*float32)(ptr)) = 1
|
||||||
|
} else {
|
||||||
|
*((*float32)(ptr)) = 0
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
iter.ReportError("fuzzyFloat32Decoder", "not number or string")
|
iter.ReportError("fuzzyFloat32Decoder", "not number or string")
|
||||||
}
|
}
|
||||||
@ -247,9 +262,16 @@ func (decoder *fuzzyFloat64Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.It
|
|||||||
newIter := iter.Pool().BorrowIterator([]byte(str))
|
newIter := iter.Pool().BorrowIterator([]byte(str))
|
||||||
defer iter.Pool().ReturnIterator(newIter)
|
defer iter.Pool().ReturnIterator(newIter)
|
||||||
*((*float64)(ptr)) = newIter.ReadFloat64()
|
*((*float64)(ptr)) = newIter.ReadFloat64()
|
||||||
if newIter.Error != nil {
|
if newIter.Error != nil && newIter.Error != io.EOF {
|
||||||
iter.Error = newIter.Error
|
iter.Error = newIter.Error
|
||||||
}
|
}
|
||||||
|
case jsoniter.BoolValue:
|
||||||
|
// support bool to float64
|
||||||
|
if iter.ReadBool() {
|
||||||
|
*((*float64)(ptr)) = 1
|
||||||
|
} else {
|
||||||
|
*((*float64)(ptr)) = 0
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
iter.ReportError("fuzzyFloat32Decoder", "not number or string")
|
iter.ReportError("fuzzyFloat32Decoder", "not number or string")
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,12 @@ func Test_any_to_int64(t *testing.T) {
|
|||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(int64(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.Nil(jsoniter.UnmarshalFromString(`-10`, &val))
|
||||||
should.Equal(int64(-10), val)
|
should.Equal(int64(-10), val)
|
||||||
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
|
should.NotNil(jsoniter.UnmarshalFromString("{}", &val))
|
||||||
@ -57,6 +63,13 @@ func Test_any_to_int(t *testing.T) {
|
|||||||
should.Equal(10, val)
|
should.Equal(10, val)
|
||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(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))
|
||||||
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
||||||
// large float to int
|
// large float to int
|
||||||
@ -74,6 +87,13 @@ func Test_any_to_int16(t *testing.T) {
|
|||||||
should.Equal(int16(10), val)
|
should.Equal(int16(10), val)
|
||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(int16(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))
|
||||||
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
||||||
// large float to int
|
// large float to int
|
||||||
@ -91,6 +111,13 @@ func Test_any_to_int32(t *testing.T) {
|
|||||||
should.Equal(int32(10), val)
|
should.Equal(int32(10), val)
|
||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(int32(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))
|
||||||
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
||||||
// large float to int
|
// large float to int
|
||||||
@ -108,6 +135,13 @@ func Test_any_to_int8(t *testing.T) {
|
|||||||
should.Equal(int8(10), val)
|
should.Equal(int8(10), val)
|
||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(int8(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))
|
||||||
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
||||||
// large float to int
|
// large float to int
|
||||||
@ -125,6 +159,13 @@ func Test_any_to_uint8(t *testing.T) {
|
|||||||
should.Equal(uint8(10), val)
|
should.Equal(uint8(10), val)
|
||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(uint8(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))
|
||||||
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
||||||
// large float to int
|
// large float to int
|
||||||
@ -144,6 +185,12 @@ func Test_any_to_uint64(t *testing.T) {
|
|||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(uint64(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?
|
// TODO fix?
|
||||||
should.NotNil(jsoniter.UnmarshalFromString(`-10`, &val))
|
should.NotNil(jsoniter.UnmarshalFromString(`-10`, &val))
|
||||||
should.Equal(uint64(0), val)
|
should.Equal(uint64(0), val)
|
||||||
@ -165,6 +212,12 @@ func Test_any_to_uint32(t *testing.T) {
|
|||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(uint32(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?
|
// TODO fix?
|
||||||
should.NotNil(jsoniter.UnmarshalFromString(`-10`, &val))
|
should.NotNil(jsoniter.UnmarshalFromString(`-10`, &val))
|
||||||
should.Equal(uint32(0), val)
|
should.Equal(uint32(0), val)
|
||||||
@ -186,6 +239,12 @@ func Test_any_to_uint16(t *testing.T) {
|
|||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(uint16(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?
|
// TODO fix?
|
||||||
should.NotNil(jsoniter.UnmarshalFromString(`-10`, &val))
|
should.NotNil(jsoniter.UnmarshalFromString(`-10`, &val))
|
||||||
should.Equal(uint16(0), val)
|
should.Equal(uint16(0), val)
|
||||||
@ -205,6 +264,12 @@ func Test_any_to_uint(t *testing.T) {
|
|||||||
should.Equal(uint(10), val)
|
should.Equal(uint(10), val)
|
||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(uint(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))
|
||||||
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
||||||
// large float to int
|
// large float to int
|
||||||
@ -223,6 +288,13 @@ func Test_any_to_float32(t *testing.T) {
|
|||||||
should.Equal(float32(10.1), val)
|
should.Equal(float32(10.1), val)
|
||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(float32(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))
|
||||||
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
||||||
}
|
}
|
||||||
@ -240,6 +312,13 @@ func Test_any_to_float64(t *testing.T) {
|
|||||||
should.Equal(float64(10.1), val)
|
should.Equal(float64(10.1), val)
|
||||||
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`10`, &val))
|
||||||
should.Equal(float64(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))
|
||||||
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
should.NotNil(jsoniter.UnmarshalFromString("[]", &val))
|
||||||
}
|
}
|
||||||
@ -257,3 +336,24 @@ func Test_empty_array_as_object(t *testing.T) {
|
|||||||
should.Nil(jsoniter.UnmarshalFromString(`[]`, &val))
|
should.Nil(jsoniter.UnmarshalFromString(`[]`, &val))
|
||||||
should.Equal(struct{}{}, 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)
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@ type Config struct {
|
|||||||
SortMapKeys bool
|
SortMapKeys bool
|
||||||
UseNumber bool
|
UseNumber bool
|
||||||
TagKey string
|
TagKey string
|
||||||
|
ValidateJsonRawMessage bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type frozenConfig struct {
|
type frozenConfig struct {
|
||||||
@ -55,6 +56,7 @@ var ConfigDefault = Config{
|
|||||||
var ConfigCompatibleWithStandardLibrary = Config{
|
var ConfigCompatibleWithStandardLibrary = Config{
|
||||||
EscapeHTML: true,
|
EscapeHTML: true,
|
||||||
SortMapKeys: true,
|
SortMapKeys: true,
|
||||||
|
ValidateJsonRawMessage: true,
|
||||||
}.Froze()
|
}.Froze()
|
||||||
|
|
||||||
// ConfigFastest marshals float with only 6 digits precision
|
// ConfigFastest marshals float with only 6 digits precision
|
||||||
@ -83,10 +85,31 @@ func (cfg Config) Froze() API {
|
|||||||
if cfg.UseNumber {
|
if cfg.UseNumber {
|
||||||
frozenConfig.useNumber()
|
frozenConfig.useNumber()
|
||||||
}
|
}
|
||||||
|
if cfg.ValidateJsonRawMessage {
|
||||||
|
frozenConfig.validateJsonRawMessage()
|
||||||
|
}
|
||||||
frozenConfig.configBeforeFrozen = cfg
|
frozenConfig.configBeforeFrozen = cfg
|
||||||
return frozenConfig
|
return frozenConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cfg *frozenConfig) validateJsonRawMessage() {
|
||||||
|
encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) {
|
||||||
|
rawMessage := *(*json.RawMessage)(ptr)
|
||||||
|
iter := cfg.BorrowIterator([]byte(rawMessage))
|
||||||
|
iter.Read()
|
||||||
|
if iter.Error != nil {
|
||||||
|
stream.WriteRaw("null")
|
||||||
|
} else {
|
||||||
|
cfg.ReturnIterator(iter)
|
||||||
|
stream.WriteRaw(string(rawMessage))
|
||||||
|
}
|
||||||
|
}, func(ptr unsafe.Pointer) bool {
|
||||||
|
return false
|
||||||
|
}}
|
||||||
|
cfg.addEncoderToCache(reflect.TypeOf((*json.RawMessage)(nil)).Elem(), encoder)
|
||||||
|
cfg.addEncoderToCache(reflect.TypeOf((*RawMessage)(nil)).Elem(), encoder)
|
||||||
|
}
|
||||||
|
|
||||||
func (cfg *frozenConfig) useNumber() {
|
func (cfg *frozenConfig) useNumber() {
|
||||||
cfg.addDecoderToCache(reflect.TypeOf((*interface{})(nil)).Elem(), &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) {
|
cfg.addDecoderToCache(reflect.TypeOf((*interface{})(nil)).Elem(), &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
if iter.WhatIsNext() == NumberValue {
|
if iter.WhatIsNext() == NumberValue {
|
||||||
|
@ -64,7 +64,7 @@ func (iter *Iterator) trySkipString() bool {
|
|||||||
} else if c == '\\' {
|
} else if c == '\\' {
|
||||||
return false
|
return false
|
||||||
} else if c < ' ' {
|
} else if c < ' ' {
|
||||||
iter.ReportError("ReadString",
|
iter.ReportError("trySkipString",
|
||||||
fmt.Sprintf(`invalid control character found: %d`, c))
|
fmt.Sprintf(`invalid control character found: %d`, c))
|
||||||
return true // already failed
|
return true // already failed
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ func (iter *Iterator) readStringSlowPath() (ret string) {
|
|||||||
str = append(str, c)
|
str = append(str, c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iter.ReportError("ReadString", "unexpected end of input")
|
iter.ReportError("readStringSlowPath", "unexpected end of input")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ func (iter *Iterator) readEscapedChar(c byte, str []byte) []byte {
|
|||||||
case 't':
|
case 't':
|
||||||
str = append(str, '\t')
|
str = append(str, '\t')
|
||||||
default:
|
default:
|
||||||
iter.ReportError("ReadString",
|
iter.ReportError("readEscapedChar",
|
||||||
`invalid escape char after \`)
|
`invalid escape char after \`)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ func (iter *Iterator) ReadStringAsSlice() (ret []byte) {
|
|||||||
}
|
}
|
||||||
return copied
|
return copied
|
||||||
}
|
}
|
||||||
iter.ReportError("ReadString", `expects " or n`)
|
iter.ReportError("ReadStringAsSlice", `expects " or n`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,11 +154,11 @@ func (encoder *placeholderEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (encoder *placeholderEncoder) getRealEncoder() ValEncoder {
|
func (encoder *placeholderEncoder) getRealEncoder() ValEncoder {
|
||||||
for i := 0; i < 30; i++ {
|
for i := 0; i < 500; i++ {
|
||||||
realDecoder := encoder.cfg.getEncoderFromCache(encoder.cacheKey)
|
realDecoder := encoder.cfg.getEncoderFromCache(encoder.cacheKey)
|
||||||
_, isPlaceholder := realDecoder.(*placeholderEncoder)
|
_, isPlaceholder := realDecoder.(*placeholderEncoder)
|
||||||
if isPlaceholder {
|
if isPlaceholder {
|
||||||
time.Sleep(time.Second)
|
time.Sleep(10 * time.Millisecond)
|
||||||
} else {
|
} else {
|
||||||
return realDecoder
|
return realDecoder
|
||||||
}
|
}
|
||||||
@ -172,11 +172,11 @@ type placeholderDecoder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (decoder *placeholderDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (decoder *placeholderDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
for i := 0; i < 30; i++ {
|
for i := 0; i < 500; i++ {
|
||||||
realDecoder := decoder.cfg.getDecoderFromCache(decoder.cacheKey)
|
realDecoder := decoder.cfg.getDecoderFromCache(decoder.cacheKey)
|
||||||
_, isPlaceholder := realDecoder.(*placeholderDecoder)
|
_, isPlaceholder := realDecoder.(*placeholderDecoder)
|
||||||
if isPlaceholder {
|
if isPlaceholder {
|
||||||
time.Sleep(time.Second)
|
time.Sleep(10 * time.Millisecond)
|
||||||
} else {
|
} else {
|
||||||
realDecoder.Decode(ptr, iter)
|
realDecoder.Decode(ptr, iter)
|
||||||
return
|
return
|
||||||
@ -466,6 +466,18 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error
|
|||||||
}
|
}
|
||||||
return encoder, nil
|
return encoder, nil
|
||||||
}
|
}
|
||||||
|
if reflect.PtrTo(typ).Implements(marshalerType) {
|
||||||
|
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) {
|
if typ.Implements(textMarshalerType) {
|
||||||
checkIsEmpty, err := createCheckIsEmpty(typ)
|
checkIsEmpty, err := createCheckIsEmpty(typ)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding"
|
"encoding"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,8 +32,10 @@ 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)))
|
||||||
@ -50,8 +53,10 @@ type uintptrCodec struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (codec *uintptrCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (codec *uintptrCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
if !iter.ReadNil() {
|
||||||
*((*uintptr)(ptr)) = uintptr(iter.ReadUint64())
|
*((*uintptr)(ptr)) = uintptr(iter.ReadUint64())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (codec *uintptrCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
func (codec *uintptrCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||||
stream.WriteUint64(uint64(*((*uintptr)(ptr))))
|
stream.WriteUint64(uint64(*((*uintptr)(ptr))))
|
||||||
@ -69,8 +74,10 @@ 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)))
|
||||||
@ -88,8 +95,10 @@ 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)))
|
||||||
@ -107,8 +116,10 @@ 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)))
|
||||||
@ -126,8 +137,10 @@ 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)))
|
||||||
@ -145,7 +158,10 @@ type uintCodec struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (codec *uintCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (codec *uintCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
if !iter.ReadNil() {
|
||||||
*((*uint)(ptr)) = iter.ReadUint()
|
*((*uint)(ptr)) = iter.ReadUint()
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (codec *uintCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
func (codec *uintCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||||
@ -164,8 +180,10 @@ 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)))
|
||||||
@ -183,8 +201,10 @@ type uint16Codec struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (codec *uint16Codec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
if !iter.ReadNil() {
|
||||||
*((*uint16)(ptr)) = iter.ReadUint16()
|
*((*uint16)(ptr)) = iter.ReadUint16()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
func (codec *uint16Codec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||||
stream.WriteUint16(*((*uint16)(ptr)))
|
stream.WriteUint16(*((*uint16)(ptr)))
|
||||||
@ -202,8 +222,10 @@ 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)))
|
||||||
@ -221,8 +243,10 @@ 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)))
|
||||||
@ -240,8 +264,10 @@ 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)))
|
||||||
@ -259,8 +285,10 @@ 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)))
|
||||||
@ -278,8 +306,10 @@ 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)))
|
||||||
@ -297,8 +327,43 @@ type emptyInterfaceCodec struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
existing := *((*interface{})(ptr))
|
||||||
|
|
||||||
|
// Checking for both typed and untyped nil pointers.
|
||||||
|
if existing != nil &&
|
||||||
|
reflect.TypeOf(existing).Kind() == reflect.Ptr &&
|
||||||
|
!reflect.ValueOf(existing).IsNil() {
|
||||||
|
|
||||||
|
var ptrToExisting interface{}
|
||||||
|
for {
|
||||||
|
elem := reflect.ValueOf(existing).Elem()
|
||||||
|
if elem.Kind() != reflect.Ptr || elem.IsNil() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ptrToExisting = existing
|
||||||
|
existing = elem.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
if iter.ReadNil() {
|
||||||
|
if ptrToExisting != nil {
|
||||||
|
nilPtr := reflect.Zero(reflect.TypeOf(ptrToExisting).Elem())
|
||||||
|
reflect.ValueOf(ptrToExisting).Elem().Set(nilPtr)
|
||||||
|
} else {
|
||||||
|
*((*interface{})(ptr)) = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
iter.ReadVal(existing)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if iter.ReadNil() {
|
||||||
|
*((*interface{})(ptr)) = nil
|
||||||
|
} else {
|
||||||
*((*interface{})(ptr)) = iter.Read()
|
*((*interface{})(ptr)) = iter.Read()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (codec *emptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
func (codec *emptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||||
stream.WriteVal(*((*interface{})(ptr)))
|
stream.WriteVal(*((*interface{})(ptr)))
|
||||||
@ -309,7 +374,8 @@ func (codec *emptyInterfaceCodec) EncodeInterface(val interface{}, stream *Strea
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (codec *emptyInterfaceCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
func (codec *emptyInterfaceCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
||||||
return ptr == nil
|
emptyInterface := (*emptyInterface)(ptr)
|
||||||
|
return emptyInterface.typ == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type nonEmptyInterfaceCodec struct {
|
type nonEmptyInterfaceCodec struct {
|
||||||
@ -326,15 +392,20 @@ func (codec *nonEmptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator)
|
|||||||
e.typ = nonEmptyInterface.itab.typ
|
e.typ = nonEmptyInterface.itab.typ
|
||||||
e.word = nonEmptyInterface.word
|
e.word = nonEmptyInterface.word
|
||||||
iter.ReadVal(&i)
|
iter.ReadVal(&i)
|
||||||
|
if e.word == nil {
|
||||||
|
nonEmptyInterface.itab = nil
|
||||||
|
}
|
||||||
nonEmptyInterface.word = e.word
|
nonEmptyInterface.word = e.word
|
||||||
}
|
}
|
||||||
|
|
||||||
func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||||
nonEmptyInterface := (*nonEmptyInterface)(ptr)
|
nonEmptyInterface := (*nonEmptyInterface)(ptr)
|
||||||
var i interface{}
|
var i interface{}
|
||||||
|
if nonEmptyInterface.itab != nil {
|
||||||
e := (*emptyInterface)(unsafe.Pointer(&i))
|
e := (*emptyInterface)(unsafe.Pointer(&i))
|
||||||
e.typ = nonEmptyInterface.itab.typ
|
e.typ = nonEmptyInterface.itab.typ
|
||||||
e.word = nonEmptyInterface.word
|
e.word = nonEmptyInterface.word
|
||||||
|
}
|
||||||
stream.WriteVal(i)
|
stream.WriteVal(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,7 +666,12 @@ func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
|||||||
templateInterface := encoder.templateInterface
|
templateInterface := encoder.templateInterface
|
||||||
templateInterface.word = ptr
|
templateInterface.word = ptr
|
||||||
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
|
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
|
||||||
marshaler := (*realInterface).(json.Marshaler)
|
marshaler, ok := (*realInterface).(json.Marshaler)
|
||||||
|
if !ok {
|
||||||
|
stream.WriteVal(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
bytes, err := marshaler.MarshalJSON()
|
bytes, err := marshaler.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stream.Error = err
|
stream.Error = err
|
||||||
|
@ -82,3 +82,32 @@ func Test_decode_string_bool(t *testing.T) {
|
|||||||
err = Unmarshal([]byte(`{"Field":true}`), &obj)
|
err = Unmarshal([]byte(`{"Field":true}`), &obj)
|
||||||
should.NotNil(err)
|
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)
|
||||||
|
}
|
||||||
|
@ -314,3 +314,27 @@ func Test_recursive_empty_interface_customization(t *testing.T) {
|
|||||||
Unmarshal([]byte("[100]"), &obj)
|
Unmarshal([]byte("[100]"), &obj)
|
||||||
should.Equal([]interface{}{int64(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)
|
||||||
|
}
|
||||||
|
50
jsoniter_enum_marshaler_test.go
Normal file
50
jsoniter_enum_marshaler_test.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
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)
|
||||||
|
}
|
@ -20,7 +20,45 @@ func Test_read_uint64_invalid(t *testing.T) {
|
|||||||
should.NotNil(iter.Error)
|
should.NotNil(iter.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_read_int8(t *testing.T) {
|
func Test_read_int_from_null(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) {
|
||||||
|
@ -2,9 +2,11 @@ package jsoniter
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/stretchr/testify/require"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_write_array_of_interface(t *testing.T) {
|
func Test_write_array_of_interface(t *testing.T) {
|
||||||
@ -297,3 +299,262 @@ func Test_array_with_nothing(t *testing.T) {
|
|||||||
should.Nil(err)
|
should.Nil(err)
|
||||||
should.Equal(`[null,null]`, output)
|
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)
|
||||||
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package jsoniter
|
package jsoniter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
"bytes"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_missing_object_end(t *testing.T) {
|
func Test_missing_object_end(t *testing.T) {
|
||||||
|
@ -3,9 +3,10 @@ package jsoniter
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_read_null(t *testing.T) {
|
func Test_read_null(t *testing.T) {
|
||||||
@ -135,3 +136,33 @@ func Test_encode_nil_array(t *testing.T) {
|
|||||||
should.Nil(err)
|
should.Nil(err)
|
||||||
should.Equal("null", string(output))
|
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)
|
||||||
|
}
|
||||||
|
@ -72,3 +72,17 @@ func Test_encode_map_of_jsoniter_raw_message(t *testing.T) {
|
|||||||
should.Nil(err)
|
should.Nil(err)
|
||||||
should.Equal(`{"hello":[]}`, output)
|
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)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user