├── value_tests
├── bool_test.go
├── number_test.go
├── array_test.go
├── raw_message_test.go
├── slice_test.go
├── ptr_test.go
├── error_test.go
├── iface_test.go
├── marshaler_test.go
├── eface_test.go
├── value_test.go
├── map_test.go
├── string_test.go
├── float_test.go
└── struct_test.go
├── test.sh
├── skip_tests
├── array_test.go
├── string_test.go
├── float64_test.go
├── struct_test.go
├── skip_test.go
└── jsoniter_skip_test.go
├── any_tests
├── jsoniter_any_null_test.go
├── jsoniter_any_map_test.go
├── jsoniter_any_bool_test.go
├── jsoniter_any_string_test.go
├── jsoniter_must_be_valid_test.go
├── jsoniter_any_float_test.go
├── jsoniter_wrap_test.go
├── jsoniter_any_object_test.go
└── jsoniter_any_array_test.go
├── extra
├── private_fields_test.go
├── binary_as_string_codec_test.go
├── time_as_int64_codec_test.go
├── time_as_int64_codec.go
├── naming_strategy_test.go
├── privat_fields.go
└── naming_strategy.go
├── api_tests
├── encoder_test.go
├── marshal_indent_test.go
├── encoder_18_test.go
├── decoder_test.go
└── config_test.go
├── type_tests
├── struct_field_case_test.go
├── map_key_test.go
├── marshaler_string_test.go
├── array_test.go
├── text_marshaler_string_test.go
├── map_test.go
├── marshaler_struct_test.go
├── text_marshaler_struct_test.go
├── builtin_test.go
├── slice_test.go
└── struct_embedded_test.go
├── benchmarks
├── encode_string_test.go
├── large-file.json
└── jsoniter_large_file_test.go
├── fuzzy_mode_convert_table.md
├── jsoniter.go
├── pool.go
├── LICENSE
├── any_nil.go
├── misc_tests
├── jsoniter_bool_test.go
├── jsoniter_nested_test.go
├── jsoniter_null_test.go
├── jsoniter_int_test.go
├── jsoniter_float_test.go
├── jsoniter_raw_message_test.go
├── jsoniter_map_test.go
├── jsoniter_object_test.go
└── jsoniter_interface_test.go
├── any_int64.go
├── any_int32.go
├── any_uint64.go
├── iter_array.go
├── any_uint32.go
├── any_float.go
├── any_invalid.go
├── reflect_dynamic.go
├── reflect_json_raw_message.go
├── stream_test.go
├── iter_skip_strict.go
├── any_bool.go
├── stream_float.go
├── reflect_slice.go
├── reflect_array.go
├── README.md
├── any_number.go
├── reflect_json_number.go
├── example_test.go
├── demo
└── example.go
├── extension_tests
├── extension_test.go
└── decoder_test.go
├── iter_skip_sloppy.go
├── any_str.go
├── iter_skip.go
├── iter_skip_sloppy_test.go
├── reflect_optional.go
└── stream_int.go
/value_tests/bool_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | func init() {
4 | unmarshalCases = append(unmarshalCases, unmarshalCase{
5 | ptr: (*struct {
6 | Field bool `json:"field"`
7 | })(nil),
8 | input: `{"field": null}`,
9 | })
10 | }
11 |
--------------------------------------------------------------------------------
/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 | echo "" > coverage.txt
5 |
6 | for d in $(go list ./... | grep -v vendor); do
7 | go test -coverprofile=profile.out -coverpkg=github.com/json-iterator/go $d
8 | if [ -f profile.out ]; then
9 | cat profile.out >> coverage.txt
10 | rm profile.out
11 | fi
12 | done
13 |
--------------------------------------------------------------------------------
/skip_tests/array_test.go:
--------------------------------------------------------------------------------
1 | package skip_tests
2 |
3 | func init() {
4 | testCases = append(testCases, testCase{
5 | ptr: (*[]interface{})(nil),
6 | inputs: []string{
7 | `[]`, // valid
8 | `[1]`, // valid
9 | `[ 1, "hello"]`, // valid
10 | `[abc]`, // invalid
11 | `[`, // invalid
12 | `[[]`, // invalid
13 | },
14 | })
15 | }
16 |
--------------------------------------------------------------------------------
/skip_tests/string_test.go:
--------------------------------------------------------------------------------
1 | package skip_tests
2 |
3 | func init() {
4 | testCases = append(testCases, testCase{
5 | ptr: (*string)(nil),
6 | inputs: []string{
7 | `""`, // valid
8 | `"hello"`, // valid
9 | `"`, // invalid
10 | `"\"`, // invalid
11 | `"\x00"`, // invalid
12 | "\"\x00\"", // invalid
13 | "\"\t\"", // invalid
14 | `"\t"`, // valid
15 | },
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/value_tests/number_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import "encoding/json"
4 |
5 | func init() {
6 | unmarshalCases = append(unmarshalCases, unmarshalCase{
7 | ptr: (*json.Number)(nil),
8 | input: `"500"`,
9 | }, unmarshalCase{
10 | ptr: (*json.Number)(nil),
11 | input: `1`,
12 | }, unmarshalCase{
13 | ptr: (*json.Number)(nil),
14 | input: `null`,
15 | })
16 | marshalCases = append(marshalCases, json.Number(""))
17 | }
18 |
--------------------------------------------------------------------------------
/any_tests/jsoniter_any_null_test.go:
--------------------------------------------------------------------------------
1 | package any_tests
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "github.com/stretchr/testify/require"
6 | "testing"
7 | )
8 |
9 | func Test_read_null_as_any(t *testing.T) {
10 | should := require.New(t)
11 | any := jsoniter.Get([]byte(`null`))
12 | should.Equal(0, any.ToInt())
13 | should.Equal(float64(0), any.ToFloat64())
14 | should.Equal("", any.ToString())
15 | should.False(any.ToBool())
16 | }
17 |
--------------------------------------------------------------------------------
/extra/private_fields_test.go:
--------------------------------------------------------------------------------
1 | package extra
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "github.com/stretchr/testify/require"
6 | "testing"
7 | )
8 |
9 | func Test_private_fields(t *testing.T) {
10 | type TestObject struct {
11 | field1 string
12 | }
13 | SupportPrivateFields()
14 | should := require.New(t)
15 | obj := TestObject{}
16 | should.Nil(jsoniter.UnmarshalFromString(`{"field1":"Hello"}`, &obj))
17 | should.Equal("Hello", obj.field1)
18 | }
19 |
--------------------------------------------------------------------------------
/value_tests/array_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | func init() {
4 | two := float64(2)
5 | marshalCases = append(marshalCases,
6 | [1]*float64{nil},
7 | [1]*float64{&two},
8 | [2]*float64{},
9 | )
10 | unmarshalCases = append(unmarshalCases, unmarshalCase{
11 | ptr: (*[0]int)(nil),
12 | input: `[1]`,
13 | }, unmarshalCase{
14 | ptr: (*[1]int)(nil),
15 | input: `[2]`,
16 | }, unmarshalCase{
17 | ptr: (*[1]int)(nil),
18 | input: `[]`,
19 | })
20 | }
21 |
--------------------------------------------------------------------------------
/skip_tests/float64_test.go:
--------------------------------------------------------------------------------
1 | package skip_tests
2 |
3 | func init() {
4 | testCases = append(testCases, testCase{
5 | ptr: (*float64)(nil),
6 | inputs: []string{
7 | "+1", // invalid
8 | "-a", // invalid
9 | "-\x00", // invalid, zero byte
10 | "0.1", // valid
11 | "0..1", // invalid, more dot
12 | "1e+1", // valid
13 | "1+1", // invalid
14 | "1E1", // valid, e or E
15 | "1ee1", // invalid
16 | "100a", // invalid
17 | "10.", // invalid
18 | },
19 | })
20 | }
21 |
--------------------------------------------------------------------------------
/api_tests/encoder_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "github.com/json-iterator/go"
7 | "github.com/stretchr/testify/require"
8 | "testing"
9 | )
10 |
11 | // Standard Encoder has trailing newline.
12 | func TestEncoderHasTrailingNewline(t *testing.T) {
13 | should := require.New(t)
14 | var buf, stdbuf bytes.Buffer
15 | enc := jsoniter.ConfigCompatibleWithStandardLibrary.NewEncoder(&buf)
16 | enc.Encode(1)
17 | stdenc := json.NewEncoder(&stdbuf)
18 | stdenc.Encode(1)
19 | should.Equal(stdbuf.Bytes(), buf.Bytes())
20 | }
21 |
--------------------------------------------------------------------------------
/value_tests/raw_message_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "encoding/json"
5 | )
6 |
7 | func init() {
8 | marshalCases = append(marshalCases,
9 | json.RawMessage("{}"),
10 | struct {
11 | Env string `json:"env"`
12 | Extra json.RawMessage `json:"extra,omitempty"`
13 | }{
14 | Env: "jfdk",
15 | },
16 | )
17 | unmarshalCases = append(unmarshalCases, unmarshalCase{
18 | ptr: (*json.RawMessage)(nil),
19 | input: `[1,2,3]`,
20 | }, unmarshalCase{
21 | ptr: (*json.RawMessage)(nil),
22 | input: `1.122e+250`,
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/type_tests/struct_field_case_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | func init() {
4 | testCases = append(testCases,
5 | (*struct {
6 | Upper bool `json:"M"`
7 | Lower bool `json:"m"`
8 | })(nil),
9 | )
10 | asymmetricTestCases = append(asymmetricTestCases, [][2]interface{}{
11 | {
12 | (*struct {
13 | Field string
14 | })(nil),
15 | (*struct {
16 | FIELD string
17 | })(nil),
18 | },
19 | {
20 | (*struct {
21 | F1 string
22 | F2 string
23 | F3 string
24 | })(nil),
25 | (*struct {
26 | F1 string
27 | })(nil),
28 | },
29 | }...)
30 | }
31 |
--------------------------------------------------------------------------------
/benchmarks/encode_string_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "bytes"
5 | "github.com/json-iterator/go"
6 | "testing"
7 | )
8 |
9 | func Benchmark_encode_string_with_SetEscapeHTML(b *testing.B) {
10 | type V struct {
11 | S string
12 | B bool
13 | I int
14 | }
15 | var json = jsoniter.ConfigCompatibleWithStandardLibrary
16 | b.ReportAllocs()
17 | for i := 0; i < b.N; i++ {
18 | buf := &bytes.Buffer{}
19 | enc := json.NewEncoder(buf)
20 | enc.SetEscapeHTML(true)
21 | if err := enc.Encode(V{S: "s", B: true, I: 233}); err != nil {
22 | b.Fatal(err)
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/skip_tests/struct_test.go:
--------------------------------------------------------------------------------
1 | package skip_tests
2 |
3 | func init() {
4 | testCases = append(testCases, testCase{
5 | ptr: (*struct{})(nil),
6 | inputs: []string{
7 | `{}`, // valid
8 | `{"hello":"world"}`, // valid
9 | `{hello:"world"}`, // invalid
10 | `{"hello:"world"}`, // invalid
11 | `{"hello","world"}`, // invalid
12 | `{"hello":{}`, // invalid
13 | `{"hello":{}}`, // valid
14 | `{"hello":{}}}`, // invalid
15 | `{"hello": { "hello": 1}}`, // valid
16 | `{abc}`, // invalid
17 | },
18 | })
19 | }
20 |
--------------------------------------------------------------------------------
/value_tests/slice_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | func init() {
4 | nilSlice := []string(nil)
5 | marshalCases = append(marshalCases,
6 | []interface{}{"hello"},
7 | nilSlice,
8 | &nilSlice,
9 | []byte{1, 2, 3},
10 | )
11 | unmarshalCases = append(unmarshalCases, unmarshalCase{
12 | ptr: (*[]string)(nil),
13 | input: "null",
14 | }, unmarshalCase{
15 | ptr: (*[]string)(nil),
16 | input: "[]",
17 | }, unmarshalCase{
18 | ptr: (*[]byte)(nil),
19 | input: "[1,2,3]",
20 | }, unmarshalCase{
21 | ptr: (*[]byte)(nil),
22 | input: `"aGVsbG8="`,
23 | }, unmarshalCase{
24 | ptr: (*[]byte)(nil),
25 | input: `"c3ViamVjdHM\/X2Q9MQ=="`,
26 | })
27 | }
28 |
--------------------------------------------------------------------------------
/value_tests/ptr_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | func init() {
4 | var pInt = func(val int) *int {
5 | return &val
6 | }
7 | marshalCases = append(marshalCases,
8 | (*int)(nil),
9 | pInt(100),
10 | )
11 | unmarshalCases = append(unmarshalCases, unmarshalCase{
12 | obj: func() interface{} {
13 | var i int
14 | return &i
15 | },
16 | input: "null",
17 | }, unmarshalCase{
18 | obj: func() interface{} {
19 | var i *int
20 | return &i
21 | },
22 | input: "10",
23 | }, unmarshalCase{
24 | obj: func() interface{} {
25 | var i int
26 | pi := &i
27 | return &pi
28 | },
29 | input: "null",
30 | }, unmarshalCase{
31 | obj: func() interface{} {
32 | var i int
33 | pi := &i
34 | ppi := &pi
35 | return &ppi
36 | },
37 | input: "null",
38 | })
39 | }
40 |
--------------------------------------------------------------------------------
/value_tests/error_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "github.com/stretchr/testify/require"
6 | "reflect"
7 | "testing"
8 | )
9 |
10 | func Test_errorInput(t *testing.T) {
11 | for _, testCase := range unmarshalCases {
12 | if testCase.obj != nil {
13 | continue
14 | }
15 | valType := reflect.TypeOf(testCase.ptr).Elem()
16 | t.Run(valType.String(), func(t *testing.T) {
17 | for _, data := range []string{
18 | `x`,
19 | `n`,
20 | `nul`,
21 | `{x}`,
22 | `{"x"}`,
23 | `{"x": "y"x}`,
24 | `{"x": "y"`,
25 | `{"x": "y", "a"}`,
26 | `[`,
27 | `[{"x": "y"}`,
28 | } {
29 | ptrVal := reflect.New(valType)
30 | ptr := ptrVal.Interface()
31 | err := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal([]byte(data), ptr)
32 | require.Error(t, err, "on input %q", data)
33 | }
34 | })
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/any_tests/jsoniter_any_map_test.go:
--------------------------------------------------------------------------------
1 | package any_tests
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "github.com/stretchr/testify/require"
6 | "testing"
7 | )
8 |
9 | func Test_wrap_map(t *testing.T) {
10 | should := require.New(t)
11 | any := jsoniter.Wrap(map[string]string{"Field1": "hello"})
12 | should.Equal("hello", any.Get("Field1").ToString())
13 | any = jsoniter.Wrap(map[string]string{"Field1": "hello"})
14 | should.Equal(1, any.Size())
15 | }
16 |
17 | func Test_map_wrapper_any_get_all(t *testing.T) {
18 | should := require.New(t)
19 | any := jsoniter.Wrap(map[string][]int{"Field1": {1, 2}})
20 | should.Equal(`{"Field1":1}`, any.Get('*', 0).ToString())
21 | should.Contains(any.Keys(), "Field1")
22 |
23 | // map write to
24 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, nil, 0)
25 | any.WriteTo(stream)
26 | // TODO cannot pass
27 | //should.Equal(string(stream.buf), "")
28 | }
29 |
--------------------------------------------------------------------------------
/fuzzy_mode_convert_table.md:
--------------------------------------------------------------------------------
1 | | json type \ dest type | bool | int | uint | float |string|
2 | | --- | --- | --- | --- |--|--|
3 | | number | positive => true
negative => true
zero => false| 23.2 => 23
-32.1 => -32| 12.1 => 12
-12.1 => 0|as normal|same as origin|
4 | | string | empty string => false
string "0" => false
other strings => true | "123.32" => 123
"-123.4" => -123
"123.23xxxw" => 123
"abcde12" => 0
"-32.1" => -32| 13.2 => 13
-1.1 => 0 |12.1 => 12.1
-12.3 => -12.3
12.4xxa => 12.4
+1.1e2 =>110 |same as origin|
5 | | bool | true => true
false => false| true => 1
false => 0 | true => 1
false => 0 |true => 1
false => 0|true => "true"
false => "false"|
6 | | object | true | 0 | 0 |0|originnal json|
7 | | array | empty array => false
nonempty array => true| [] => 0
[1,2] => 1 | [] => 0
[1,2] => 1 |[] => 0
[1,2] => 1|original json|
--------------------------------------------------------------------------------
/jsoniter.go:
--------------------------------------------------------------------------------
1 | // Package jsoniter implements encoding and decoding of JSON as defined in
2 | // RFC 4627 and provides interfaces with identical syntax of standard lib encoding/json.
3 | // Converting from encoding/json to jsoniter is no more than replacing the package with jsoniter
4 | // and variable type declarations (if any).
5 | // jsoniter interfaces gives 100% compatibility with code using standard lib.
6 | //
7 | // "JSON and Go"
8 | // (https://golang.org/doc/articles/json_and_go.html)
9 | // gives a description of how Marshal/Unmarshal operate
10 | // between arbitrary or predefined json objects and bytes,
11 | // and it applies to jsoniter.Marshal/Unmarshal as well.
12 | //
13 | // Besides, jsoniter.Iterator provides a different set of interfaces
14 | // iterating given bytes/string/reader
15 | // and yielding parsed elements one by one.
16 | // This set of interfaces reads input as required and gives
17 | // better performance.
18 | package jsoniter
19 |
--------------------------------------------------------------------------------
/extra/binary_as_string_codec_test.go:
--------------------------------------------------------------------------------
1 | package extra
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "github.com/stretchr/testify/require"
6 | "testing"
7 | )
8 |
9 | func init() {
10 | jsoniter.RegisterExtension(&BinaryAsStringExtension{})
11 | }
12 |
13 | func TestBinaryAsStringCodec(t *testing.T) {
14 | t.Run("safe set", func(t *testing.T) {
15 | should := require.New(t)
16 | output, err := jsoniter.Marshal([]byte("hello"))
17 | should.NoError(err)
18 | should.Equal(`"hello"`, string(output))
19 | var val []byte
20 | should.NoError(jsoniter.Unmarshal(output, &val))
21 | should.Equal(`hello`, string(val))
22 | })
23 | t.Run("non safe set", func(t *testing.T) {
24 | should := require.New(t)
25 | output, err := jsoniter.Marshal([]byte{1, 2, 3, 15})
26 | should.NoError(err)
27 | should.Equal(`"\\x01\\x02\\x03\\x0f"`, string(output))
28 | var val []byte
29 | should.NoError(jsoniter.Unmarshal(output, &val))
30 | should.Equal([]byte{1, 2, 3, 15}, val)
31 | })
32 | }
33 |
--------------------------------------------------------------------------------
/extra/time_as_int64_codec_test.go:
--------------------------------------------------------------------------------
1 | package extra
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "github.com/stretchr/testify/require"
6 | "testing"
7 | "time"
8 | )
9 |
10 | func Test_time_as_int64(t *testing.T) {
11 | should := require.New(t)
12 | RegisterTimeAsInt64Codec(time.Nanosecond)
13 | output, err := jsoniter.Marshal(time.Unix(1497952257, 1002))
14 | should.Nil(err)
15 | should.Equal("1497952257000001002", string(output))
16 | var val time.Time
17 | should.Nil(jsoniter.Unmarshal(output, &val))
18 | should.Equal(int64(1497952257000001002), val.UnixNano())
19 | }
20 |
21 | func Test_time_as_int64_keep_microsecond(t *testing.T) {
22 | t.Skip("conflict")
23 | should := require.New(t)
24 | RegisterTimeAsInt64Codec(time.Microsecond)
25 | output, err := jsoniter.Marshal(time.Unix(1, 1002))
26 | should.Nil(err)
27 | should.Equal("1000001", string(output))
28 | var val time.Time
29 | should.Nil(jsoniter.Unmarshal(output, &val))
30 | should.Equal(int64(1000001000), val.UnixNano())
31 | }
32 |
--------------------------------------------------------------------------------
/value_tests/iface_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import "io"
4 |
5 | func init() {
6 | var pCloser1 = func(str string) *io.Closer {
7 | closer := io.Closer(strCloser1(str))
8 | return &closer
9 | }
10 | var pCloser2 = func(str string) *io.Closer {
11 | strCloser := strCloser2(str)
12 | closer := io.Closer(&strCloser)
13 | return &closer
14 | }
15 | marshalCases = append(marshalCases,
16 | pCloser1("hello"),
17 | pCloser2("hello"),
18 | )
19 | unmarshalCases = append(unmarshalCases, unmarshalCase{
20 | ptr: (*[]io.Closer)(nil),
21 | input: "[null]",
22 | }, unmarshalCase{
23 | obj: func() interface{} {
24 | strCloser := strCloser2("")
25 | return &struct {
26 | Field io.Closer
27 | }{
28 | &strCloser,
29 | }
30 | },
31 | input: `{"Field": "hello"}`,
32 | })
33 | }
34 |
35 | type strCloser1 string
36 |
37 | func (closer strCloser1) Close() error {
38 | return nil
39 | }
40 |
41 | type strCloser2 string
42 |
43 | func (closer *strCloser2) Close() error {
44 | return nil
45 | }
46 |
--------------------------------------------------------------------------------
/type_tests/map_key_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "encoding"
5 | "strings"
6 | )
7 |
8 | func init() {
9 | testCases = append(testCases,
10 | (*map[stringKeyType]string)(nil),
11 | (*map[structKeyType]string)(nil),
12 | )
13 | }
14 |
15 | type stringKeyType string
16 |
17 | func (k stringKeyType) MarshalText() ([]byte, error) {
18 | return []byte("MANUAL__" + k), nil
19 | }
20 |
21 | func (k *stringKeyType) UnmarshalText(text []byte) error {
22 | *k = stringKeyType(strings.TrimPrefix(string(text), "MANUAL__"))
23 | return nil
24 | }
25 |
26 | var _ encoding.TextMarshaler = stringKeyType("")
27 | var _ encoding.TextUnmarshaler = new(stringKeyType)
28 |
29 | type structKeyType struct {
30 | X string
31 | }
32 |
33 | func (k structKeyType) MarshalText() ([]byte, error) {
34 | return []byte("MANUAL__" + k.X), nil
35 | }
36 |
37 | func (k *structKeyType) UnmarshalText(text []byte) error {
38 | k.X = strings.TrimPrefix(string(text), "MANUAL__")
39 | return nil
40 | }
41 |
42 | var _ encoding.TextMarshaler = structKeyType{}
43 | var _ encoding.TextUnmarshaler = &structKeyType{}
44 |
--------------------------------------------------------------------------------
/extra/time_as_int64_codec.go:
--------------------------------------------------------------------------------
1 | package extra
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "time"
6 | "unsafe"
7 | )
8 |
9 | // RegisterTimeAsInt64Codec encode/decode time since number of unit since epoch. the precision is the unit.
10 | func RegisterTimeAsInt64Codec(precision time.Duration) {
11 | jsoniter.RegisterTypeEncoder("time.Time", &timeAsInt64Codec{precision})
12 | jsoniter.RegisterTypeDecoder("time.Time", &timeAsInt64Codec{precision})
13 | }
14 |
15 | type timeAsInt64Codec struct {
16 | precision time.Duration
17 | }
18 |
19 | func (codec *timeAsInt64Codec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
20 | nanoseconds := iter.ReadInt64() * codec.precision.Nanoseconds()
21 | *((*time.Time)(ptr)) = time.Unix(0, nanoseconds)
22 | }
23 |
24 | func (codec *timeAsInt64Codec) IsEmpty(ptr unsafe.Pointer) bool {
25 | ts := *((*time.Time)(ptr))
26 | return ts.UnixNano() == 0
27 | }
28 | func (codec *timeAsInt64Codec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
29 | ts := *((*time.Time)(ptr))
30 | stream.WriteInt64(ts.UnixNano() / codec.precision.Nanoseconds())
31 | }
32 |
--------------------------------------------------------------------------------
/skip_tests/skip_test.go:
--------------------------------------------------------------------------------
1 | package skip_tests
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "github.com/json-iterator/go"
7 | "github.com/stretchr/testify/require"
8 | "io"
9 | "reflect"
10 | "testing"
11 | )
12 |
13 | type testCase struct {
14 | ptr interface{}
15 | inputs []string
16 | }
17 |
18 | var testCases []testCase
19 |
20 | func Test_skip(t *testing.T) {
21 | for _, testCase := range testCases {
22 | valType := reflect.TypeOf(testCase.ptr).Elem()
23 | for _, input := range testCase.inputs {
24 | t.Run(input, func(t *testing.T) {
25 | should := require.New(t)
26 | ptrVal := reflect.New(valType)
27 | stdErr := json.Unmarshal([]byte(input), ptrVal.Interface())
28 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, input)
29 | iter.Skip()
30 | iter.ReadNil() // trigger looking forward
31 | err := iter.Error
32 | if err == io.EOF {
33 | err = nil
34 | } else {
35 | err = errors.New("remaining bytes")
36 | }
37 | if stdErr == nil {
38 | should.Nil(err)
39 | } else {
40 | should.NotNil(err)
41 | }
42 | })
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/pool.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "io"
5 | )
6 |
7 | // IteratorPool a thread safe pool of iterators with same configuration
8 | type IteratorPool interface {
9 | BorrowIterator(data []byte) *Iterator
10 | ReturnIterator(iter *Iterator)
11 | }
12 |
13 | // StreamPool a thread safe pool of streams with same configuration
14 | type StreamPool interface {
15 | BorrowStream(writer io.Writer) *Stream
16 | ReturnStream(stream *Stream)
17 | }
18 |
19 | func (cfg *frozenConfig) BorrowStream(writer io.Writer) *Stream {
20 | stream := cfg.streamPool.Get().(*Stream)
21 | stream.Reset(writer)
22 | return stream
23 | }
24 |
25 | func (cfg *frozenConfig) ReturnStream(stream *Stream) {
26 | stream.out = nil
27 | stream.Error = nil
28 | stream.Attachment = nil
29 | cfg.streamPool.Put(stream)
30 | }
31 |
32 | func (cfg *frozenConfig) BorrowIterator(data []byte) *Iterator {
33 | iter := cfg.iteratorPool.Get().(*Iterator)
34 | iter.ResetBytes(data)
35 | return iter
36 | }
37 |
38 | func (cfg *frozenConfig) ReturnIterator(iter *Iterator) {
39 | iter.Error = nil
40 | iter.Attachment = nil
41 | cfg.iteratorPool.Put(iter)
42 | }
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 json-iterator
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/any_nil.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | type nilAny struct {
4 | baseAny
5 | }
6 |
7 | func (any *nilAny) LastError() error {
8 | return nil
9 | }
10 |
11 | func (any *nilAny) ValueType() ValueType {
12 | return NilValue
13 | }
14 |
15 | func (any *nilAny) MustBeValid() Any {
16 | return any
17 | }
18 |
19 | func (any *nilAny) ToBool() bool {
20 | return false
21 | }
22 |
23 | func (any *nilAny) ToInt() int {
24 | return 0
25 | }
26 |
27 | func (any *nilAny) ToInt32() int32 {
28 | return 0
29 | }
30 |
31 | func (any *nilAny) ToInt64() int64 {
32 | return 0
33 | }
34 |
35 | func (any *nilAny) ToUint() uint {
36 | return 0
37 | }
38 |
39 | func (any *nilAny) ToUint32() uint32 {
40 | return 0
41 | }
42 |
43 | func (any *nilAny) ToUint64() uint64 {
44 | return 0
45 | }
46 |
47 | func (any *nilAny) ToFloat32() float32 {
48 | return 0
49 | }
50 |
51 | func (any *nilAny) ToFloat64() float64 {
52 | return 0
53 | }
54 |
55 | func (any *nilAny) ToString() string {
56 | return ""
57 | }
58 |
59 | func (any *nilAny) WriteTo(stream *Stream) {
60 | stream.WriteNil()
61 | }
62 |
63 | func (any *nilAny) Parse() *Iterator {
64 | return nil
65 | }
66 |
67 | func (any *nilAny) GetInterface() interface{} {
68 | return nil
69 | }
70 |
--------------------------------------------------------------------------------
/api_tests/marshal_indent_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/json-iterator/go"
6 | "github.com/stretchr/testify/require"
7 | "testing"
8 | )
9 |
10 | func Test_marshal_indent(t *testing.T) {
11 | should := require.New(t)
12 | obj := struct {
13 | F1 int
14 | F2 []int
15 | }{1, []int{2, 3, 4}}
16 | output, err := json.MarshalIndent(obj, "", " ")
17 | should.Nil(err)
18 | should.Equal("{\n \"F1\": 1,\n \"F2\": [\n 2,\n 3,\n 4\n ]\n}", string(output))
19 | output, err = jsoniter.MarshalIndent(obj, "", " ")
20 | should.Nil(err)
21 | should.Equal("{\n \"F1\": 1,\n \"F2\": [\n 2,\n 3,\n 4\n ]\n}", string(output))
22 | }
23 |
24 | func Test_marshal_indent_map(t *testing.T) {
25 | should := require.New(t)
26 | obj := map[int]int{1: 2}
27 | output, err := json.MarshalIndent(obj, "", " ")
28 | should.Nil(err)
29 | should.Equal("{\n \"1\": 2\n}", string(output))
30 | output, err = jsoniter.MarshalIndent(obj, "", " ")
31 | should.Nil(err)
32 | should.Equal("{\n \"1\": 2\n}", string(output))
33 | output, err = jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent(obj, "", " ")
34 | should.Nil(err)
35 | should.Equal("{\n \"1\": 2\n}", string(output))
36 | }
37 |
--------------------------------------------------------------------------------
/api_tests/encoder_18_test.go:
--------------------------------------------------------------------------------
1 | //+build go1.8
2 |
3 | package test
4 |
5 | import (
6 | "bytes"
7 | "encoding/json"
8 | "testing"
9 | "unicode/utf8"
10 |
11 | "github.com/json-iterator/go"
12 | "github.com/stretchr/testify/require"
13 | )
14 |
15 | func Test_new_encoder(t *testing.T) {
16 | should := require.New(t)
17 | buf1 := &bytes.Buffer{}
18 | encoder1 := json.NewEncoder(buf1)
19 | encoder1.SetEscapeHTML(false)
20 | encoder1.Encode([]int{1})
21 | should.Equal("[1]\n", buf1.String())
22 | buf2 := &bytes.Buffer{}
23 | encoder2 := jsoniter.NewEncoder(buf2)
24 | encoder2.SetEscapeHTML(false)
25 | encoder2.Encode([]int{1})
26 | should.Equal("[1]\n", buf2.String())
27 | }
28 |
29 | func Test_string_encode_with_std_without_html_escape(t *testing.T) {
30 | api := jsoniter.Config{EscapeHTML: false}.Froze()
31 | should := require.New(t)
32 | for i := 0; i < utf8.RuneSelf; i++ {
33 | input := string([]byte{byte(i)})
34 | buf := &bytes.Buffer{}
35 | encoder := json.NewEncoder(buf)
36 | encoder.SetEscapeHTML(false)
37 | err := encoder.Encode(input)
38 | should.Nil(err)
39 | stdOutput := buf.String()
40 | stdOutput = stdOutput[:len(stdOutput)-1]
41 | jsoniterOutputBytes, err := api.Marshal(input)
42 | should.Nil(err)
43 | jsoniterOutput := string(jsoniterOutputBytes)
44 | should.Equal(stdOutput, jsoniterOutput)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/type_tests/marshaler_string_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "bytes"
5 | "encoding/base64"
6 | "encoding/json"
7 | "strings"
8 | )
9 |
10 | type StringMarshaler string
11 |
12 | func (m StringMarshaler) encode(str string) string {
13 | buf := bytes.Buffer{}
14 | b64 := base64.NewEncoder(base64.StdEncoding, &buf)
15 | if _, err := b64.Write([]byte(str)); err != nil {
16 | panic(err)
17 | }
18 | if err := b64.Close(); err != nil {
19 | panic(err)
20 | }
21 | return buf.String()
22 | }
23 |
24 | func (m StringMarshaler) decode(str string) string {
25 | if len(str) == 0 {
26 | return ""
27 | }
28 | b64 := base64.NewDecoder(base64.StdEncoding, strings.NewReader(str))
29 | bs := make([]byte, len(str))
30 | if n, err := b64.Read(bs); err != nil {
31 | panic(err)
32 | } else {
33 | bs = bs[:n]
34 | }
35 | return string(bs)
36 | }
37 |
38 | func (m StringMarshaler) MarshalJSON() ([]byte, error) {
39 | return []byte(`"MANUAL__` + m.encode(string(m)) + `"`), nil
40 | }
41 |
42 | func (m *StringMarshaler) UnmarshalJSON(text []byte) error {
43 | *m = StringMarshaler(m.decode(strings.TrimPrefix(strings.Trim(string(text), `"`), "MANUAL__")))
44 | return nil
45 | }
46 |
47 | var _ json.Marshaler = *new(StringMarshaler)
48 | var _ json.Unmarshaler = new(StringMarshaler)
49 |
50 | func init() {
51 | testCases = append(testCases, (*StringMarshaler)(nil))
52 | }
53 |
--------------------------------------------------------------------------------
/misc_tests/jsoniter_bool_test.go:
--------------------------------------------------------------------------------
1 | package misc_tests
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 |
7 | "github.com/json-iterator/go"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func Test_true(t *testing.T) {
12 | should := require.New(t)
13 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `true`)
14 | should.True(iter.ReadBool())
15 | iter = jsoniter.ParseString(jsoniter.ConfigDefault, `true`)
16 | should.Equal(true, iter.Read())
17 | }
18 |
19 | func Test_false(t *testing.T) {
20 | should := require.New(t)
21 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `false`)
22 | should.False(iter.ReadBool())
23 | }
24 |
25 | func Test_write_true_false(t *testing.T) {
26 | should := require.New(t)
27 | buf := &bytes.Buffer{}
28 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, buf, 4096)
29 | stream.WriteTrue()
30 | stream.WriteFalse()
31 | stream.WriteBool(false)
32 | stream.Flush()
33 | should.Nil(stream.Error)
34 | should.Equal("truefalsefalse", buf.String())
35 | }
36 |
37 | func Test_write_val_bool(t *testing.T) {
38 | should := require.New(t)
39 | buf := &bytes.Buffer{}
40 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, buf, 4096)
41 | stream.WriteVal(true)
42 | should.Equal(stream.Buffered(), 4)
43 | stream.Flush()
44 | should.Equal(stream.Buffered(), 0)
45 | should.Nil(stream.Error)
46 | should.Equal("true", buf.String())
47 | }
48 |
--------------------------------------------------------------------------------
/any_int64.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "strconv"
5 | )
6 |
7 | type int64Any struct {
8 | baseAny
9 | val int64
10 | }
11 |
12 | func (any *int64Any) LastError() error {
13 | return nil
14 | }
15 |
16 | func (any *int64Any) ValueType() ValueType {
17 | return NumberValue
18 | }
19 |
20 | func (any *int64Any) MustBeValid() Any {
21 | return any
22 | }
23 |
24 | func (any *int64Any) ToBool() bool {
25 | return any.val != 0
26 | }
27 |
28 | func (any *int64Any) ToInt() int {
29 | return int(any.val)
30 | }
31 |
32 | func (any *int64Any) ToInt32() int32 {
33 | return int32(any.val)
34 | }
35 |
36 | func (any *int64Any) ToInt64() int64 {
37 | return any.val
38 | }
39 |
40 | func (any *int64Any) ToUint() uint {
41 | return uint(any.val)
42 | }
43 |
44 | func (any *int64Any) ToUint32() uint32 {
45 | return uint32(any.val)
46 | }
47 |
48 | func (any *int64Any) ToUint64() uint64 {
49 | return uint64(any.val)
50 | }
51 |
52 | func (any *int64Any) ToFloat32() float32 {
53 | return float32(any.val)
54 | }
55 |
56 | func (any *int64Any) ToFloat64() float64 {
57 | return float64(any.val)
58 | }
59 |
60 | func (any *int64Any) ToString() string {
61 | return strconv.FormatInt(any.val, 10)
62 | }
63 |
64 | func (any *int64Any) WriteTo(stream *Stream) {
65 | stream.WriteInt64(any.val)
66 | }
67 |
68 | func (any *int64Any) Parse() *Iterator {
69 | return nil
70 | }
71 |
72 | func (any *int64Any) GetInterface() interface{} {
73 | return any.val
74 | }
75 |
--------------------------------------------------------------------------------
/any_int32.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "strconv"
5 | )
6 |
7 | type int32Any struct {
8 | baseAny
9 | val int32
10 | }
11 |
12 | func (any *int32Any) LastError() error {
13 | return nil
14 | }
15 |
16 | func (any *int32Any) ValueType() ValueType {
17 | return NumberValue
18 | }
19 |
20 | func (any *int32Any) MustBeValid() Any {
21 | return any
22 | }
23 |
24 | func (any *int32Any) ToBool() bool {
25 | return any.val != 0
26 | }
27 |
28 | func (any *int32Any) ToInt() int {
29 | return int(any.val)
30 | }
31 |
32 | func (any *int32Any) ToInt32() int32 {
33 | return any.val
34 | }
35 |
36 | func (any *int32Any) ToInt64() int64 {
37 | return int64(any.val)
38 | }
39 |
40 | func (any *int32Any) ToUint() uint {
41 | return uint(any.val)
42 | }
43 |
44 | func (any *int32Any) ToUint32() uint32 {
45 | return uint32(any.val)
46 | }
47 |
48 | func (any *int32Any) ToUint64() uint64 {
49 | return uint64(any.val)
50 | }
51 |
52 | func (any *int32Any) ToFloat32() float32 {
53 | return float32(any.val)
54 | }
55 |
56 | func (any *int32Any) ToFloat64() float64 {
57 | return float64(any.val)
58 | }
59 |
60 | func (any *int32Any) ToString() string {
61 | return strconv.FormatInt(int64(any.val), 10)
62 | }
63 |
64 | func (any *int32Any) WriteTo(stream *Stream) {
65 | stream.WriteInt32(any.val)
66 | }
67 |
68 | func (any *int32Any) Parse() *Iterator {
69 | return nil
70 | }
71 |
72 | func (any *int32Any) GetInterface() interface{} {
73 | return any.val
74 | }
75 |
--------------------------------------------------------------------------------
/any_uint64.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "strconv"
5 | )
6 |
7 | type uint64Any struct {
8 | baseAny
9 | val uint64
10 | }
11 |
12 | func (any *uint64Any) LastError() error {
13 | return nil
14 | }
15 |
16 | func (any *uint64Any) ValueType() ValueType {
17 | return NumberValue
18 | }
19 |
20 | func (any *uint64Any) MustBeValid() Any {
21 | return any
22 | }
23 |
24 | func (any *uint64Any) ToBool() bool {
25 | return any.val != 0
26 | }
27 |
28 | func (any *uint64Any) ToInt() int {
29 | return int(any.val)
30 | }
31 |
32 | func (any *uint64Any) ToInt32() int32 {
33 | return int32(any.val)
34 | }
35 |
36 | func (any *uint64Any) ToInt64() int64 {
37 | return int64(any.val)
38 | }
39 |
40 | func (any *uint64Any) ToUint() uint {
41 | return uint(any.val)
42 | }
43 |
44 | func (any *uint64Any) ToUint32() uint32 {
45 | return uint32(any.val)
46 | }
47 |
48 | func (any *uint64Any) ToUint64() uint64 {
49 | return any.val
50 | }
51 |
52 | func (any *uint64Any) ToFloat32() float32 {
53 | return float32(any.val)
54 | }
55 |
56 | func (any *uint64Any) ToFloat64() float64 {
57 | return float64(any.val)
58 | }
59 |
60 | func (any *uint64Any) ToString() string {
61 | return strconv.FormatUint(any.val, 10)
62 | }
63 |
64 | func (any *uint64Any) WriteTo(stream *Stream) {
65 | stream.WriteUint64(any.val)
66 | }
67 |
68 | func (any *uint64Any) Parse() *Iterator {
69 | return nil
70 | }
71 |
72 | func (any *uint64Any) GetInterface() interface{} {
73 | return any.val
74 | }
75 |
--------------------------------------------------------------------------------
/iter_array.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | // ReadArray read array element, tells if the array has more element to read.
4 | func (iter *Iterator) ReadArray() (ret bool) {
5 | c := iter.nextToken()
6 | switch c {
7 | case 'n':
8 | iter.skipThreeBytes('u', 'l', 'l')
9 | return false // null
10 | case '[':
11 | c = iter.nextToken()
12 | if c != ']' {
13 | iter.unreadByte()
14 | return true
15 | }
16 | return false
17 | case ']':
18 | return false
19 | case ',':
20 | return true
21 | default:
22 | iter.ReportError("ReadArray", "expect [ or , or ] or n, but found "+string([]byte{c}))
23 | return
24 | }
25 | }
26 |
27 | // ReadArrayCB read array with callback
28 | func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) {
29 | c := iter.nextToken()
30 | if c == '[' {
31 | c = iter.nextToken()
32 | if c != ']' {
33 | iter.unreadByte()
34 | if !callback(iter) {
35 | return false
36 | }
37 | c = iter.nextToken()
38 | for c == ',' {
39 | if !callback(iter) {
40 | return false
41 | }
42 | c = iter.nextToken()
43 | }
44 | if c != ']' {
45 | iter.ReportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c}))
46 | return false
47 | }
48 | return true
49 | }
50 | return true
51 | }
52 | if c == 'n' {
53 | iter.skipThreeBytes('u', 'l', 'l')
54 | return true // null
55 | }
56 | iter.ReportError("ReadArrayCB", "expect [ or n, but found "+string([]byte{c}))
57 | return false
58 | }
59 |
--------------------------------------------------------------------------------
/any_uint32.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "strconv"
5 | )
6 |
7 | type uint32Any struct {
8 | baseAny
9 | val uint32
10 | }
11 |
12 | func (any *uint32Any) LastError() error {
13 | return nil
14 | }
15 |
16 | func (any *uint32Any) ValueType() ValueType {
17 | return NumberValue
18 | }
19 |
20 | func (any *uint32Any) MustBeValid() Any {
21 | return any
22 | }
23 |
24 | func (any *uint32Any) ToBool() bool {
25 | return any.val != 0
26 | }
27 |
28 | func (any *uint32Any) ToInt() int {
29 | return int(any.val)
30 | }
31 |
32 | func (any *uint32Any) ToInt32() int32 {
33 | return int32(any.val)
34 | }
35 |
36 | func (any *uint32Any) ToInt64() int64 {
37 | return int64(any.val)
38 | }
39 |
40 | func (any *uint32Any) ToUint() uint {
41 | return uint(any.val)
42 | }
43 |
44 | func (any *uint32Any) ToUint32() uint32 {
45 | return any.val
46 | }
47 |
48 | func (any *uint32Any) ToUint64() uint64 {
49 | return uint64(any.val)
50 | }
51 |
52 | func (any *uint32Any) ToFloat32() float32 {
53 | return float32(any.val)
54 | }
55 |
56 | func (any *uint32Any) ToFloat64() float64 {
57 | return float64(any.val)
58 | }
59 |
60 | func (any *uint32Any) ToString() string {
61 | return strconv.FormatInt(int64(any.val), 10)
62 | }
63 |
64 | func (any *uint32Any) WriteTo(stream *Stream) {
65 | stream.WriteUint32(any.val)
66 | }
67 |
68 | func (any *uint32Any) Parse() *Iterator {
69 | return nil
70 | }
71 |
72 | func (any *uint32Any) GetInterface() interface{} {
73 | return any.val
74 | }
75 |
--------------------------------------------------------------------------------
/type_tests/array_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | func init() {
4 | testCases = append(testCases,
5 | (*[4]bool)(nil),
6 | (*[4]byte)(nil),
7 | (*[4]float64)(nil),
8 | (*[4]int32)(nil),
9 | (*[4]map[int32]string)(nil),
10 | (*[4]map[string]string)(nil),
11 | (*[4]*bool)(nil),
12 | (*[4]*float64)(nil),
13 | (*[4]*int32)(nil),
14 | (*[4]*map[int32]string)(nil),
15 | (*[4]*map[string]string)(nil),
16 | (*[4]*[4]bool)(nil),
17 | (*[4]*[4]byte)(nil),
18 | (*[4]*[4]float64)(nil),
19 | (*[4]*[4]int32)(nil),
20 | (*[4]*[4]*string)(nil),
21 | (*[4]*[4]string)(nil),
22 | (*[4]*[4]uint8)(nil),
23 | (*[4]*string)(nil),
24 | (*[4]*struct {
25 | String string
26 | Int int32
27 | Float float64
28 | Struct struct {
29 | X string
30 | }
31 | Slice [4]string
32 | Map map[string]string
33 | })(nil),
34 | (*[4]*uint8)(nil),
35 | (*[4][4]bool)(nil),
36 | (*[4][4]byte)(nil),
37 | (*[4][4]float64)(nil),
38 | (*[4][4]int32)(nil),
39 | (*[4][4]*string)(nil),
40 | (*[4][4]string)(nil),
41 | (*[4][4]uint8)(nil),
42 | (*[4]string)(nil),
43 | (*[4]struct{})(nil),
44 | (*[4]structEmpty)(nil),
45 | (*[4]struct {
46 | F *string
47 | })(nil),
48 | (*[4]struct {
49 | String string
50 | Int int32
51 | Float float64
52 | Struct struct {
53 | X string
54 | }
55 | Slice [4]string
56 | Map map[string]string
57 | })(nil),
58 | (*[4]uint8)(nil),
59 | )
60 | }
61 |
62 | type structEmpty struct{}
63 | type arrayAlis [4]stringAlias
64 |
--------------------------------------------------------------------------------
/type_tests/text_marshaler_string_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "bytes"
5 | "encoding"
6 | "encoding/base64"
7 | "strings"
8 | )
9 |
10 | func init() {
11 | testCases = append(testCases,
12 | (*StringTextMarshaler)(nil),
13 | )
14 | }
15 |
16 | // StringTextMarshaler TEST ONLY
17 | type StringTextMarshaler string
18 |
19 | func (m StringTextMarshaler) encode(str string) string {
20 | buf := bytes.Buffer{}
21 | b64 := base64.NewEncoder(base64.StdEncoding, &buf)
22 | if _, err := b64.Write([]byte(str)); err != nil {
23 | panic(err)
24 | }
25 | if err := b64.Close(); err != nil {
26 | panic(err)
27 | }
28 | return buf.String()
29 | }
30 |
31 | func (m StringTextMarshaler) decode(str string) string {
32 | if len(str) == 0 {
33 | return ""
34 | }
35 | b64 := base64.NewDecoder(base64.StdEncoding, strings.NewReader(str))
36 | bs := make([]byte, len(str))
37 | if n, err := b64.Read(bs); err != nil {
38 | panic(err)
39 | } else {
40 | bs = bs[:n]
41 | }
42 | return string(bs)
43 | }
44 |
45 | // MarshalText TEST ONLY
46 | func (m StringTextMarshaler) MarshalText() ([]byte, error) {
47 | return []byte(`MANUAL__` + m.encode(string(m))), nil
48 | }
49 |
50 | // UnmarshalText TEST ONLY
51 | func (m *StringTextMarshaler) UnmarshalText(text []byte) error {
52 | *m = StringTextMarshaler(m.decode(strings.TrimPrefix(string(text), "MANUAL__")))
53 | return nil
54 | }
55 |
56 | var _ encoding.TextMarshaler = *new(StringTextMarshaler)
57 | var _ encoding.TextUnmarshaler = new(StringTextMarshaler)
58 |
--------------------------------------------------------------------------------
/extra/naming_strategy_test.go:
--------------------------------------------------------------------------------
1 | package extra
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "github.com/stretchr/testify/require"
6 | "testing"
7 | )
8 |
9 | func Test_lower_case_with_underscores(t *testing.T) {
10 | should := require.New(t)
11 | should.Equal("hello_world", LowerCaseWithUnderscores("helloWorld"))
12 | should.Equal("hello_world", LowerCaseWithUnderscores("HelloWorld"))
13 | SetNamingStrategy(LowerCaseWithUnderscores)
14 | output, err := jsoniter.Marshal(struct {
15 | UserName string
16 | FirstLanguage string
17 | }{
18 | UserName: "taowen",
19 | FirstLanguage: "Chinese",
20 | })
21 | should.Nil(err)
22 | should.Equal(`{"user_name":"taowen","first_language":"Chinese"}`, string(output))
23 | }
24 |
25 | func Test_set_naming_strategy_with_overrides(t *testing.T) {
26 | should := require.New(t)
27 | SetNamingStrategy(LowerCaseWithUnderscores)
28 | output, err := jsoniter.Marshal(struct {
29 | UserName string `json:"UserName"`
30 | FirstLanguage string
31 | }{
32 | UserName: "taowen",
33 | FirstLanguage: "Chinese",
34 | })
35 | should.Nil(err)
36 | should.Equal(`{"UserName":"taowen","first_language":"Chinese"}`, string(output))
37 | }
38 |
39 | func Test_set_naming_strategy_with_omitempty(t *testing.T) {
40 | should := require.New(t)
41 | SetNamingStrategy(LowerCaseWithUnderscores)
42 | output, err := jsoniter.Marshal(struct {
43 | UserName string
44 | FirstLanguage string `json:",omitempty"`
45 | }{
46 | UserName: "taowen",
47 | })
48 | should.Nil(err)
49 | should.Equal(`{"user_name":"taowen"}`, string(output))
50 | }
51 |
--------------------------------------------------------------------------------
/any_float.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "strconv"
5 | )
6 |
7 | type floatAny struct {
8 | baseAny
9 | val float64
10 | }
11 |
12 | func (any *floatAny) Parse() *Iterator {
13 | return nil
14 | }
15 |
16 | func (any *floatAny) ValueType() ValueType {
17 | return NumberValue
18 | }
19 |
20 | func (any *floatAny) MustBeValid() Any {
21 | return any
22 | }
23 |
24 | func (any *floatAny) LastError() error {
25 | return nil
26 | }
27 |
28 | func (any *floatAny) ToBool() bool {
29 | return any.ToFloat64() != 0
30 | }
31 |
32 | func (any *floatAny) ToInt() int {
33 | return int(any.val)
34 | }
35 |
36 | func (any *floatAny) ToInt32() int32 {
37 | return int32(any.val)
38 | }
39 |
40 | func (any *floatAny) ToInt64() int64 {
41 | return int64(any.val)
42 | }
43 |
44 | func (any *floatAny) ToUint() uint {
45 | if any.val > 0 {
46 | return uint(any.val)
47 | }
48 | return 0
49 | }
50 |
51 | func (any *floatAny) ToUint32() uint32 {
52 | if any.val > 0 {
53 | return uint32(any.val)
54 | }
55 | return 0
56 | }
57 |
58 | func (any *floatAny) ToUint64() uint64 {
59 | if any.val > 0 {
60 | return uint64(any.val)
61 | }
62 | return 0
63 | }
64 |
65 | func (any *floatAny) ToFloat32() float32 {
66 | return float32(any.val)
67 | }
68 |
69 | func (any *floatAny) ToFloat64() float64 {
70 | return any.val
71 | }
72 |
73 | func (any *floatAny) ToString() string {
74 | return strconv.FormatFloat(any.val, 'E', -1, 64)
75 | }
76 |
77 | func (any *floatAny) WriteTo(stream *Stream) {
78 | stream.WriteFloat64(any.val)
79 | }
80 |
81 | func (any *floatAny) GetInterface() interface{} {
82 | return any.val
83 | }
84 |
--------------------------------------------------------------------------------
/extra/privat_fields.go:
--------------------------------------------------------------------------------
1 | package extra
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "strings"
6 | "unicode"
7 | )
8 |
9 | // SupportPrivateFields include private fields when encoding/decoding
10 | func SupportPrivateFields() {
11 | jsoniter.RegisterExtension(&privateFieldsExtension{})
12 | }
13 |
14 | type privateFieldsExtension struct {
15 | jsoniter.DummyExtension
16 | }
17 |
18 | func (extension *privateFieldsExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
19 | for _, binding := range structDescriptor.Fields {
20 | isPrivate := unicode.IsLower(rune(binding.Field.Name()[0]))
21 | if isPrivate {
22 | tag, hastag := binding.Field.Tag().Lookup("json")
23 | if !hastag {
24 | binding.FromNames = []string{binding.Field.Name()}
25 | binding.ToNames = []string{binding.Field.Name()}
26 | continue
27 | }
28 | tagParts := strings.Split(tag, ",")
29 | names := calcFieldNames(binding.Field.Name(), tagParts[0], tag)
30 | binding.FromNames = names
31 | binding.ToNames = names
32 | }
33 | }
34 | }
35 |
36 | func calcFieldNames(originalFieldName string, tagProvidedFieldName string, wholeTag string) []string {
37 | // ignore?
38 | if wholeTag == "-" {
39 | return []string{}
40 | }
41 | // rename?
42 | var fieldNames []string
43 | if tagProvidedFieldName == "" {
44 | fieldNames = []string{originalFieldName}
45 | } else {
46 | fieldNames = []string{tagProvidedFieldName}
47 | }
48 | // private?
49 | isNotExported := unicode.IsLower(rune(originalFieldName[0]))
50 | if isNotExported {
51 | fieldNames = []string{}
52 | }
53 | return fieldNames
54 | }
55 |
--------------------------------------------------------------------------------
/type_tests/map_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | func init() {
4 | testCases = append(testCases,
5 | (*map[int8]string)(nil),
6 | (*map[int16]string)(nil),
7 | (*map[int32]string)(nil),
8 | (*map[int64]string)(nil),
9 | (*map[string][4]string)(nil),
10 | (*map[string]bool)(nil),
11 | (*map[string]byte)(nil),
12 | (*map[string]float64)(nil),
13 | (*map[string]int32)(nil),
14 | (*map[string]map[string]string)(nil),
15 | (*map[string]*[4]string)(nil),
16 | (*map[string]*bool)(nil),
17 | (*map[string]*float64)(nil),
18 | (*map[string]*int32)(nil),
19 | (*map[string]*map[string]string)(nil),
20 | (*map[string]*[]string)(nil),
21 | (*map[string]*string)(nil),
22 | (*map[string]*structVarious)(nil),
23 | (*map[string]*uint8)(nil),
24 | (*map[string][]string)(nil),
25 | (*map[string]string)(nil),
26 | (*map[string]stringAlias)(nil),
27 | (*map[string]struct{})(nil),
28 | (*map[string]structEmpty)(nil),
29 | (*map[string]struct {
30 | F *string
31 | })(nil),
32 | (*map[string]struct {
33 | String string
34 | Int int32
35 | Float float64
36 | Struct struct {
37 | X string
38 | }
39 | Slice []string
40 | Map map[string]string
41 | })(nil),
42 | (*map[string]uint8)(nil),
43 | (*map[stringAlias]string)(nil),
44 | (*map[stringAlias]stringAlias)(nil),
45 | (*map[uint8]string)(nil),
46 | (*map[uint16]string)(nil),
47 | (*map[uint32]string)(nil),
48 | )
49 | }
50 |
51 | type structVarious struct {
52 | String string
53 | Int int32
54 | Float float64
55 | Struct struct {
56 | X string
57 | }
58 | Slice []string
59 | Map map[string]string
60 | }
61 |
--------------------------------------------------------------------------------
/extra/naming_strategy.go:
--------------------------------------------------------------------------------
1 | package extra
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "strings"
6 | "unicode"
7 | )
8 |
9 | // SetNamingStrategy rename struct fields uniformly
10 | func SetNamingStrategy(translate func(string) string) {
11 | jsoniter.RegisterExtension(&namingStrategyExtension{jsoniter.DummyExtension{}, translate})
12 | }
13 |
14 | type namingStrategyExtension struct {
15 | jsoniter.DummyExtension
16 | translate func(string) string
17 | }
18 |
19 | func (extension *namingStrategyExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
20 | for _, binding := range structDescriptor.Fields {
21 | tag, hastag := binding.Field.Tag().Lookup("json")
22 | if hastag {
23 | tagParts := strings.Split(tag, ",")
24 | if tagParts[0] == "-" {
25 | continue // hidden field
26 | }
27 | if tagParts[0] != "" {
28 | continue // field explicitly named
29 | }
30 | }
31 | binding.ToNames = []string{extension.translate(binding.Field.Name())}
32 | binding.FromNames = []string{extension.translate(binding.Field.Name())}
33 | }
34 | }
35 |
36 | // LowerCaseWithUnderscores one strategy to SetNamingStrategy for. It will change HelloWorld to hello_world.
37 | func LowerCaseWithUnderscores(name string) string {
38 | newName := []rune{}
39 | for i, c := range name {
40 | if i == 0 {
41 | newName = append(newName, unicode.ToLower(c))
42 | } else {
43 | if unicode.IsUpper(c) {
44 | newName = append(newName, '_')
45 | newName = append(newName, unicode.ToLower(c))
46 | } else {
47 | newName = append(newName, c)
48 | }
49 | }
50 | }
51 | return string(newName)
52 | }
53 |
--------------------------------------------------------------------------------
/any_tests/jsoniter_any_bool_test.go:
--------------------------------------------------------------------------------
1 | package any_tests
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/json-iterator/go"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | var boolConvertMap = map[string]bool{
12 | "null": false,
13 | "true": true,
14 | "false": false,
15 |
16 | `"true"`: true,
17 | `"false"`: true,
18 |
19 | "123": true,
20 | `"123"`: true,
21 | "0": false,
22 | `"0"`: false,
23 | "-1": true,
24 | `"-1"`: true,
25 |
26 | "1.1": true,
27 | "0.0": false,
28 | "-1.1": true,
29 | `""`: false,
30 | "[1,2]": true,
31 | "[]": false,
32 | "{}": true,
33 | `{"abc":1}`: true,
34 | }
35 |
36 | func Test_read_bool_as_any(t *testing.T) {
37 | should := require.New(t)
38 |
39 | var any jsoniter.Any
40 | for k, v := range boolConvertMap {
41 | any = jsoniter.Get([]byte(k))
42 | if v {
43 | should.True(any.ToBool(), fmt.Sprintf("origin val is %v", k))
44 | } else {
45 | should.False(any.ToBool(), fmt.Sprintf("origin val is %v", k))
46 | }
47 | }
48 |
49 | }
50 |
51 | func Test_write_bool_to_stream(t *testing.T) {
52 | should := require.New(t)
53 | any := jsoniter.Get([]byte("true"))
54 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, nil, 32)
55 | any.WriteTo(stream)
56 | should.Equal("true", string(stream.Buffer()))
57 | should.Equal(any.ValueType(), jsoniter.BoolValue)
58 |
59 | any = jsoniter.Get([]byte("false"))
60 | stream = jsoniter.NewStream(jsoniter.ConfigDefault, nil, 32)
61 | any.WriteTo(stream)
62 | should.Equal("false", string(stream.Buffer()))
63 |
64 | should.Equal(any.ValueType(), jsoniter.BoolValue)
65 | }
66 |
--------------------------------------------------------------------------------
/type_tests/marshaler_struct_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "bytes"
5 | "encoding/base64"
6 | "encoding/json"
7 | "strings"
8 | )
9 |
10 | type structMarshaler struct {
11 | X string
12 | }
13 |
14 | func (m structMarshaler) encode(str string) string {
15 | buf := bytes.Buffer{}
16 | b64 := base64.NewEncoder(base64.StdEncoding, &buf)
17 | if _, err := b64.Write([]byte(str)); err != nil {
18 | panic(err)
19 | }
20 | if err := b64.Close(); err != nil {
21 | panic(err)
22 | }
23 | return buf.String()
24 | }
25 |
26 | func (m structMarshaler) decode(str string) string {
27 | if len(str) == 0 {
28 | return ""
29 | }
30 | b64 := base64.NewDecoder(base64.StdEncoding, strings.NewReader(str))
31 | bs := make([]byte, len(str))
32 | if n, err := b64.Read(bs); err != nil {
33 | panic(err)
34 | } else {
35 | bs = bs[:n]
36 | }
37 | return string(bs)
38 | }
39 |
40 | func (m structMarshaler) MarshalJSON() ([]byte, error) {
41 | return []byte(`"MANUAL__` + m.encode(m.X) + `"`), nil
42 | }
43 |
44 | func (m *structMarshaler) UnmarshalJSON(text []byte) error {
45 | m.X = m.decode(strings.TrimPrefix(strings.Trim(string(text), `"`), "MANUAL__"))
46 | return nil
47 | }
48 |
49 | var _ json.Marshaler = structMarshaler{}
50 | var _ json.Unmarshaler = &structMarshaler{}
51 |
52 | type structMarshalerAlias structMarshaler
53 |
54 | func init() {
55 | testCases = append(testCases,
56 | (*structMarshaler)(nil),
57 | (*structMarshalerAlias)(nil),
58 | (*struct {
59 | S string
60 | M structMarshaler
61 | I int8
62 | })(nil),
63 | (*struct {
64 | S string
65 | M structMarshalerAlias
66 | I int8
67 | })(nil),
68 | )
69 | }
70 |
--------------------------------------------------------------------------------
/type_tests/text_marshaler_struct_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "bytes"
5 | "encoding"
6 | "encoding/base64"
7 | "strings"
8 | )
9 |
10 | func init() {
11 | testCases = append(testCases,
12 | (*structTextMarshaler)(nil),
13 | (*structTextMarshalerAlias)(nil),
14 | (*struct {
15 | S string
16 | M structTextMarshaler
17 | I int8
18 | })(nil),
19 | (*struct {
20 | S string
21 | M structTextMarshalerAlias
22 | I int8
23 | })(nil),
24 | )
25 | }
26 |
27 | type structTextMarshaler struct {
28 | X string
29 | }
30 |
31 | func (m structTextMarshaler) encode(str string) string {
32 | buf := bytes.Buffer{}
33 | b64 := base64.NewEncoder(base64.StdEncoding, &buf)
34 | if _, err := b64.Write([]byte(str)); err != nil {
35 | panic(err)
36 | }
37 | if err := b64.Close(); err != nil {
38 | panic(err)
39 | }
40 | return buf.String()
41 | }
42 |
43 | func (m structTextMarshaler) decode(str string) string {
44 | if len(str) == 0 {
45 | return ""
46 | }
47 | b64 := base64.NewDecoder(base64.StdEncoding, strings.NewReader(str))
48 | bs := make([]byte, len(str))
49 | if n, err := b64.Read(bs); err != nil {
50 | panic(err)
51 | } else {
52 | bs = bs[:n]
53 | }
54 | return string(bs)
55 | }
56 |
57 | func (m structTextMarshaler) MarshalText() ([]byte, error) {
58 | return []byte(`MANUAL__` + m.encode(m.X)), nil
59 | }
60 |
61 | func (m *structTextMarshaler) UnmarshalText(text []byte) error {
62 | m.X = m.decode(strings.TrimPrefix(string(text), "MANUAL__"))
63 | return nil
64 | }
65 |
66 | var _ encoding.TextMarshaler = structTextMarshaler{}
67 | var _ encoding.TextUnmarshaler = &structTextMarshaler{}
68 |
69 | type structTextMarshalerAlias structTextMarshaler
70 |
--------------------------------------------------------------------------------
/any_invalid.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import "fmt"
4 |
5 | type invalidAny struct {
6 | baseAny
7 | err error
8 | }
9 |
10 | func newInvalidAny(path []interface{}) *invalidAny {
11 | return &invalidAny{baseAny{}, fmt.Errorf("%v not found", path)}
12 | }
13 |
14 | func (any *invalidAny) LastError() error {
15 | return any.err
16 | }
17 |
18 | func (any *invalidAny) ValueType() ValueType {
19 | return InvalidValue
20 | }
21 |
22 | func (any *invalidAny) MustBeValid() Any {
23 | panic(any.err)
24 | }
25 |
26 | func (any *invalidAny) ToBool() bool {
27 | return false
28 | }
29 |
30 | func (any *invalidAny) ToInt() int {
31 | return 0
32 | }
33 |
34 | func (any *invalidAny) ToInt32() int32 {
35 | return 0
36 | }
37 |
38 | func (any *invalidAny) ToInt64() int64 {
39 | return 0
40 | }
41 |
42 | func (any *invalidAny) ToUint() uint {
43 | return 0
44 | }
45 |
46 | func (any *invalidAny) ToUint32() uint32 {
47 | return 0
48 | }
49 |
50 | func (any *invalidAny) ToUint64() uint64 {
51 | return 0
52 | }
53 |
54 | func (any *invalidAny) ToFloat32() float32 {
55 | return 0
56 | }
57 |
58 | func (any *invalidAny) ToFloat64() float64 {
59 | return 0
60 | }
61 |
62 | func (any *invalidAny) ToString() string {
63 | return ""
64 | }
65 |
66 | func (any *invalidAny) WriteTo(stream *Stream) {
67 | }
68 |
69 | func (any *invalidAny) Get(path ...interface{}) Any {
70 | if any.err == nil {
71 | return &invalidAny{baseAny{}, fmt.Errorf("get %v from invalid", path)}
72 | }
73 | return &invalidAny{baseAny{}, fmt.Errorf("%v, get %v from invalid", any.err, path)}
74 | }
75 |
76 | func (any *invalidAny) Parse() *Iterator {
77 | return nil
78 | }
79 |
80 | func (any *invalidAny) GetInterface() interface{} {
81 | return nil
82 | }
83 |
--------------------------------------------------------------------------------
/reflect_dynamic.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "github.com/modern-go/reflect2"
5 | "reflect"
6 | "unsafe"
7 | )
8 |
9 | type dynamicEncoder struct {
10 | valType reflect2.Type
11 | }
12 |
13 | func (encoder *dynamicEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
14 | obj := encoder.valType.UnsafeIndirect(ptr)
15 | stream.WriteVal(obj)
16 | }
17 |
18 | func (encoder *dynamicEncoder) IsEmpty(ptr unsafe.Pointer) bool {
19 | return encoder.valType.UnsafeIndirect(ptr) == nil
20 | }
21 |
22 | type efaceDecoder struct {
23 | }
24 |
25 | func (decoder *efaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
26 | pObj := (*interface{})(ptr)
27 | obj := *pObj
28 | if obj == nil {
29 | *pObj = iter.Read()
30 | return
31 | }
32 | typ := reflect2.TypeOf(obj)
33 | if typ.Kind() != reflect.Ptr {
34 | *pObj = iter.Read()
35 | return
36 | }
37 | ptrType := typ.(*reflect2.UnsafePtrType)
38 | ptrElemType := ptrType.Elem()
39 | if iter.WhatIsNext() == NilValue {
40 | if ptrElemType.Kind() != reflect.Ptr {
41 | iter.skipFourBytes('n', 'u', 'l', 'l')
42 | *pObj = nil
43 | return
44 | }
45 | }
46 | if reflect2.IsNil(obj) {
47 | obj := ptrElemType.New()
48 | iter.ReadVal(obj)
49 | *pObj = obj
50 | return
51 | }
52 | iter.ReadVal(obj)
53 | }
54 |
55 | type ifaceDecoder struct {
56 | valType *reflect2.UnsafeIFaceType
57 | }
58 |
59 | func (decoder *ifaceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
60 | if iter.ReadNil() {
61 | decoder.valType.UnsafeSet(ptr, decoder.valType.UnsafeNew())
62 | return
63 | }
64 | obj := decoder.valType.UnsafeIndirect(ptr)
65 | if reflect2.IsNil(obj) {
66 | iter.ReportError("decode non empty interface", "can not unmarshal into nil")
67 | return
68 | }
69 | iter.ReadVal(obj)
70 | }
71 |
--------------------------------------------------------------------------------
/type_tests/builtin_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | func init() {
4 | testCases = append(testCases,
5 | (*bool)(nil),
6 | (*boolAlias)(nil),
7 | (*byte)(nil),
8 | (*byteAlias)(nil),
9 | (*float32)(nil),
10 | (*float32Alias)(nil),
11 | (*float64)(nil),
12 | (*float64Alias)(nil),
13 | (*int8)(nil),
14 | (*int8Alias)(nil),
15 | (*int16)(nil),
16 | (*int16Alias)(nil),
17 | (*int32)(nil),
18 | (*int32Alias)(nil),
19 | (*int64)(nil),
20 | (*int64Alias)(nil),
21 | (*string)(nil),
22 | (*stringAlias)(nil),
23 | (*uint8)(nil),
24 | (*uint8Alias)(nil),
25 | (*uint16)(nil),
26 | (*uint16Alias)(nil),
27 | (*uint32)(nil),
28 | (*uint32Alias)(nil),
29 | (*uintptr)(nil),
30 | (*uintptrAlias)(nil),
31 | (*struct {
32 | A int8Alias `json:"a"`
33 | B int16Alias `json:"stream"`
34 | C int32Alias `json:"c"`
35 | D int64Alias `json:"d"`
36 | E uintAlias `json:"e"`
37 | F uint16Alias `json:"f"`
38 | G uint32Alias `json:"g"`
39 | H uint64Alias `json:"h"`
40 | I float32Alias `json:"i"`
41 | J float64Alias `json:"j"`
42 | K stringAlias `json:"k"`
43 | L intAlias `json:"l"`
44 | M uintAlias `json:"m"`
45 | N boolAlias `json:"n"`
46 | O uintptrAlias `json:"o"`
47 | })(nil),
48 | )
49 | }
50 |
51 | type boolAlias bool
52 | type byteAlias byte
53 | type float32Alias float32
54 | type float64Alias float64
55 | type ptrFloat64Alias *float64
56 | type int8Alias int8
57 | type int16Alias int16
58 | type int32Alias int32
59 | type ptrInt32Alias *int32
60 | type int64Alias int64
61 | type stringAlias string
62 | type ptrStringAlias *string
63 | type uint8Alias uint8
64 | type uint16Alias uint16
65 | type uint32Alias uint32
66 | type uintptrAlias uintptr
67 | type uintAlias uint
68 | type uint64Alias uint64
69 | type intAlias int
70 |
--------------------------------------------------------------------------------
/value_tests/marshaler_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "encoding"
5 | "encoding/json"
6 | )
7 |
8 | func init() {
9 | jm := json.Marshaler(jmOfStruct{})
10 | tm1 := encoding.TextMarshaler(tmOfStruct{})
11 | tm2 := encoding.TextMarshaler(&tmOfStructInt{})
12 | marshalCases = append(marshalCases,
13 | jmOfStruct{},
14 | &jm,
15 | tmOfStruct{},
16 | &tm1,
17 | tmOfStructInt{},
18 | &tm2,
19 | map[tmOfStruct]int{
20 | {}: 100,
21 | },
22 | map[*tmOfStruct]int{
23 | {}: 100,
24 | },
25 | map[encoding.TextMarshaler]int{
26 | tm1: 100,
27 | },
28 | )
29 | unmarshalCases = append(unmarshalCases, unmarshalCase{
30 | ptr: (*tmOfMap)(nil),
31 | input: `"{1:2}"`,
32 | }, unmarshalCase{
33 | ptr: (*tmOfMapPtr)(nil),
34 | input: `"{1:2}"`,
35 | })
36 | }
37 |
38 | type jmOfStruct struct {
39 | F2 chan []byte
40 | }
41 |
42 | func (q jmOfStruct) MarshalJSON() ([]byte, error) {
43 | return []byte(`""`), nil
44 | }
45 |
46 | func (q *jmOfStruct) UnmarshalJSON(value []byte) error {
47 | return nil
48 | }
49 |
50 | type tmOfStruct struct {
51 | F2 chan []byte
52 | }
53 |
54 | func (q tmOfStruct) MarshalText() ([]byte, error) {
55 | return []byte(`""`), nil
56 | }
57 |
58 | func (q *tmOfStruct) UnmarshalText(value []byte) error {
59 | return nil
60 | }
61 |
62 | type tmOfStructInt struct {
63 | Field2 int
64 | }
65 |
66 | func (q *tmOfStructInt) MarshalText() ([]byte, error) {
67 | return []byte(`"abc"`), nil
68 | }
69 |
70 | func (q *tmOfStructInt) UnmarshalText(value []byte) error {
71 | return nil
72 | }
73 |
74 | type tmOfMap map[int]int
75 |
76 | func (q tmOfMap) UnmarshalText(value []byte) error {
77 | return nil
78 | }
79 |
80 | type tmOfMapPtr map[int]int
81 |
82 | func (q *tmOfMapPtr) UnmarshalText(value []byte) error {
83 | return nil
84 | }
85 |
--------------------------------------------------------------------------------
/value_tests/eface_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | func init() {
4 | var pEFace = func(val interface{}) *interface{} {
5 | return &val
6 | }
7 | var pInt = func(val int) *int {
8 | return &val
9 | }
10 | unmarshalCases = append(unmarshalCases, unmarshalCase{
11 | ptr: (**interface{})(nil),
12 | input: `"hello"`,
13 | }, unmarshalCase{
14 | ptr: (**interface{})(nil),
15 | input: `1e1`,
16 | }, unmarshalCase{
17 | ptr: (**interface{})(nil),
18 | input: `1.0e1`,
19 | }, unmarshalCase{
20 | ptr: (*[]interface{})(nil),
21 | input: `[1.0e1]`,
22 | }, unmarshalCase{
23 | ptr: (*struct {
24 | Field interface{}
25 | })(nil),
26 | input: `{"field":"hello"}`,
27 | }, unmarshalCase{
28 | obj: func() interface{} {
29 | type TestData struct {
30 | Name string `json:"name"`
31 | }
32 | o := &TestData{}
33 | return &o
34 | },
35 | input: `{"name":"value"}`,
36 | }, unmarshalCase{
37 | obj: func() interface{} {
38 | b := true
39 | return &struct {
40 | Field interface{} `json:"field"`
41 | }{&b}
42 | },
43 | input: `{"field": null}`,
44 | }, unmarshalCase{
45 | obj: func() interface{} {
46 | var pb *bool
47 | return &struct {
48 | Field interface{} `json:"field"`
49 | }{&pb}
50 | },
51 | input: `{"field": null}`,
52 | }, unmarshalCase{
53 | obj: func() interface{} {
54 | b := true
55 | pb := &b
56 | return &struct {
57 | Field interface{} `json:"field"`
58 | }{&pb}
59 | },
60 | input: `{"field": null}`,
61 | })
62 | marshalCases = append(marshalCases,
63 | pEFace("hello"),
64 | struct {
65 | Field interface{}
66 | }{"hello"},
67 | struct {
68 | Field interface{}
69 | }{struct {
70 | field chan int
71 | }{}},
72 | struct {
73 | Field interface{}
74 | }{struct {
75 | Field *int
76 | }{pInt(100)}},
77 | )
78 | }
79 |
--------------------------------------------------------------------------------
/reflect_json_raw_message.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/modern-go/reflect2"
6 | "unsafe"
7 | )
8 |
9 | var jsonRawMessageType = reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()
10 | var jsoniterRawMessageType = reflect2.TypeOfPtr((*RawMessage)(nil)).Elem()
11 |
12 | func createEncoderOfJsonRawMessage(ctx *ctx, typ reflect2.Type) ValEncoder {
13 | if typ == jsonRawMessageType {
14 | return &jsonRawMessageCodec{}
15 | }
16 | if typ == jsoniterRawMessageType {
17 | return &jsoniterRawMessageCodec{}
18 | }
19 | return nil
20 | }
21 |
22 | func createDecoderOfJsonRawMessage(ctx *ctx, typ reflect2.Type) ValDecoder {
23 | if typ == jsonRawMessageType {
24 | return &jsonRawMessageCodec{}
25 | }
26 | if typ == jsoniterRawMessageType {
27 | return &jsoniterRawMessageCodec{}
28 | }
29 | return nil
30 | }
31 |
32 | type jsonRawMessageCodec struct {
33 | }
34 |
35 | func (codec *jsonRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
36 | *((*json.RawMessage)(ptr)) = json.RawMessage(iter.SkipAndReturnBytes())
37 | }
38 |
39 | func (codec *jsonRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
40 | stream.WriteRaw(string(*((*json.RawMessage)(ptr))))
41 | }
42 |
43 | func (codec *jsonRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool {
44 | return len(*((*json.RawMessage)(ptr))) == 0
45 | }
46 |
47 | type jsoniterRawMessageCodec struct {
48 | }
49 |
50 | func (codec *jsoniterRawMessageCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
51 | *((*RawMessage)(ptr)) = RawMessage(iter.SkipAndReturnBytes())
52 | }
53 |
54 | func (codec *jsoniterRawMessageCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
55 | stream.WriteRaw(string(*((*RawMessage)(ptr))))
56 | }
57 |
58 | func (codec *jsoniterRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool {
59 | return len(*((*RawMessage)(ptr))) == 0
60 | }
61 |
--------------------------------------------------------------------------------
/any_tests/jsoniter_any_string_test.go:
--------------------------------------------------------------------------------
1 | package any_tests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/json-iterator/go"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | var stringConvertMap = map[string]string{
11 | "null": "",
12 | "321.1": "321.1",
13 | `"1.1"`: "1.1",
14 | `"-123.1"`: "-123.1",
15 | "0.0": "0.0",
16 | "0": "0",
17 | `"0"`: "0",
18 | `"0.0"`: "0.0",
19 | `"00.0"`: "00.0",
20 | "true": "true",
21 | "false": "false",
22 | `"true"`: "true",
23 | `"false"`: "false",
24 | `"true123"`: "true123",
25 | `"+1"`: "+1",
26 | "[]": "[]",
27 | "[1,2]": "[1,2]",
28 | "{}": "{}",
29 | `{"a":1, "stream":true}`: `{"a":1, "stream":true}`,
30 | }
31 |
32 | func Test_read_any_to_string(t *testing.T) {
33 | should := require.New(t)
34 | for k, v := range stringConvertMap {
35 | any := jsoniter.Get([]byte(k))
36 | should.Equal(v, any.ToString(), "original val "+k)
37 | }
38 | }
39 |
40 | func Test_read_string_as_any(t *testing.T) {
41 | should := require.New(t)
42 | any := jsoniter.Get([]byte(`"hello"`))
43 | should.Equal("hello", any.ToString())
44 | should.True(any.ToBool())
45 | any = jsoniter.Get([]byte(`" "`))
46 | should.False(any.ToBool())
47 | any = jsoniter.Get([]byte(`"false"`))
48 | should.True(any.ToBool())
49 | any = jsoniter.Get([]byte(`"123"`))
50 | should.Equal(123, any.ToInt())
51 | }
52 |
53 | func Test_wrap_string(t *testing.T) {
54 | should := require.New(t)
55 | any := jsoniter.Get([]byte("-32000")).MustBeValid()
56 | should.Equal(-32000, any.ToInt())
57 | should.NoError(any.LastError())
58 | }
59 |
--------------------------------------------------------------------------------
/api_tests/decoder_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "github.com/json-iterator/go"
7 | "github.com/stretchr/testify/require"
8 | "io/ioutil"
9 | "testing"
10 | )
11 |
12 | func Test_disallowUnknownFields(t *testing.T) {
13 | should := require.New(t)
14 | type TestObject struct{}
15 | var obj TestObject
16 | decoder := jsoniter.NewDecoder(bytes.NewBufferString(`{"field1":100}`))
17 | decoder.DisallowUnknownFields()
18 | should.Error(decoder.Decode(&obj))
19 | }
20 |
21 | func Test_new_decoder(t *testing.T) {
22 | should := require.New(t)
23 | decoder1 := json.NewDecoder(bytes.NewBufferString(`[1][2]`))
24 | decoder2 := jsoniter.NewDecoder(bytes.NewBufferString(`[1][2]`))
25 | arr1 := []int{}
26 | should.Nil(decoder1.Decode(&arr1))
27 | should.Equal([]int{1}, arr1)
28 | arr2 := []int{}
29 | should.True(decoder1.More())
30 | buffered, _ := ioutil.ReadAll(decoder1.Buffered())
31 | should.Equal("[2]", string(buffered))
32 | should.Nil(decoder2.Decode(&arr2))
33 | should.Equal([]int{1}, arr2)
34 | should.True(decoder2.More())
35 | buffered, _ = ioutil.ReadAll(decoder2.Buffered())
36 | should.Equal("[2]", string(buffered))
37 |
38 | should.Nil(decoder1.Decode(&arr1))
39 | should.Equal([]int{2}, arr1)
40 | should.False(decoder1.More())
41 | should.Nil(decoder2.Decode(&arr2))
42 | should.Equal([]int{2}, arr2)
43 | should.False(decoder2.More())
44 | }
45 |
46 | func Test_use_number(t *testing.T) {
47 | should := require.New(t)
48 | decoder1 := json.NewDecoder(bytes.NewBufferString(`123`))
49 | decoder1.UseNumber()
50 | decoder2 := jsoniter.NewDecoder(bytes.NewBufferString(`123`))
51 | decoder2.UseNumber()
52 | var obj1 interface{}
53 | should.Nil(decoder1.Decode(&obj1))
54 | should.Equal(json.Number("123"), obj1)
55 | var obj2 interface{}
56 | should.Nil(decoder2.Decode(&obj2))
57 | should.Equal(json.Number("123"), obj2)
58 | }
59 |
60 | func Test_decoder_more(t *testing.T) {
61 | should := require.New(t)
62 | decoder := jsoniter.NewDecoder(bytes.NewBufferString("abcde"))
63 | should.True(decoder.More())
64 | }
65 |
--------------------------------------------------------------------------------
/stream_test.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "github.com/stretchr/testify/require"
5 | "testing"
6 | )
7 |
8 | func Test_writeByte_should_grow_buffer(t *testing.T) {
9 | should := require.New(t)
10 | stream := NewStream(ConfigDefault, nil, 1)
11 | stream.writeByte('1')
12 | should.Equal("1", string(stream.Buffer()))
13 | should.Equal(1, len(stream.buf))
14 | stream.writeByte('2')
15 | should.Equal("12", string(stream.Buffer()))
16 | should.Equal(2, len(stream.buf))
17 | stream.writeThreeBytes('3', '4', '5')
18 | should.Equal("12345", string(stream.Buffer()))
19 | }
20 |
21 | func Test_writeBytes_should_grow_buffer(t *testing.T) {
22 | should := require.New(t)
23 | stream := NewStream(ConfigDefault, nil, 1)
24 | stream.Write([]byte{'1', '2'})
25 | should.Equal("12", string(stream.Buffer()))
26 | should.Equal(2, len(stream.buf))
27 | stream.Write([]byte{'3', '4', '5', '6', '7'})
28 | should.Equal("1234567", string(stream.Buffer()))
29 | should.Equal(7, len(stream.buf))
30 | }
31 |
32 | func Test_writeIndention_should_grow_buffer(t *testing.T) {
33 | should := require.New(t)
34 | stream := NewStream(Config{IndentionStep: 2}.Froze(), nil, 1)
35 | stream.WriteVal([]int{1, 2, 3})
36 | should.Equal("[\n 1,\n 2,\n 3\n]", string(stream.Buffer()))
37 | }
38 |
39 | func Test_writeRaw_should_grow_buffer(t *testing.T) {
40 | should := require.New(t)
41 | stream := NewStream(ConfigDefault, nil, 1)
42 | stream.WriteRaw("123")
43 | should.Nil(stream.Error)
44 | should.Equal("123", string(stream.Buffer()))
45 | }
46 |
47 | func Test_writeString_should_grow_buffer(t *testing.T) {
48 | should := require.New(t)
49 | stream := NewStream(ConfigDefault, nil, 0)
50 | stream.WriteString("123")
51 | should.Nil(stream.Error)
52 | should.Equal(`"123"`, string(stream.Buffer()))
53 | }
54 |
55 | type NopWriter struct {
56 | bufferSize int
57 | }
58 |
59 | func (w *NopWriter) Write(p []byte) (n int, err error) {
60 | w.bufferSize = cap(p)
61 | return len(p), nil
62 | }
63 |
64 | func Test_flush_buffer_should_stop_grow_buffer(t *testing.T) {
65 | writer := new(NopWriter)
66 | NewEncoder(writer).Encode(make([]int, 10000000))
67 | should := require.New(t)
68 | should.Equal(8, writer.bufferSize)
69 | }
70 |
--------------------------------------------------------------------------------
/any_tests/jsoniter_must_be_valid_test.go:
--------------------------------------------------------------------------------
1 | package any_tests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/json-iterator/go"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | // if must be valid is useless, just drop this test
11 | func Test_must_be_valid(t *testing.T) {
12 | should := require.New(t)
13 | any := jsoniter.Get([]byte("123"))
14 | should.Equal(any.MustBeValid().ToInt(), 123)
15 |
16 | any = jsoniter.Wrap(int8(10))
17 | should.Equal(any.MustBeValid().ToInt(), 10)
18 |
19 | any = jsoniter.Wrap(int16(10))
20 | should.Equal(any.MustBeValid().ToInt(), 10)
21 |
22 | any = jsoniter.Wrap(int32(10))
23 | should.Equal(any.MustBeValid().ToInt(), 10)
24 |
25 | any = jsoniter.Wrap(int64(10))
26 | should.Equal(any.MustBeValid().ToInt(), 10)
27 |
28 | any = jsoniter.Wrap(uint(10))
29 | should.Equal(any.MustBeValid().ToInt(), 10)
30 |
31 | any = jsoniter.Wrap(uint8(10))
32 | should.Equal(any.MustBeValid().ToInt(), 10)
33 |
34 | any = jsoniter.Wrap(uint16(10))
35 | should.Equal(any.MustBeValid().ToInt(), 10)
36 |
37 | any = jsoniter.Wrap(uint32(10))
38 | should.Equal(any.MustBeValid().ToInt(), 10)
39 |
40 | any = jsoniter.Wrap(uint64(10))
41 | should.Equal(any.MustBeValid().ToInt(), 10)
42 |
43 | any = jsoniter.Wrap(float32(10))
44 | should.Equal(any.MustBeValid().ToFloat64(), float64(10))
45 |
46 | any = jsoniter.Wrap(float64(10))
47 | should.Equal(any.MustBeValid().ToFloat64(), float64(10))
48 |
49 | any = jsoniter.Wrap(true)
50 | should.Equal(any.MustBeValid().ToFloat64(), float64(1))
51 |
52 | any = jsoniter.Wrap(false)
53 | should.Equal(any.MustBeValid().ToFloat64(), float64(0))
54 |
55 | any = jsoniter.Wrap(nil)
56 | should.Equal(any.MustBeValid().ToFloat64(), float64(0))
57 |
58 | any = jsoniter.Wrap(struct{ age int }{age: 1})
59 | should.Equal(any.MustBeValid().ToFloat64(), float64(0))
60 |
61 | any = jsoniter.Wrap(map[string]interface{}{"abc": 1})
62 | should.Equal(any.MustBeValid().ToFloat64(), float64(0))
63 |
64 | any = jsoniter.Wrap("abc")
65 | should.Equal(any.MustBeValid().ToFloat64(), float64(0))
66 |
67 | any = jsoniter.Wrap([]int{})
68 | should.Equal(any.MustBeValid().ToFloat64(), float64(0))
69 |
70 | any = jsoniter.Wrap([]int{1, 2})
71 | should.Equal(any.MustBeValid().ToFloat64(), float64(1))
72 | }
73 |
--------------------------------------------------------------------------------
/value_tests/value_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "github.com/json-iterator/go"
7 | "github.com/modern-go/reflect2"
8 | "github.com/stretchr/testify/require"
9 | "testing"
10 | )
11 |
12 | type unmarshalCase struct {
13 | obj func() interface{}
14 | ptr interface{}
15 | input string
16 | selected bool
17 | }
18 |
19 | var unmarshalCases []unmarshalCase
20 |
21 | var marshalCases = []interface{}{
22 | nil,
23 | }
24 |
25 | type selectedMarshalCase struct {
26 | marshalCase interface{}
27 | }
28 |
29 | func Test_unmarshal(t *testing.T) {
30 | for _, testCase := range unmarshalCases {
31 | if testCase.selected {
32 | unmarshalCases = []unmarshalCase{testCase}
33 | break
34 | }
35 | }
36 | for i, testCase := range unmarshalCases {
37 | t.Run(fmt.Sprintf("[%v]%s", i, testCase.input), func(t *testing.T) {
38 | should := require.New(t)
39 | var obj1 interface{}
40 | var obj2 interface{}
41 | if testCase.obj != nil {
42 | obj1 = testCase.obj()
43 | obj2 = testCase.obj()
44 | } else {
45 | valType := reflect2.TypeOfPtr(testCase.ptr).Elem()
46 | obj1 = valType.New()
47 | obj2 = valType.New()
48 | }
49 | err1 := json.Unmarshal([]byte(testCase.input), obj1)
50 | should.NoError(err1, "json")
51 | err2 := jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal([]byte(testCase.input), obj2)
52 | should.NoError(err2, "jsoniter")
53 | should.Equal(obj1, obj2)
54 | })
55 | }
56 | }
57 |
58 | func Test_marshal(t *testing.T) {
59 | for _, testCase := range marshalCases {
60 | selectedMarshalCase, found := testCase.(selectedMarshalCase)
61 | if found {
62 | marshalCases = []interface{}{selectedMarshalCase.marshalCase}
63 | break
64 | }
65 | }
66 | for i, testCase := range marshalCases {
67 | var name string
68 | if testCase != nil {
69 | name = fmt.Sprintf("[%v]%v/%s", i, testCase, reflect2.TypeOf(testCase).String())
70 | }
71 | t.Run(name, func(t *testing.T) {
72 | should := require.New(t)
73 | output1, err1 := json.Marshal(testCase)
74 | should.NoError(err1, "json")
75 | output2, err2 := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(testCase)
76 | should.NoError(err2, "jsoniter")
77 | should.Equal(string(output1), string(output2))
78 | })
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/misc_tests/jsoniter_nested_test.go:
--------------------------------------------------------------------------------
1 | package misc_tests
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/json-iterator/go"
6 | "reflect"
7 | "testing"
8 | )
9 |
10 | type Level1 struct {
11 | Hello []Level2
12 | }
13 |
14 | type Level2 struct {
15 | World string
16 | }
17 |
18 | func Test_nested(t *testing.T) {
19 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `{"hello": [{"world": "value1"}, {"world": "value2"}]}`)
20 | l1 := Level1{}
21 | for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
22 | switch l1Field {
23 | case "hello":
24 | l2Array := []Level2{}
25 | for iter.ReadArray() {
26 | l2 := Level2{}
27 | for l2Field := iter.ReadObject(); l2Field != ""; l2Field = iter.ReadObject() {
28 | switch l2Field {
29 | case "world":
30 | l2.World = iter.ReadString()
31 | default:
32 | iter.ReportError("bind l2", "unexpected field: "+l2Field)
33 | }
34 | }
35 | l2Array = append(l2Array, l2)
36 | }
37 | l1.Hello = l2Array
38 | default:
39 | iter.ReportError("bind l1", "unexpected field: "+l1Field)
40 | }
41 | }
42 | if !reflect.DeepEqual(l1, Level1{
43 | Hello: []Level2{
44 | {World: "value1"},
45 | {World: "value2"},
46 | },
47 | }) {
48 | t.Fatal(l1)
49 | }
50 | }
51 |
52 | func Benchmark_jsoniter_nested(b *testing.B) {
53 | for n := 0; n < b.N; n++ {
54 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `{"hello": [{"world": "value1"}, {"world": "value2"}]}`)
55 | l1 := Level1{}
56 | for l1Field := iter.ReadObject(); l1Field != ""; l1Field = iter.ReadObject() {
57 | switch l1Field {
58 | case "hello":
59 | l1.Hello = readLevel1Hello(iter)
60 | default:
61 | iter.Skip()
62 | }
63 | }
64 | }
65 | }
66 |
67 | func readLevel1Hello(iter *jsoniter.Iterator) []Level2 {
68 | l2Array := make([]Level2, 0, 2)
69 | for iter.ReadArray() {
70 | l2 := Level2{}
71 | for l2Field := iter.ReadObject(); l2Field != ""; l2Field = iter.ReadObject() {
72 | switch l2Field {
73 | case "world":
74 | l2.World = iter.ReadString()
75 | default:
76 | iter.Skip()
77 | }
78 | }
79 | l2Array = append(l2Array, l2)
80 | }
81 | return l2Array
82 | }
83 |
84 | func Benchmark_json_nested(b *testing.B) {
85 | for n := 0; n < b.N; n++ {
86 | l1 := Level1{}
87 | json.Unmarshal([]byte(`{"hello": [{"world": "value1"}, {"world": "value2"}]}`), &l1)
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/misc_tests/jsoniter_null_test.go:
--------------------------------------------------------------------------------
1 | package misc_tests
2 |
3 | import (
4 | "bytes"
5 | "io"
6 | "testing"
7 |
8 | "github.com/json-iterator/go"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func Test_read_null(t *testing.T) {
13 | should := require.New(t)
14 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `null`)
15 | should.True(iter.ReadNil())
16 | iter = jsoniter.ParseString(jsoniter.ConfigDefault, `null`)
17 | should.Nil(iter.Read())
18 | iter = jsoniter.ParseString(jsoniter.ConfigDefault, `navy`)
19 | iter.Read()
20 | should.True(iter.Error != nil && iter.Error != io.EOF)
21 | iter = jsoniter.ParseString(jsoniter.ConfigDefault, `navy`)
22 | iter.ReadNil()
23 | should.True(iter.Error != nil && iter.Error != io.EOF)
24 | }
25 |
26 | func Test_write_null(t *testing.T) {
27 | should := require.New(t)
28 | buf := &bytes.Buffer{}
29 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, buf, 4096)
30 | stream.WriteNil()
31 | stream.Flush()
32 | should.Nil(stream.Error)
33 | should.Equal("null", buf.String())
34 | }
35 |
36 | func Test_decode_null_object_field(t *testing.T) {
37 | should := require.New(t)
38 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[null,"a"]`)
39 | iter.ReadArray()
40 | if iter.ReadObject() != "" {
41 | t.FailNow()
42 | }
43 | iter.ReadArray()
44 | if iter.ReadString() != "a" {
45 | t.FailNow()
46 | }
47 | type TestObject struct {
48 | Field string
49 | }
50 | objs := []TestObject{}
51 | should.Nil(jsoniter.UnmarshalFromString("[null]", &objs))
52 | should.Len(objs, 1)
53 | }
54 |
55 | func Test_decode_null_array_element(t *testing.T) {
56 | should := require.New(t)
57 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[null,"a"]`)
58 | should.True(iter.ReadArray())
59 | should.True(iter.ReadNil())
60 | should.True(iter.ReadArray())
61 | should.Equal("a", iter.ReadString())
62 | }
63 |
64 | func Test_decode_null_string(t *testing.T) {
65 | should := require.New(t)
66 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[null,"a"]`)
67 | should.True(iter.ReadArray())
68 | should.Equal("", iter.ReadString())
69 | should.True(iter.ReadArray())
70 | should.Equal("a", iter.ReadString())
71 | }
72 |
73 | func Test_decode_null_skip(t *testing.T) {
74 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[null,"a"]`)
75 | iter.ReadArray()
76 | iter.Skip()
77 | iter.ReadArray()
78 | if iter.ReadString() != "a" {
79 | t.FailNow()
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/iter_skip_strict.go:
--------------------------------------------------------------------------------
1 | //+build !jsoniter_sloppy
2 |
3 | package jsoniter
4 |
5 | import (
6 | "fmt"
7 | "io"
8 | )
9 |
10 | func (iter *Iterator) skipNumber() {
11 | if !iter.trySkipNumber() {
12 | iter.unreadByte()
13 | if iter.Error != nil && iter.Error != io.EOF {
14 | return
15 | }
16 | iter.ReadFloat64()
17 | if iter.Error != nil && iter.Error != io.EOF {
18 | iter.Error = nil
19 | iter.ReadBigFloat()
20 | }
21 | }
22 | }
23 |
24 | func (iter *Iterator) trySkipNumber() bool {
25 | dotFound := false
26 | for i := iter.head; i < iter.tail; i++ {
27 | c := iter.buf[i]
28 | switch c {
29 | case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
30 | case '.':
31 | if dotFound {
32 | iter.ReportError("validateNumber", `more than one dot found in number`)
33 | return true // already failed
34 | }
35 | if i+1 == iter.tail {
36 | return false
37 | }
38 | c = iter.buf[i+1]
39 | switch c {
40 | case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
41 | default:
42 | iter.ReportError("validateNumber", `missing digit after dot`)
43 | return true // already failed
44 | }
45 | dotFound = true
46 | default:
47 | switch c {
48 | case ',', ']', '}', ' ', '\t', '\n', '\r':
49 | if iter.head == i {
50 | return false // if - without following digits
51 | }
52 | iter.head = i
53 | return true // must be valid
54 | }
55 | return false // may be invalid
56 | }
57 | }
58 | return false
59 | }
60 |
61 | func (iter *Iterator) skipString() {
62 | if !iter.trySkipString() {
63 | iter.unreadByte()
64 | iter.ReadString()
65 | }
66 | }
67 |
68 | func (iter *Iterator) trySkipString() bool {
69 | for i := iter.head; i < iter.tail; i++ {
70 | c := iter.buf[i]
71 | if c == '"' {
72 | iter.head = i + 1
73 | return true // valid
74 | } else if c == '\\' {
75 | return false
76 | } else if c < ' ' {
77 | iter.ReportError("trySkipString",
78 | fmt.Sprintf(`invalid control character found: %d`, c))
79 | return true // already failed
80 | }
81 | }
82 | return false
83 | }
84 |
85 | func (iter *Iterator) skipObject() {
86 | iter.unreadByte()
87 | iter.ReadObjectCB(func(iter *Iterator, field string) bool {
88 | iter.Skip()
89 | return true
90 | })
91 | }
92 |
93 | func (iter *Iterator) skipArray() {
94 | iter.unreadByte()
95 | iter.ReadArrayCB(func(iter *Iterator) bool {
96 | iter.Skip()
97 | return true
98 | })
99 | }
100 |
--------------------------------------------------------------------------------
/any_bool.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | type trueAny struct {
4 | baseAny
5 | }
6 |
7 | func (any *trueAny) LastError() error {
8 | return nil
9 | }
10 |
11 | func (any *trueAny) ToBool() bool {
12 | return true
13 | }
14 |
15 | func (any *trueAny) ToInt() int {
16 | return 1
17 | }
18 |
19 | func (any *trueAny) ToInt32() int32 {
20 | return 1
21 | }
22 |
23 | func (any *trueAny) ToInt64() int64 {
24 | return 1
25 | }
26 |
27 | func (any *trueAny) ToUint() uint {
28 | return 1
29 | }
30 |
31 | func (any *trueAny) ToUint32() uint32 {
32 | return 1
33 | }
34 |
35 | func (any *trueAny) ToUint64() uint64 {
36 | return 1
37 | }
38 |
39 | func (any *trueAny) ToFloat32() float32 {
40 | return 1
41 | }
42 |
43 | func (any *trueAny) ToFloat64() float64 {
44 | return 1
45 | }
46 |
47 | func (any *trueAny) ToString() string {
48 | return "true"
49 | }
50 |
51 | func (any *trueAny) WriteTo(stream *Stream) {
52 | stream.WriteTrue()
53 | }
54 |
55 | func (any *trueAny) Parse() *Iterator {
56 | return nil
57 | }
58 |
59 | func (any *trueAny) GetInterface() interface{} {
60 | return true
61 | }
62 |
63 | func (any *trueAny) ValueType() ValueType {
64 | return BoolValue
65 | }
66 |
67 | func (any *trueAny) MustBeValid() Any {
68 | return any
69 | }
70 |
71 | type falseAny struct {
72 | baseAny
73 | }
74 |
75 | func (any *falseAny) LastError() error {
76 | return nil
77 | }
78 |
79 | func (any *falseAny) ToBool() bool {
80 | return false
81 | }
82 |
83 | func (any *falseAny) ToInt() int {
84 | return 0
85 | }
86 |
87 | func (any *falseAny) ToInt32() int32 {
88 | return 0
89 | }
90 |
91 | func (any *falseAny) ToInt64() int64 {
92 | return 0
93 | }
94 |
95 | func (any *falseAny) ToUint() uint {
96 | return 0
97 | }
98 |
99 | func (any *falseAny) ToUint32() uint32 {
100 | return 0
101 | }
102 |
103 | func (any *falseAny) ToUint64() uint64 {
104 | return 0
105 | }
106 |
107 | func (any *falseAny) ToFloat32() float32 {
108 | return 0
109 | }
110 |
111 | func (any *falseAny) ToFloat64() float64 {
112 | return 0
113 | }
114 |
115 | func (any *falseAny) ToString() string {
116 | return "false"
117 | }
118 |
119 | func (any *falseAny) WriteTo(stream *Stream) {
120 | stream.WriteFalse()
121 | }
122 |
123 | func (any *falseAny) Parse() *Iterator {
124 | return nil
125 | }
126 |
127 | func (any *falseAny) GetInterface() interface{} {
128 | return false
129 | }
130 |
131 | func (any *falseAny) ValueType() ValueType {
132 | return BoolValue
133 | }
134 |
135 | func (any *falseAny) MustBeValid() Any {
136 | return any
137 | }
138 |
--------------------------------------------------------------------------------
/any_tests/jsoniter_any_float_test.go:
--------------------------------------------------------------------------------
1 | package any_tests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/json-iterator/go"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | var floatConvertMap = map[string]float64{
11 | "null": 0,
12 | "true": 1,
13 | "false": 0,
14 |
15 | `"true"`: 0,
16 | `"false"`: 0,
17 |
18 | "1e1": 10,
19 | "1e+1": 10,
20 | "1e-1": .1,
21 | "1E1": 10,
22 | "1E+1": 10,
23 | "1E-1": .1,
24 |
25 | "-1e1": -10,
26 | "-1e+1": -10,
27 | "-1e-1": -.1,
28 | "-1E1": -10,
29 | "-1E+1": -10,
30 | "-1E-1": -.1,
31 |
32 | `"1e1"`: 10,
33 | `"1e+1"`: 10,
34 | `"1e-1"`: .1,
35 | `"1E1"`: 10,
36 | `"1E+1"`: 10,
37 | `"1E-1"`: .1,
38 |
39 | `"-1e1"`: -10,
40 | `"-1e+1"`: -10,
41 | `"-1e-1"`: -.1,
42 | `"-1E1"`: -10,
43 | `"-1E+1"`: -10,
44 | `"-1E-1"`: -.1,
45 |
46 | "123": 123,
47 | `"123true"`: 123,
48 | `"+"`: 0,
49 | `"-"`: 0,
50 |
51 | `"-123true"`: -123,
52 | `"-99.9true"`: -99.9,
53 | "0": 0,
54 | `"0"`: 0,
55 | "-1": -1,
56 |
57 | "1.1": 1.1,
58 | "0.0": 0,
59 | "-1.1": -1.1,
60 | `"+1.1"`: 1.1,
61 | `""`: 0,
62 | "[1,2]": 1,
63 | "[]": 0,
64 | "{}": 0,
65 | `{"abc":1}`: 0,
66 | }
67 |
68 | func Test_read_any_to_float(t *testing.T) {
69 | should := require.New(t)
70 | for k, v := range floatConvertMap {
71 | any := jsoniter.Get([]byte(k))
72 | should.Equal(float64(v), any.ToFloat64(), "the original val is "+k)
73 | }
74 |
75 | for k, v := range floatConvertMap {
76 | any := jsoniter.Get([]byte(k))
77 | should.Equal(float32(v), any.ToFloat32(), "the original val is "+k)
78 | }
79 | }
80 |
81 | func Test_read_float_to_any(t *testing.T) {
82 | should := require.New(t)
83 | any := jsoniter.WrapFloat64(12.3)
84 | anyFloat64 := float64(12.3)
85 | any2 := jsoniter.WrapFloat64(-1.1)
86 | should.Equal(float64(12.3), any.ToFloat64())
87 | should.True(any.ToBool())
88 | should.Equal(float32(anyFloat64), any.ToFloat32())
89 | should.Equal(int(anyFloat64), any.ToInt())
90 | should.Equal(int32(anyFloat64), any.ToInt32())
91 | should.Equal(int64(anyFloat64), any.ToInt64())
92 | should.Equal(uint(anyFloat64), any.ToUint())
93 | should.Equal(uint32(anyFloat64), any.ToUint32())
94 | should.Equal(uint64(anyFloat64), any.ToUint64())
95 | should.Equal(uint(0), any2.ToUint())
96 | should.Equal(uint32(0), any2.ToUint32())
97 | should.Equal(uint64(0), any2.ToUint64())
98 | should.Equal(any.ValueType(), jsoniter.NumberValue)
99 |
100 | should.Equal("1.23E+01", any.ToString())
101 | }
102 |
--------------------------------------------------------------------------------
/stream_float.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "math"
5 | "strconv"
6 | )
7 |
8 | var pow10 []uint64
9 |
10 | func init() {
11 | pow10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000}
12 | }
13 |
14 | // WriteFloat32 write float32 to stream
15 | func (stream *Stream) WriteFloat32(val float32) {
16 | abs := math.Abs(float64(val))
17 | fmt := byte('f')
18 | // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
19 | if abs != 0 {
20 | if float32(abs) < 1e-6 || float32(abs) >= 1e21 {
21 | fmt = 'e'
22 | }
23 | }
24 | stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 32)
25 | }
26 |
27 | // WriteFloat32Lossy write float32 to stream with ONLY 6 digits precision although much much faster
28 | func (stream *Stream) WriteFloat32Lossy(val float32) {
29 | if val < 0 {
30 | stream.writeByte('-')
31 | val = -val
32 | }
33 | if val > 0x4ffffff {
34 | stream.WriteFloat32(val)
35 | return
36 | }
37 | precision := 6
38 | exp := uint64(1000000) // 6
39 | lval := uint64(float64(val)*float64(exp) + 0.5)
40 | stream.WriteUint64(lval / exp)
41 | fval := lval % exp
42 | if fval == 0 {
43 | return
44 | }
45 | stream.writeByte('.')
46 | for p := precision - 1; p > 0 && fval < pow10[p]; p-- {
47 | stream.writeByte('0')
48 | }
49 | stream.WriteUint64(fval)
50 | for stream.buf[len(stream.buf)-1] == '0' {
51 | stream.buf = stream.buf[:len(stream.buf)-1]
52 | }
53 | }
54 |
55 | // WriteFloat64 write float64 to stream
56 | func (stream *Stream) WriteFloat64(val float64) {
57 | abs := math.Abs(val)
58 | fmt := byte('f')
59 | // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
60 | if abs != 0 {
61 | if abs < 1e-6 || abs >= 1e21 {
62 | fmt = 'e'
63 | }
64 | }
65 | stream.buf = strconv.AppendFloat(stream.buf, float64(val), fmt, -1, 64)
66 | }
67 |
68 | // WriteFloat64Lossy write float64 to stream with ONLY 6 digits precision although much much faster
69 | func (stream *Stream) WriteFloat64Lossy(val float64) {
70 | if val < 0 {
71 | stream.writeByte('-')
72 | val = -val
73 | }
74 | if val > 0x4ffffff {
75 | stream.WriteFloat64(val)
76 | return
77 | }
78 | precision := 6
79 | exp := uint64(1000000) // 6
80 | lval := uint64(val*float64(exp) + 0.5)
81 | stream.WriteUint64(lval / exp)
82 | fval := lval % exp
83 | if fval == 0 {
84 | return
85 | }
86 | stream.writeByte('.')
87 | for p := precision - 1; p > 0 && fval < pow10[p]; p-- {
88 | stream.writeByte('0')
89 | }
90 | stream.WriteUint64(fval)
91 | for stream.buf[len(stream.buf)-1] == '0' {
92 | stream.buf = stream.buf[:len(stream.buf)-1]
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/benchmarks/large-file.json:
--------------------------------------------------------------------------------
1 | [{
2 | "person": {
3 | "id": "d50887ca-a6ce-4e59-b89f-14f0b5d03b03",
4 | "name": {
5 | "fullName": "Leonid Bugaev",
6 | "givenName": "Leonid",
7 | "familyName": "Bugaev"
8 | },
9 | "email": "leonsbox@gmail.com",
10 | "gender": "male",
11 | "location": "Saint Petersburg, Saint Petersburg, RU",
12 | "geo": {
13 | "city": "Saint Petersburg",
14 | "state": "Saint Petersburg",
15 | "country": "Russia",
16 | "lat": 59.9342802,
17 | "lng": 30.3350986
18 | },
19 | "bio": "Senior engineer at Granify.com",
20 | "site": "http://flickfaver.com",
21 | "avatar": "https://d1ts43dypk8bqh.cloudfront.net/v1/avatars/d50887ca-a6ce-4e59-b89f-14f0b5d03b03",
22 | "employment": {
23 | "name": "www.latera.ru",
24 | "title": "Software Engineer",
25 | "domain": "gmail.com"
26 | },
27 | "facebook": {
28 | "handle": "leonid.bugaev"
29 | },
30 | "github": {
31 | "handle": "buger",
32 | "id": 14009,
33 | "avatar": "https://avatars.githubusercontent.com/u/14009?v=3",
34 | "company": "Granify",
35 | "blog": "http://leonsbox.com",
36 | "followers": 95,
37 | "following": 10
38 | },
39 | "twitter": {
40 | "handle": "flickfaver",
41 | "id": 77004410,
42 | "bio": null,
43 | "followers": 2,
44 | "following": 1,
45 | "statuses": 5,
46 | "favorites": 0,
47 | "location": "",
48 | "site": "http://flickfaver.com",
49 | "avatar": null
50 | },
51 | "linkedin": {
52 | "handle": "in/leonidbugaev"
53 | },
54 | "googleplus": {
55 | "handle": null
56 | },
57 | "angellist": {
58 | "handle": "leonid-bugaev",
59 | "id": 61541,
60 | "bio": "Senior engineer at Granify.com",
61 | "blog": "http://buger.github.com",
62 | "site": "http://buger.github.com",
63 | "followers": 41,
64 | "avatar": "https://d1qb2nb5cznatu.cloudfront.net/users/61541-medium_jpg?1405474390"
65 | },
66 | "klout": {
67 | "handle": null,
68 | "score": null
69 | },
70 | "foursquare": {
71 | "handle": null
72 | },
73 | "aboutme": {
74 | "handle": "leonid.bugaev",
75 | "bio": null,
76 | "avatar": null
77 | },
78 | "gravatar": {
79 | "handle": "buger",
80 | "urls": [
81 | ],
82 | "avatar": "http://1.gravatar.com/avatar/f7c8edd577d13b8930d5522f28123510",
83 | "avatars": [
84 | {
85 | "url": "http://1.gravatar.com/avatar/f7c8edd577d13b8930d5522f28123510",
86 | "type": "thumbnail"
87 | }
88 | ]
89 | },
90 | "fuzzy": false
91 | },
92 | "company": "hello"
93 | }]
--------------------------------------------------------------------------------
/misc_tests/jsoniter_int_test.go:
--------------------------------------------------------------------------------
1 | // +build go1.8
2 |
3 | package misc_tests
4 |
5 | import (
6 | "bytes"
7 | "encoding/json"
8 | "io/ioutil"
9 | "strconv"
10 | "testing"
11 |
12 | "github.com/json-iterator/go"
13 | "github.com/stretchr/testify/require"
14 | )
15 |
16 | func Test_read_uint64_invalid(t *testing.T) {
17 | should := require.New(t)
18 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, ",")
19 | iter.ReadUint64()
20 | should.NotNil(iter.Error)
21 | }
22 |
23 | func Test_read_int32_array(t *testing.T) {
24 | should := require.New(t)
25 | input := `[123,456,789]`
26 | val := make([]int32, 0)
27 | jsoniter.UnmarshalFromString(input, &val)
28 | should.Equal(3, len(val))
29 | }
30 |
31 | func Test_read_int64_array(t *testing.T) {
32 | should := require.New(t)
33 | input := `[123,456,789]`
34 | val := make([]int64, 0)
35 | jsoniter.UnmarshalFromString(input, &val)
36 | should.Equal(3, len(val))
37 | }
38 |
39 | func Test_wrap_int(t *testing.T) {
40 | should := require.New(t)
41 | str, err := jsoniter.MarshalToString(jsoniter.WrapInt64(100))
42 | should.Nil(err)
43 | should.Equal("100", str)
44 | }
45 |
46 | func Test_write_val_int(t *testing.T) {
47 | should := require.New(t)
48 | buf := &bytes.Buffer{}
49 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, buf, 4096)
50 | stream.WriteVal(1001)
51 | stream.Flush()
52 | should.Nil(stream.Error)
53 | should.Equal("1001", buf.String())
54 | }
55 |
56 | func Test_write_val_int_ptr(t *testing.T) {
57 | should := require.New(t)
58 | buf := &bytes.Buffer{}
59 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, buf, 4096)
60 | val := 1001
61 | stream.WriteVal(&val)
62 | stream.Flush()
63 | should.Nil(stream.Error)
64 | should.Equal("1001", buf.String())
65 | }
66 |
67 | func Test_float_as_int(t *testing.T) {
68 | should := require.New(t)
69 | var i int
70 | should.NotNil(jsoniter.Unmarshal([]byte(`1.1`), &i))
71 | }
72 |
73 | func Benchmark_jsoniter_encode_int(b *testing.B) {
74 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, ioutil.Discard, 64)
75 | for n := 0; n < b.N; n++ {
76 | stream.Reset(nil)
77 | stream.WriteUint64(0xffffffff)
78 | }
79 | }
80 |
81 | func Benchmark_itoa(b *testing.B) {
82 | for n := 0; n < b.N; n++ {
83 | strconv.FormatInt(0xffffffff, 10)
84 | }
85 | }
86 |
87 | func Benchmark_jsoniter_int(b *testing.B) {
88 | iter := jsoniter.NewIterator(jsoniter.ConfigDefault)
89 | input := []byte(`100`)
90 | for n := 0; n < b.N; n++ {
91 | iter.ResetBytes(input)
92 | iter.ReadInt64()
93 | }
94 | }
95 |
96 | func Benchmark_json_int(b *testing.B) {
97 | for n := 0; n < b.N; n++ {
98 | result := int64(0)
99 | json.Unmarshal([]byte(`-100`), &result)
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/value_tests/map_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "math/big"
7 | "time"
8 | )
9 |
10 | func init() {
11 | var pRawMessage = func(val json.RawMessage) *json.RawMessage {
12 | return &val
13 | }
14 | nilMap := map[string]string(nil)
15 | marshalCases = append(marshalCases,
16 | map[string]interface{}{"abc": 1},
17 | map[string]MyInterface{"hello": MyString("world")},
18 | map[*big.Float]string{big.NewFloat(1.2): "2"},
19 | map[string]interface{}{
20 | "3": 3,
21 | "1": 1,
22 | "2": 2,
23 | },
24 | map[uint64]interface{}{
25 | uint64(1): "a",
26 | uint64(2): "a",
27 | uint64(4): "a",
28 | },
29 | nilMap,
30 | &nilMap,
31 | map[string]*json.RawMessage{"hello": pRawMessage(json.RawMessage("[]"))},
32 | map[Date]bool{{}: true},
33 | map[Date2]bool{{}: true},
34 | )
35 | unmarshalCases = append(unmarshalCases, unmarshalCase{
36 | ptr: (*map[string]string)(nil),
37 | input: `{"k\"ey": "val"}`,
38 | }, unmarshalCase{
39 | ptr: (*map[string]string)(nil),
40 | input: `null`,
41 | }, unmarshalCase{
42 | ptr: (*map[string]*json.RawMessage)(nil),
43 | input: "{\"test\":[{\"key\":\"value\"}]}",
44 | }, unmarshalCase{
45 | ptr: (*map[Date]bool)(nil),
46 | input: `{
47 | "2018-12-12": true,
48 | "2018-12-13": true,
49 | "2018-12-14": true
50 | }`,
51 | }, unmarshalCase{
52 | ptr: (*map[Date2]bool)(nil),
53 | input: `{
54 | "2018-12-12": true,
55 | "2018-12-13": true,
56 | "2018-12-14": true
57 | }`,
58 | })
59 | }
60 |
61 | type MyInterface interface {
62 | Hello() string
63 | }
64 |
65 | type MyString string
66 |
67 | func (ms MyString) Hello() string {
68 | return string(ms)
69 | }
70 |
71 | type Date struct {
72 | time.Time
73 | }
74 |
75 | func (d *Date) UnmarshalJSON(b []byte) error {
76 | dateStr := string(b) // something like `"2017-08-20"`
77 |
78 | if dateStr == "null" {
79 | return nil
80 | }
81 |
82 | t, err := time.Parse(`"2006-01-02"`, dateStr)
83 | if err != nil {
84 | return fmt.Errorf("cant parse date: %#v", err)
85 | }
86 |
87 | d.Time = t
88 | return nil
89 | }
90 |
91 | func (d *Date) MarshalJSON() ([]byte, error) {
92 | return []byte(d.Time.Format("2006-01-02")), nil
93 | }
94 |
95 | type Date2 struct {
96 | time.Time
97 | }
98 |
99 | func (d Date2) UnmarshalJSON(b []byte) error {
100 | dateStr := string(b) // something like `"2017-08-20"`
101 |
102 | if dateStr == "null" {
103 | return nil
104 | }
105 |
106 | t, err := time.Parse(`"2006-01-02"`, dateStr)
107 | if err != nil {
108 | return fmt.Errorf("cant parse date: %#v", err)
109 | }
110 |
111 | d.Time = t
112 | return nil
113 | }
114 |
115 | func (d Date2) MarshalJSON() ([]byte, error) {
116 | return []byte(d.Time.Format("2006-01-02")), nil
117 | }
118 |
--------------------------------------------------------------------------------
/value_tests/string_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/json-iterator/go"
6 | "testing"
7 | "unicode/utf8"
8 | )
9 |
10 | func init() {
11 | marshalCases = append(marshalCases,
12 | `>`,
13 | `"数字山谷"`,
14 | "he\u2029\u2028he",
15 | )
16 | for i := 0; i < utf8.RuneSelf; i++ {
17 | marshalCases = append(marshalCases, string([]byte{byte(i)}))
18 | }
19 | }
20 |
21 | func Test_read_string(t *testing.T) {
22 | badInputs := []string{
23 | ``,
24 | `"`,
25 | `"\"`,
26 | `"\\\"`,
27 | "\"\n\"",
28 | `"\U0001f64f"`,
29 | `"\uD83D\u00"`,
30 | }
31 | for i := 0; i < 32; i++ {
32 | // control characters are invalid
33 | badInputs = append(badInputs, string([]byte{'"', byte(i), '"'}))
34 | }
35 |
36 | for _, input := range badInputs {
37 | testReadString(t, input, "", true, "json.Unmarshal", json.Unmarshal)
38 | testReadString(t, input, "", true, "jsoniter.Unmarshal", jsoniter.Unmarshal)
39 | testReadString(t, input, "", true, "jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal", jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal)
40 | }
41 |
42 | goodInputs := []struct {
43 | input string
44 | expectValue string
45 | }{
46 | {`""`, ""},
47 | {`"a"`, "a"},
48 | {`null`, ""},
49 | {`"Iñtërnâtiônàlizætiøn,💝🐹🌇⛔"`, "Iñtërnâtiônàlizætiøn,💝🐹🌇⛔"},
50 | {`"\uD83D"`, string([]byte{239, 191, 189})},
51 | {`"\uD83D\\"`, string([]byte{239, 191, 189, '\\'})},
52 | {`"\uD83D\ub000"`, string([]byte{239, 191, 189, 235, 128, 128})},
53 | {`"\uD83D\ude04"`, "😄"},
54 | {`"\uDEADBEEF"`, string([]byte{239, 191, 189, 66, 69, 69, 70})},
55 | {`"hel\"lo"`, `hel"lo`},
56 | {`"hel\\\/lo"`, `hel\/lo`},
57 | {`"hel\\blo"`, `hel\blo`},
58 | {`"hel\\\blo"`, "hel\\\blo"},
59 | {`"hel\\nlo"`, `hel\nlo`},
60 | {`"hel\\\nlo"`, "hel\\\nlo"},
61 | {`"hel\\tlo"`, `hel\tlo`},
62 | {`"hel\\flo"`, `hel\flo`},
63 | {`"hel\\\flo"`, "hel\\\flo"},
64 | {`"hel\\\rlo"`, "hel\\\rlo"},
65 | {`"hel\\\tlo"`, "hel\\\tlo"},
66 | {`"\u4e2d\u6587"`, "中文"},
67 | {`"\ud83d\udc4a"`, "\xf0\x9f\x91\x8a"},
68 | }
69 |
70 | for _, tc := range goodInputs {
71 | testReadString(t, tc.input, tc.expectValue, false, "json.Unmarshal", json.Unmarshal)
72 | testReadString(t, tc.input, tc.expectValue, false, "jsoniter.Unmarshal", jsoniter.Unmarshal)
73 | testReadString(t, tc.input, tc.expectValue, false, "jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal", jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal)
74 | }
75 | }
76 |
77 | func testReadString(t *testing.T, input string, expectValue string, expectError bool, marshalerName string, marshaler func([]byte, interface{}) error) {
78 | var value string
79 | err := marshaler([]byte(input), &value)
80 | if expectError != (err != nil) {
81 | t.Errorf("%q: %s: expected error %v, got %v", input, marshalerName, expectError, err)
82 | return
83 | }
84 | if value != expectValue {
85 | t.Errorf("%q: %s: expected %q, got %q", input, marshalerName, expectValue, value)
86 | return
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/misc_tests/jsoniter_float_test.go:
--------------------------------------------------------------------------------
1 | package misc_tests
2 |
3 | import (
4 | "encoding/json"
5 | "testing"
6 |
7 | "github.com/json-iterator/go"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func Test_read_big_float(t *testing.T) {
12 | should := require.New(t)
13 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `12.3`)
14 | val := iter.ReadBigFloat()
15 | val64, _ := val.Float64()
16 | should.Equal(12.3, val64)
17 | }
18 |
19 | func Test_read_big_int(t *testing.T) {
20 | should := require.New(t)
21 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `92233720368547758079223372036854775807`)
22 | val := iter.ReadBigInt()
23 | should.NotNil(val)
24 | should.Equal(`92233720368547758079223372036854775807`, val.String())
25 | }
26 |
27 | func Test_read_float_as_interface(t *testing.T) {
28 | should := require.New(t)
29 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `12.3`)
30 | should.Equal(float64(12.3), iter.Read())
31 | }
32 |
33 | func Test_wrap_float(t *testing.T) {
34 | should := require.New(t)
35 | str, err := jsoniter.MarshalToString(jsoniter.WrapFloat64(12.3))
36 | should.Nil(err)
37 | should.Equal("12.3", str)
38 | }
39 |
40 | func Test_read_float64_cursor(t *testing.T) {
41 | should := require.New(t)
42 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, "[1.23456789\n,2,3]")
43 | should.True(iter.ReadArray())
44 | should.Equal(1.23456789, iter.Read())
45 | should.True(iter.ReadArray())
46 | should.Equal(float64(2), iter.Read())
47 | }
48 |
49 | func Test_read_float_scientific(t *testing.T) {
50 | should := require.New(t)
51 | var obj interface{}
52 | should.NoError(jsoniter.UnmarshalFromString(`1e1`, &obj))
53 | should.Equal(float64(10), obj)
54 | should.NoError(json.Unmarshal([]byte(`1e1`), &obj))
55 | should.Equal(float64(10), obj)
56 | should.NoError(jsoniter.UnmarshalFromString(`1.0e1`, &obj))
57 | should.Equal(float64(10), obj)
58 | should.NoError(json.Unmarshal([]byte(`1.0e1`), &obj))
59 | should.Equal(float64(10), obj)
60 | }
61 |
62 | func Test_lossy_float_marshal(t *testing.T) {
63 | should := require.New(t)
64 | api := jsoniter.Config{MarshalFloatWith6Digits: true}.Froze()
65 | output, err := api.MarshalToString(float64(0.1234567))
66 | should.Nil(err)
67 | should.Equal("0.123457", output)
68 | output, err = api.MarshalToString(float32(0.1234567))
69 | should.Nil(err)
70 | should.Equal("0.123457", output)
71 | }
72 |
73 | func Test_read_number(t *testing.T) {
74 | should := require.New(t)
75 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `92233720368547758079223372036854775807`)
76 | val := iter.ReadNumber()
77 | should.Equal(`92233720368547758079223372036854775807`, string(val))
78 | }
79 |
80 | func Benchmark_jsoniter_float(b *testing.B) {
81 | b.ReportAllocs()
82 | input := []byte(`1.1123,`)
83 | iter := jsoniter.NewIterator(jsoniter.ConfigDefault)
84 | for n := 0; n < b.N; n++ {
85 | iter.ResetBytes(input)
86 | iter.ReadFloat64()
87 | }
88 | }
89 |
90 | func Benchmark_json_float(b *testing.B) {
91 | for n := 0; n < b.N; n++ {
92 | result := float64(0)
93 | json.Unmarshal([]byte(`1.1`), &result)
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/type_tests/slice_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | func init() {
4 | testCases = append(testCases,
5 | (*[][4]bool)(nil),
6 | (*[][4]byte)(nil),
7 | (*[][4]float64)(nil),
8 | (*[][4]int32)(nil),
9 | (*[][4]*string)(nil),
10 | (*[][4]string)(nil),
11 | (*[][4]uint8)(nil),
12 | (*[]bool)(nil),
13 | (*[]byte)(nil),
14 | (*[]float64)(nil),
15 | (*[]int32)(nil),
16 | (*[]int64)(nil),
17 | (*[]map[int32]string)(nil),
18 | (*[]map[string]string)(nil),
19 | (*[4]*[4]bool)(nil),
20 | (*[4]*[4]byte)(nil),
21 | (*[4]*[4]float64)(nil),
22 | (*[4]*[4]int32)(nil),
23 | (*[4]*[4]*string)(nil),
24 | (*[4]*[4]string)(nil),
25 | (*[4]*[4]uint8)(nil),
26 | (*[]*bool)(nil),
27 | (*[]*float64)(nil),
28 | (*[]*int32)(nil),
29 | (*[]*map[int32]string)(nil),
30 | (*[]*map[string]string)(nil),
31 | (*[]*[]bool)(nil),
32 | (*[]*[]byte)(nil),
33 | (*[]*[]float64)(nil),
34 | (*[]*[]int32)(nil),
35 | (*[]*[]*string)(nil),
36 | (*[]*[]string)(nil),
37 | (*[]*[]uint8)(nil),
38 | (*[]*string)(nil),
39 | (*[]*struct {
40 | String string
41 | Int int32
42 | Float float64
43 | Struct struct {
44 | X string
45 | }
46 | Slice []string
47 | Map map[string]string
48 | })(nil),
49 | (*[]*uint8)(nil),
50 | (*[][]bool)(nil),
51 | (*[][]byte)(nil),
52 | (*[][]float64)(nil),
53 | (*[][]int32)(nil),
54 | (*[][]*string)(nil),
55 | (*[][]string)(nil),
56 | (*[][]uint8)(nil),
57 | (*[]string)(nil),
58 | (*[]struct{})(nil),
59 | (*[]structEmpty)(nil),
60 | (*[]struct {
61 | F *string
62 | })(nil),
63 | (*[]struct {
64 | String string
65 | Int int32
66 | Float float64
67 | Struct struct {
68 | X string
69 | }
70 | Slice []string
71 | Map map[string]string
72 | })(nil),
73 | (*[]uint8)(nil),
74 | (*[]jsonMarshaler)(nil),
75 | (*[]jsonMarshalerMap)(nil),
76 | (*[]textMarshaler)(nil),
77 | (*[]textMarshalerMap)(nil),
78 | )
79 | }
80 |
81 | type jsonMarshaler struct {
82 | Id string `json:"id,omitempty" db:"id"`
83 | }
84 |
85 | func (p *jsonMarshaler) MarshalJSON() ([]byte, error) {
86 | return []byte(`{}`), nil
87 | }
88 |
89 | func (p *jsonMarshaler) UnmarshalJSON(input []byte) error {
90 | p.Id = "hello"
91 | return nil
92 | }
93 |
94 | type jsonMarshalerMap map[int]int
95 |
96 | func (p *jsonMarshalerMap) MarshalJSON() ([]byte, error) {
97 | return []byte(`{}`), nil
98 | }
99 |
100 | func (p *jsonMarshalerMap) UnmarshalJSON(input []byte) error {
101 | return nil
102 | }
103 |
104 | type textMarshaler struct {
105 | Id string `json:"id,omitempty" db:"id"`
106 | }
107 |
108 | func (p *textMarshaler) MarshalText() ([]byte, error) {
109 | return []byte(`{}`), nil
110 | }
111 |
112 | func (p *textMarshaler) UnmarshalText(input []byte) error {
113 | p.Id = "hello"
114 | return nil
115 | }
116 |
117 | type textMarshalerMap map[int]int
118 |
119 | func (p *textMarshalerMap) MarshalText() ([]byte, error) {
120 | return []byte(`{}`), nil
121 | }
122 |
123 | func (p *textMarshalerMap) UnmarshalText(input []byte) error {
124 | return nil
125 | }
126 |
--------------------------------------------------------------------------------
/reflect_slice.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "fmt"
5 | "github.com/modern-go/reflect2"
6 | "io"
7 | "unsafe"
8 | )
9 |
10 | func decoderOfSlice(ctx *ctx, typ reflect2.Type) ValDecoder {
11 | sliceType := typ.(*reflect2.UnsafeSliceType)
12 | decoder := decoderOfType(ctx.append("[sliceElem]"), sliceType.Elem())
13 | return &sliceDecoder{sliceType, decoder}
14 | }
15 |
16 | func encoderOfSlice(ctx *ctx, typ reflect2.Type) ValEncoder {
17 | sliceType := typ.(*reflect2.UnsafeSliceType)
18 | encoder := encoderOfType(ctx.append("[sliceElem]"), sliceType.Elem())
19 | return &sliceEncoder{sliceType, encoder}
20 | }
21 |
22 | type sliceEncoder struct {
23 | sliceType *reflect2.UnsafeSliceType
24 | elemEncoder ValEncoder
25 | }
26 |
27 | func (encoder *sliceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
28 | if encoder.sliceType.UnsafeIsNil(ptr) {
29 | stream.WriteNil()
30 | return
31 | }
32 | length := encoder.sliceType.UnsafeLengthOf(ptr)
33 | if length == 0 {
34 | stream.WriteEmptyArray()
35 | return
36 | }
37 | stream.WriteArrayStart()
38 | encoder.elemEncoder.Encode(encoder.sliceType.UnsafeGetIndex(ptr, 0), stream)
39 | for i := 1; i < length; i++ {
40 | stream.WriteMore()
41 | elemPtr := encoder.sliceType.UnsafeGetIndex(ptr, i)
42 | encoder.elemEncoder.Encode(elemPtr, stream)
43 | }
44 | stream.WriteArrayEnd()
45 | if stream.Error != nil && stream.Error != io.EOF {
46 | stream.Error = fmt.Errorf("%v: %s", encoder.sliceType, stream.Error.Error())
47 | }
48 | }
49 |
50 | func (encoder *sliceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
51 | return encoder.sliceType.UnsafeLengthOf(ptr) == 0
52 | }
53 |
54 | type sliceDecoder struct {
55 | sliceType *reflect2.UnsafeSliceType
56 | elemDecoder ValDecoder
57 | }
58 |
59 | func (decoder *sliceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
60 | decoder.doDecode(ptr, iter)
61 | if iter.Error != nil && iter.Error != io.EOF {
62 | iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
63 | }
64 | }
65 |
66 | func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
67 | c := iter.nextToken()
68 | sliceType := decoder.sliceType
69 | if c == 'n' {
70 | iter.skipThreeBytes('u', 'l', 'l')
71 | sliceType.UnsafeSetNil(ptr)
72 | return
73 | }
74 | if c != '[' {
75 | iter.ReportError("decode slice", "expect [ or n, but found "+string([]byte{c}))
76 | return
77 | }
78 | c = iter.nextToken()
79 | if c == ']' {
80 | sliceType.UnsafeSet(ptr, sliceType.UnsafeMakeSlice(0, 0))
81 | return
82 | }
83 | iter.unreadByte()
84 | sliceType.UnsafeGrow(ptr, 1)
85 | elemPtr := sliceType.UnsafeGetIndex(ptr, 0)
86 | decoder.elemDecoder.Decode(elemPtr, iter)
87 | length := 1
88 | for c = iter.nextToken(); c == ','; c = iter.nextToken() {
89 | idx := length
90 | length += 1
91 | sliceType.UnsafeGrow(ptr, length)
92 | elemPtr = sliceType.UnsafeGetIndex(ptr, idx)
93 | decoder.elemDecoder.Decode(elemPtr, iter)
94 | }
95 | if c != ']' {
96 | iter.ReportError("decode slice", "expect ], but found "+string([]byte{c}))
97 | return
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/reflect_array.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "fmt"
5 | "github.com/modern-go/reflect2"
6 | "io"
7 | "unsafe"
8 | )
9 |
10 | func decoderOfArray(ctx *ctx, typ reflect2.Type) ValDecoder {
11 | arrayType := typ.(*reflect2.UnsafeArrayType)
12 | decoder := decoderOfType(ctx.append("[arrayElem]"), arrayType.Elem())
13 | return &arrayDecoder{arrayType, decoder}
14 | }
15 |
16 | func encoderOfArray(ctx *ctx, typ reflect2.Type) ValEncoder {
17 | arrayType := typ.(*reflect2.UnsafeArrayType)
18 | if arrayType.Len() == 0 {
19 | return emptyArrayEncoder{}
20 | }
21 | encoder := encoderOfType(ctx.append("[arrayElem]"), arrayType.Elem())
22 | return &arrayEncoder{arrayType, encoder}
23 | }
24 |
25 | type emptyArrayEncoder struct{}
26 |
27 | func (encoder emptyArrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
28 | stream.WriteEmptyArray()
29 | }
30 |
31 | func (encoder emptyArrayEncoder) IsEmpty(ptr unsafe.Pointer) bool {
32 | return true
33 | }
34 |
35 | type arrayEncoder struct {
36 | arrayType *reflect2.UnsafeArrayType
37 | elemEncoder ValEncoder
38 | }
39 |
40 | func (encoder *arrayEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
41 | stream.WriteArrayStart()
42 | elemPtr := unsafe.Pointer(ptr)
43 | encoder.elemEncoder.Encode(elemPtr, stream)
44 | for i := 1; i < encoder.arrayType.Len(); i++ {
45 | stream.WriteMore()
46 | elemPtr = encoder.arrayType.UnsafeGetIndex(ptr, i)
47 | encoder.elemEncoder.Encode(elemPtr, stream)
48 | }
49 | stream.WriteArrayEnd()
50 | if stream.Error != nil && stream.Error != io.EOF {
51 | stream.Error = fmt.Errorf("%v: %s", encoder.arrayType, stream.Error.Error())
52 | }
53 | }
54 |
55 | func (encoder *arrayEncoder) IsEmpty(ptr unsafe.Pointer) bool {
56 | return false
57 | }
58 |
59 | type arrayDecoder struct {
60 | arrayType *reflect2.UnsafeArrayType
61 | elemDecoder ValDecoder
62 | }
63 |
64 | func (decoder *arrayDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
65 | decoder.doDecode(ptr, iter)
66 | if iter.Error != nil && iter.Error != io.EOF {
67 | iter.Error = fmt.Errorf("%v: %s", decoder.arrayType, iter.Error.Error())
68 | }
69 | }
70 |
71 | func (decoder *arrayDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
72 | c := iter.nextToken()
73 | arrayType := decoder.arrayType
74 | if c == 'n' {
75 | iter.skipThreeBytes('u', 'l', 'l')
76 | return
77 | }
78 | if c != '[' {
79 | iter.ReportError("decode array", "expect [ or n, but found "+string([]byte{c}))
80 | return
81 | }
82 | c = iter.nextToken()
83 | if c == ']' {
84 | return
85 | }
86 | iter.unreadByte()
87 | elemPtr := arrayType.UnsafeGetIndex(ptr, 0)
88 | decoder.elemDecoder.Decode(elemPtr, iter)
89 | length := 1
90 | for c = iter.nextToken(); c == ','; c = iter.nextToken() {
91 | if length >= arrayType.Len() {
92 | iter.Skip()
93 | continue
94 | }
95 | idx := length
96 | length += 1
97 | elemPtr = arrayType.UnsafeGetIndex(ptr, idx)
98 | decoder.elemDecoder.Decode(elemPtr, iter)
99 | }
100 | if c != ']' {
101 | iter.ReportError("decode array", "expect ], but found "+string([]byte{c}))
102 | return
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/misc_tests/jsoniter_raw_message_test.go:
--------------------------------------------------------------------------------
1 | package misc_tests
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/json-iterator/go"
6 | "github.com/stretchr/testify/require"
7 | "strings"
8 | "testing"
9 | )
10 |
11 | func Test_jsoniter_RawMessage(t *testing.T) {
12 | should := require.New(t)
13 | var data jsoniter.RawMessage
14 | should.Nil(jsoniter.Unmarshal([]byte(`[1,2,3]`), &data))
15 | //fmt.Println(string(data))
16 | should.Equal(`[1,2,3]`, string(data))
17 | str, err := jsoniter.MarshalToString(data)
18 | should.Nil(err)
19 | should.Equal(`[1,2,3]`, str)
20 | }
21 |
22 | func Test_encode_map_of_jsoniter_raw_message(t *testing.T) {
23 | should := require.New(t)
24 | type RawMap map[string]*jsoniter.RawMessage
25 | value := jsoniter.RawMessage("[]")
26 | rawMap := RawMap{"hello": &value}
27 | output, err := jsoniter.MarshalToString(rawMap)
28 | should.Nil(err)
29 | should.Equal(`{"hello":[]}`, output)
30 | }
31 |
32 | func Test_marshal_invalid_json_raw_message(t *testing.T) {
33 | type A struct {
34 | Raw json.RawMessage `json:"raw"`
35 | }
36 | message := []byte(`{}`)
37 |
38 | a := A{}
39 | should := require.New(t)
40 | should.Nil(jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal(message, &a))
41 | aout, aouterr := jsoniter.ConfigCompatibleWithStandardLibrary.Marshal(&a)
42 | should.Equal(`{"raw":null}`, string(aout))
43 | should.Nil(aouterr)
44 | }
45 |
46 | func Test_raw_message_memory_not_copied_issue(t *testing.T) {
47 | jsonStream := `{"name":"xxxxx","bundle_id":"com.zonst.majiang","app_platform":"ios","app_category":"100103", "budget_day":1000,"bidding_min":1,"bidding_max":2,"bidding_type":"CPM", "freq":{"open":true,"type":"day","num":100},"speed":1, "targeting":{"vendor":{"open":true,"list":["zonst"]}, "geo_code":{"open":true,"list":["156110100"]},"app_category":{"open":true,"list":["100101"]}, "day_parting":{"open":true,"list":["100409","100410"]},"device_type":{"open":true,"list":["ipad"]}, "os_version":{"open":true,"list":[10]},"carrier":{"open":true,"list":["mobile"]}, "network":{"open":true,"list":["4G"]}},"url":{"tracking_imp_url":"http://www.baidu.com", "tracking_clk_url":"http://www.baidu.com","jump_url":"http://www.baidu.com","deep_link_url":"http://www.baidu.com"}}`
48 | type IteratorObject struct {
49 | Name *string `json:"name"`
50 | BundleId *string `json:"bundle_id"`
51 | AppCategory *string `json:"app_category"`
52 | AppPlatform *string `json:"app_platform"`
53 | BudgetDay *float32 `json:"budget_day"`
54 | BiddingMax *float32 `json:"bidding_max"`
55 | BiddingMin *float32 `json:"bidding_min"`
56 | BiddingType *string `json:"bidding_type"`
57 | Freq *jsoniter.RawMessage `json:"freq"`
58 | Targeting *jsoniter.RawMessage `json:"targeting"`
59 | Url *jsoniter.RawMessage `json:"url"`
60 | Speed *int `json:"speed" db:"speed"`
61 | }
62 |
63 | obj := &IteratorObject{}
64 | decoder := jsoniter.NewDecoder(strings.NewReader(jsonStream))
65 | err := decoder.Decode(obj)
66 | should := require.New(t)
67 | should.Nil(err)
68 | should.Equal(`{"open":true,"type":"day","num":100}`, string(*obj.Freq))
69 | }
70 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://sourcegraph.com/github.com/json-iterator/go?badge)
2 | [](http://godoc.org/github.com/json-iterator/go)
3 | [](https://travis-ci.org/json-iterator/go)
4 | [](https://codecov.io/gh/json-iterator/go)
5 | [](https://goreportcard.com/report/github.com/json-iterator/go)
6 | [](https://raw.githubusercontent.com/json-iterator/go/master/LICENSE)
7 | [](https://gitter.im/json-iterator/Lobby)
8 |
9 | A high-performance 100% compatible drop-in replacement of "encoding/json"
10 |
11 | You can also use thrift like JSON using [thrift-iterator](https://github.com/thrift-iterator/go)
12 |
13 | ```
14 | Go开发者们请加入我们,滴滴出行平台技术部 taowen@didichuxing.com
15 | ```
16 |
17 | # Benchmark
18 |
19 | 
20 |
21 | Source code: https://github.com/json-iterator/go-benchmark/blob/master/src/github.com/json-iterator/go-benchmark/benchmark_medium_payload_test.go
22 |
23 | Raw Result (easyjson requires static code generation)
24 |
25 | | | ns/op | allocation bytes | allocation times |
26 | | --- | --- | --- | --- |
27 | | std decode | 35510 ns/op | 1960 B/op | 99 allocs/op |
28 | | easyjson decode | 8499 ns/op | 160 B/op | 4 allocs/op |
29 | | jsoniter decode | 5623 ns/op | 160 B/op | 3 allocs/op |
30 | | std encode | 2213 ns/op | 712 B/op | 5 allocs/op |
31 | | easyjson encode | 883 ns/op | 576 B/op | 3 allocs/op |
32 | | jsoniter encode | 837 ns/op | 384 B/op | 4 allocs/op |
33 |
34 | Always benchmark with your own workload.
35 | The result depends heavily on the data input.
36 |
37 | # Usage
38 |
39 | 100% compatibility with standard lib
40 |
41 | Replace
42 |
43 | ```go
44 | import "encoding/json"
45 | json.Marshal(&data)
46 | ```
47 |
48 | with
49 |
50 | ```go
51 | import "github.com/json-iterator/go"
52 |
53 | var json = jsoniter.ConfigCompatibleWithStandardLibrary
54 | json.Marshal(&data)
55 | ```
56 |
57 | Replace
58 |
59 | ```go
60 | import "encoding/json"
61 | json.Unmarshal(input, &data)
62 | ```
63 |
64 | with
65 |
66 | ```go
67 | import "github.com/json-iterator/go"
68 |
69 | var json = jsoniter.ConfigCompatibleWithStandardLibrary
70 | json.Unmarshal(input, &data)
71 | ```
72 |
73 | [More documentation](http://jsoniter.com/migrate-from-go-std.html)
74 |
75 | # How to get
76 |
77 | ```
78 | go get github.com/json-iterator/go
79 | ```
80 |
81 | # Contribution Welcomed !
82 |
83 | Contributors
84 |
85 | * [thockin](https://github.com/thockin)
86 | * [mattn](https://github.com/mattn)
87 | * [cch123](https://github.com/cch123)
88 | * [Oleg Shaldybin](https://github.com/olegshaldybin)
89 | * [Jason Toffaletti](https://github.com/toffaletti)
90 |
91 | Report issue or pull request, or email taowen@gmail.com, or [](https://gitter.im/json-iterator/Lobby)
92 |
--------------------------------------------------------------------------------
/any_number.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "io"
5 | "unsafe"
6 | )
7 |
8 | type numberLazyAny struct {
9 | baseAny
10 | cfg *frozenConfig
11 | buf []byte
12 | err error
13 | }
14 |
15 | func (any *numberLazyAny) ValueType() ValueType {
16 | return NumberValue
17 | }
18 |
19 | func (any *numberLazyAny) MustBeValid() Any {
20 | return any
21 | }
22 |
23 | func (any *numberLazyAny) LastError() error {
24 | return any.err
25 | }
26 |
27 | func (any *numberLazyAny) ToBool() bool {
28 | return any.ToFloat64() != 0
29 | }
30 |
31 | func (any *numberLazyAny) ToInt() int {
32 | iter := any.cfg.BorrowIterator(any.buf)
33 | defer any.cfg.ReturnIterator(iter)
34 | val := iter.ReadInt()
35 | if iter.Error != nil && iter.Error != io.EOF {
36 | any.err = iter.Error
37 | }
38 | return val
39 | }
40 |
41 | func (any *numberLazyAny) ToInt32() int32 {
42 | iter := any.cfg.BorrowIterator(any.buf)
43 | defer any.cfg.ReturnIterator(iter)
44 | val := iter.ReadInt32()
45 | if iter.Error != nil && iter.Error != io.EOF {
46 | any.err = iter.Error
47 | }
48 | return val
49 | }
50 |
51 | func (any *numberLazyAny) ToInt64() int64 {
52 | iter := any.cfg.BorrowIterator(any.buf)
53 | defer any.cfg.ReturnIterator(iter)
54 | val := iter.ReadInt64()
55 | if iter.Error != nil && iter.Error != io.EOF {
56 | any.err = iter.Error
57 | }
58 | return val
59 | }
60 |
61 | func (any *numberLazyAny) ToUint() uint {
62 | iter := any.cfg.BorrowIterator(any.buf)
63 | defer any.cfg.ReturnIterator(iter)
64 | val := iter.ReadUint()
65 | if iter.Error != nil && iter.Error != io.EOF {
66 | any.err = iter.Error
67 | }
68 | return val
69 | }
70 |
71 | func (any *numberLazyAny) ToUint32() uint32 {
72 | iter := any.cfg.BorrowIterator(any.buf)
73 | defer any.cfg.ReturnIterator(iter)
74 | val := iter.ReadUint32()
75 | if iter.Error != nil && iter.Error != io.EOF {
76 | any.err = iter.Error
77 | }
78 | return val
79 | }
80 |
81 | func (any *numberLazyAny) ToUint64() uint64 {
82 | iter := any.cfg.BorrowIterator(any.buf)
83 | defer any.cfg.ReturnIterator(iter)
84 | val := iter.ReadUint64()
85 | if iter.Error != nil && iter.Error != io.EOF {
86 | any.err = iter.Error
87 | }
88 | return val
89 | }
90 |
91 | func (any *numberLazyAny) ToFloat32() float32 {
92 | iter := any.cfg.BorrowIterator(any.buf)
93 | defer any.cfg.ReturnIterator(iter)
94 | val := iter.ReadFloat32()
95 | if iter.Error != nil && iter.Error != io.EOF {
96 | any.err = iter.Error
97 | }
98 | return val
99 | }
100 |
101 | func (any *numberLazyAny) ToFloat64() float64 {
102 | iter := any.cfg.BorrowIterator(any.buf)
103 | defer any.cfg.ReturnIterator(iter)
104 | val := iter.ReadFloat64()
105 | if iter.Error != nil && iter.Error != io.EOF {
106 | any.err = iter.Error
107 | }
108 | return val
109 | }
110 |
111 | func (any *numberLazyAny) ToString() string {
112 | return *(*string)(unsafe.Pointer(&any.buf))
113 | }
114 |
115 | func (any *numberLazyAny) WriteTo(stream *Stream) {
116 | stream.Write(any.buf)
117 | }
118 |
119 | func (any *numberLazyAny) GetInterface() interface{} {
120 | iter := any.cfg.BorrowIterator(any.buf)
121 | defer any.cfg.ReturnIterator(iter)
122 | return iter.Read()
123 | }
124 |
--------------------------------------------------------------------------------
/reflect_json_number.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/modern-go/reflect2"
6 | "strconv"
7 | "unsafe"
8 | )
9 |
10 | type Number string
11 |
12 | // String returns the literal text of the number.
13 | func (n Number) String() string { return string(n) }
14 |
15 | // Float64 returns the number as a float64.
16 | func (n Number) Float64() (float64, error) {
17 | return strconv.ParseFloat(string(n), 64)
18 | }
19 |
20 | // Int64 returns the number as an int64.
21 | func (n Number) Int64() (int64, error) {
22 | return strconv.ParseInt(string(n), 10, 64)
23 | }
24 |
25 | func CastJsonNumber(val interface{}) (string, bool) {
26 | switch typedVal := val.(type) {
27 | case json.Number:
28 | return string(typedVal), true
29 | case Number:
30 | return string(typedVal), true
31 | }
32 | return "", false
33 | }
34 |
35 | var jsonNumberType = reflect2.TypeOfPtr((*json.Number)(nil)).Elem()
36 | var jsoniterNumberType = reflect2.TypeOfPtr((*Number)(nil)).Elem()
37 |
38 | func createDecoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValDecoder {
39 | if typ.AssignableTo(jsonNumberType) {
40 | return &jsonNumberCodec{}
41 | }
42 | if typ.AssignableTo(jsoniterNumberType) {
43 | return &jsoniterNumberCodec{}
44 | }
45 | return nil
46 | }
47 |
48 | func createEncoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValEncoder {
49 | if typ.AssignableTo(jsonNumberType) {
50 | return &jsonNumberCodec{}
51 | }
52 | if typ.AssignableTo(jsoniterNumberType) {
53 | return &jsoniterNumberCodec{}
54 | }
55 | return nil
56 | }
57 |
58 | type jsonNumberCodec struct {
59 | }
60 |
61 | func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
62 | switch iter.WhatIsNext() {
63 | case StringValue:
64 | *((*json.Number)(ptr)) = json.Number(iter.ReadString())
65 | case NilValue:
66 | iter.skipFourBytes('n', 'u', 'l', 'l')
67 | *((*json.Number)(ptr)) = ""
68 | default:
69 | *((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString()))
70 | }
71 | }
72 |
73 | func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
74 | number := *((*json.Number)(ptr))
75 | if len(number) == 0 {
76 | stream.writeByte('0')
77 | } else {
78 | stream.WriteRaw(string(number))
79 | }
80 | }
81 |
82 | func (codec *jsonNumberCodec) IsEmpty(ptr unsafe.Pointer) bool {
83 | return len(*((*json.Number)(ptr))) == 0
84 | }
85 |
86 | type jsoniterNumberCodec struct {
87 | }
88 |
89 | func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
90 | switch iter.WhatIsNext() {
91 | case StringValue:
92 | *((*Number)(ptr)) = Number(iter.ReadString())
93 | case NilValue:
94 | iter.skipFourBytes('n', 'u', 'l', 'l')
95 | *((*Number)(ptr)) = ""
96 | default:
97 | *((*Number)(ptr)) = Number([]byte(iter.readNumberAsString()))
98 | }
99 | }
100 |
101 | func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
102 | number := *((*Number)(ptr))
103 | if len(number) == 0 {
104 | stream.writeByte('0')
105 | } else {
106 | stream.WriteRaw(string(number))
107 | }
108 | }
109 |
110 | func (codec *jsoniterNumberCodec) IsEmpty(ptr unsafe.Pointer) bool {
111 | return len(*((*Number)(ptr))) == 0
112 | }
113 |
--------------------------------------------------------------------------------
/example_test.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "strings"
7 | )
8 |
9 | func ExampleMarshal() {
10 | type ColorGroup struct {
11 | ID int
12 | Name string
13 | Colors []string
14 | }
15 | group := ColorGroup{
16 | ID: 1,
17 | Name: "Reds",
18 | Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
19 | }
20 | b, err := Marshal(group)
21 | if err != nil {
22 | fmt.Println("error:", err)
23 | }
24 | os.Stdout.Write(b)
25 | // Output:
26 | // {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
27 | }
28 |
29 | func ExampleUnmarshal() {
30 | var jsonBlob = []byte(`[
31 | {"Name": "Platypus", "Order": "Monotremata"},
32 | {"Name": "Quoll", "Order": "Dasyuromorphia"}
33 | ]`)
34 | type Animal struct {
35 | Name string
36 | Order string
37 | }
38 | var animals []Animal
39 | err := Unmarshal(jsonBlob, &animals)
40 | if err != nil {
41 | fmt.Println("error:", err)
42 | }
43 | fmt.Printf("%+v", animals)
44 | // Output:
45 | // [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
46 | }
47 |
48 | func ExampleConfigFastest_Marshal() {
49 | type ColorGroup struct {
50 | ID int
51 | Name string
52 | Colors []string
53 | }
54 | group := ColorGroup{
55 | ID: 1,
56 | Name: "Reds",
57 | Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
58 | }
59 | stream := ConfigFastest.BorrowStream(nil)
60 | defer ConfigFastest.ReturnStream(stream)
61 | stream.WriteVal(group)
62 | if stream.Error != nil {
63 | fmt.Println("error:", stream.Error)
64 | }
65 | os.Stdout.Write(stream.Buffer())
66 | // Output:
67 | // {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
68 | }
69 |
70 | func ExampleConfigFastest_Unmarshal() {
71 | var jsonBlob = []byte(`[
72 | {"Name": "Platypus", "Order": "Monotremata"},
73 | {"Name": "Quoll", "Order": "Dasyuromorphia"}
74 | ]`)
75 | type Animal struct {
76 | Name string
77 | Order string
78 | }
79 | var animals []Animal
80 | iter := ConfigFastest.BorrowIterator(jsonBlob)
81 | defer ConfigFastest.ReturnIterator(iter)
82 | iter.ReadVal(&animals)
83 | if iter.Error != nil {
84 | fmt.Println("error:", iter.Error)
85 | }
86 | fmt.Printf("%+v", animals)
87 | // Output:
88 | // [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
89 | }
90 |
91 | func ExampleGet() {
92 | //val := []byte(`{"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}`)
93 | val := []byte(`{"ID":1,"Name":"Reds","Colors":{"c":"Crimson","r":"Red","rb":"Ruby","m":"Maroon"}}`)
94 | fmt.Printf(Get(val, "Colors", 0).ToString())
95 | // Output:
96 | // Crimson
97 | }
98 |
99 | func ExampleMapKey() {
100 | hello := MyKey("hello")
101 | output, _ := Marshal(map[*MyKey]string{&hello: "world"})
102 | fmt.Println(string(output))
103 | obj := map[*MyKey]string{}
104 | Unmarshal(output, &obj)
105 | for k, v := range obj {
106 | fmt.Println(*k, v)
107 | }
108 | // Output:
109 | // {"Hello":"world"}
110 | // Hel world
111 | }
112 |
113 | type MyKey string
114 |
115 | func (m *MyKey) MarshalText() ([]byte, error) {
116 | return []byte(strings.Replace(string(*m), "h", "H", -1)), nil
117 | }
118 |
119 | func (m *MyKey) UnmarshalText(text []byte) error {
120 | *m = MyKey(text[:3])
121 | return nil
122 | }
123 |
--------------------------------------------------------------------------------
/demo/example.go:
--------------------------------------------------------------------------------
1 | /*
2 | * iterator-api:用于处理超大的输入
3 | * bind-api:日常最经常使用的对象绑定
4 | * any-api:lazy 解析大对象,具有 PHP Array 一般的使用体验
5 | */
6 |
7 | package main
8 |
9 | import (
10 | "fmt"
11 | "github.com/json-iterator/go"
12 | "os"
13 | "strings"
14 | )
15 |
16 | type ColorGroup struct {
17 | ID int
18 | Name string
19 | Colors []string
20 | }
21 |
22 | type Animal struct {
23 | Name string
24 | Order string
25 | }
26 |
27 | func main() {
28 | // ================= 序列化 =====================
29 | group := ColorGroup{
30 | ID: 1,
31 | Name: "Reds",
32 | Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
33 | }
34 | b, err := jsoniter.Marshal(group)
35 | bb, err := jsoniter.MarshalIndent(group, "", " ")
36 | if err != nil{
37 | fmt.Println("error: ", err)
38 | }
39 | os.Stdout.Write(b)
40 | fmt.Println()
41 | os.Stdout.Write(bb)
42 | fmt.Println()
43 |
44 | // =================== Deconde 解码 =================
45 | jsoniter.NewDecoder(os.Stdin).Decode(&group)
46 | fmt.Println(group)
47 |
48 | encoder := jsoniter.NewEncoder(os.Stdout)
49 | encoder.SetEscapeHTML(true)
50 | encoder.Encode(bb)
51 | fmt.Println(string(bb))
52 |
53 | // =================== 反序列化 =======================
54 | var jsonBlob = []byte(`[
55 | {"Name": "Platypus", "Order": "Monotremata"},
56 | {"Name": "Quoll", "Order": "Dasyuromorphia"}
57 | ]`)
58 | var animals []Animal
59 | if err := jsoniter.Unmarshal(jsonBlob, &animals); err != nil{
60 | fmt.Println("error: ", err)
61 | }
62 |
63 | fmt.Printf("the unmarshal is %+v", animals)
64 |
65 | // ======================= 流式 ========================
66 | fmt.Println()
67 |
68 | // 序列化
69 | stream := jsoniter.ConfigFastest.BorrowStream(nil)
70 | defer jsoniter.ConfigFastest.ReturnStream(stream)
71 | stream.WriteVal(group)
72 | if stream.Error != nil{
73 | fmt.Println("error: ", stream.Error)
74 | }
75 | os.Stdout.Write(stream.Buffer())
76 |
77 | fmt.Println()
78 | // 反序列化
79 | iter := jsoniter.ConfigFastest.BorrowIterator(jsonBlob)
80 | defer jsoniter.ConfigFastest.ReturnIterator(iter)
81 | iter.ReadVal(&animals)
82 | if iter.Error != nil{
83 | fmt.Println("error: ", iter.Error)
84 | }
85 | fmt.Printf("%+v", animals)
86 |
87 | fmt.Println()
88 | // ====================其他操作===================
89 | // get
90 | val := []byte(`{"ID":1,"Name":"Reds","Colors":{"c":"Crimson","r":"Red","rb":"Ruby","m":"Maroon","tests":["tests_1","tests_2","tests_3","tests_4"]}}`)
91 | fmt.Println(jsoniter.Get(val, "Colors").ToString())
92 | fmt.Println("the result is " , jsoniter.Get(val, "Colors","tests",0).ToString())
93 | // fmt.Println(jsoniter.Get(val, "colors", 0).ToString())
94 |
95 | fmt.Println()
96 | hello := MyKey("hello")
97 | output, _ := jsoniter.Marshal(map[*MyKey]string{&hello: "world"})
98 | fmt.Println(string(output))
99 |
100 | obj := map[*MyKey]string{}
101 | jsoniter.Unmarshal(output, &obj)
102 | for k, v := range obj{
103 | fmt.Println(*k," = ", v)
104 | }
105 |
106 | }
107 | // 自定义类型
108 | // 序列化: 需要实现MarshellText
109 | type MyKey string
110 |
111 | func (m *MyKey) MarshalText() ([]byte, error){
112 | // return []byte(string(*m)) , nil // 针对序列化的内容不做任何调整
113 | return []byte(strings.Replace(string(*m), "h","H",-1)), nil
114 | }
115 |
116 | func(m *MyKey) UnmarshalText(text []byte) error{
117 | *m = MyKey(text[:]) // 针对text不做处理
118 | return nil
119 | }
120 |
--------------------------------------------------------------------------------
/extension_tests/extension_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "github.com/modern-go/reflect2"
6 | "github.com/stretchr/testify/require"
7 | "reflect"
8 | "strconv"
9 | "testing"
10 | "unsafe"
11 | )
12 |
13 | type TestObject1 struct {
14 | Field1 string
15 | }
16 |
17 | type testExtension struct {
18 | jsoniter.DummyExtension
19 | }
20 |
21 | func (extension *testExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
22 | if structDescriptor.Type.String() != "test.TestObject1" {
23 | return
24 | }
25 | binding := structDescriptor.GetField("Field1")
26 | binding.Encoder = &funcEncoder{fun: func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
27 | str := *((*string)(ptr))
28 | val, _ := strconv.Atoi(str)
29 | stream.WriteInt(val)
30 | }}
31 | binding.Decoder = &funcDecoder{func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
32 | *((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
33 | }}
34 | binding.ToNames = []string{"field-1"}
35 | binding.FromNames = []string{"field-1"}
36 | }
37 |
38 | func Test_customize_field_by_extension(t *testing.T) {
39 | should := require.New(t)
40 | cfg := jsoniter.Config{}.Froze()
41 | cfg.RegisterExtension(&testExtension{})
42 | obj := TestObject1{}
43 | err := cfg.UnmarshalFromString(`{"field-1": 100}`, &obj)
44 | should.Nil(err)
45 | should.Equal("100", obj.Field1)
46 | str, err := cfg.MarshalToString(obj)
47 | should.Nil(err)
48 | should.Equal(`{"field-1":100}`, str)
49 | }
50 |
51 | func Test_customize_map_key_encoder(t *testing.T) {
52 | should := require.New(t)
53 | cfg := jsoniter.Config{}.Froze()
54 | cfg.RegisterExtension(&testMapKeyExtension{})
55 | m := map[int]int{1: 2}
56 | output, err := cfg.MarshalToString(m)
57 | should.NoError(err)
58 | should.Equal(`{"2":2}`, output)
59 | m = map[int]int{}
60 | should.NoError(cfg.UnmarshalFromString(output, &m))
61 | should.Equal(map[int]int{1: 2}, m)
62 | }
63 |
64 | type testMapKeyExtension struct {
65 | jsoniter.DummyExtension
66 | }
67 |
68 | func (extension *testMapKeyExtension) CreateMapKeyEncoder(typ reflect2.Type) jsoniter.ValEncoder {
69 | if typ.Kind() == reflect.Int {
70 | return &funcEncoder{
71 | fun: func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
72 | stream.WriteRaw(`"`)
73 | stream.WriteInt(*(*int)(ptr) + 1)
74 | stream.WriteRaw(`"`)
75 | },
76 | }
77 | }
78 | return nil
79 | }
80 |
81 | func (extension *testMapKeyExtension) CreateMapKeyDecoder(typ reflect2.Type) jsoniter.ValDecoder {
82 | if typ.Kind() == reflect.Int {
83 | return &funcDecoder{
84 | fun: func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
85 | i, err := strconv.Atoi(iter.ReadString())
86 | if err != nil {
87 | iter.ReportError("read map key", err.Error())
88 | return
89 | }
90 | i--
91 | *(*int)(ptr) = i
92 | },
93 | }
94 | }
95 | return nil
96 | }
97 |
98 | type funcDecoder struct {
99 | fun jsoniter.DecoderFunc
100 | }
101 |
102 | func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
103 | decoder.fun(ptr, iter)
104 | }
105 |
106 | type funcEncoder struct {
107 | fun jsoniter.EncoderFunc
108 | isEmptyFunc func(ptr unsafe.Pointer) bool
109 | }
110 |
111 | func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
112 | encoder.fun(ptr, stream)
113 | }
114 |
115 | func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool {
116 | if encoder.isEmptyFunc == nil {
117 | return false
118 | }
119 | return encoder.isEmptyFunc(ptr)
120 | }
121 |
--------------------------------------------------------------------------------
/iter_skip_sloppy.go:
--------------------------------------------------------------------------------
1 | //+build jsoniter_sloppy
2 |
3 | package jsoniter
4 |
5 | // sloppy but faster implementation, do not validate the input json
6 |
7 | func (iter *Iterator) skipNumber() {
8 | for {
9 | for i := iter.head; i < iter.tail; i++ {
10 | c := iter.buf[i]
11 | switch c {
12 | case ' ', '\n', '\r', '\t', ',', '}', ']':
13 | iter.head = i
14 | return
15 | }
16 | }
17 | if !iter.loadMore() {
18 | return
19 | }
20 | }
21 | }
22 |
23 | func (iter *Iterator) skipArray() {
24 | level := 1
25 | for {
26 | for i := iter.head; i < iter.tail; i++ {
27 | switch iter.buf[i] {
28 | case '"': // If inside string, skip it
29 | iter.head = i + 1
30 | iter.skipString()
31 | i = iter.head - 1 // it will be i++ soon
32 | case '[': // If open symbol, increase level
33 | level++
34 | case ']': // If close symbol, increase level
35 | level--
36 |
37 | // If we have returned to the original level, we're done
38 | if level == 0 {
39 | iter.head = i + 1
40 | return
41 | }
42 | }
43 | }
44 | if !iter.loadMore() {
45 | iter.ReportError("skipObject", "incomplete array")
46 | return
47 | }
48 | }
49 | }
50 |
51 | func (iter *Iterator) skipObject() {
52 | level := 1
53 | for {
54 | for i := iter.head; i < iter.tail; i++ {
55 | switch iter.buf[i] {
56 | case '"': // If inside string, skip it
57 | iter.head = i + 1
58 | iter.skipString()
59 | i = iter.head - 1 // it will be i++ soon
60 | case '{': // If open symbol, increase level
61 | level++
62 | case '}': // If close symbol, increase level
63 | level--
64 |
65 | // If we have returned to the original level, we're done
66 | if level == 0 {
67 | iter.head = i + 1
68 | return
69 | }
70 | }
71 | }
72 | if !iter.loadMore() {
73 | iter.ReportError("skipObject", "incomplete object")
74 | return
75 | }
76 | }
77 | }
78 |
79 | func (iter *Iterator) skipString() {
80 | for {
81 | end, escaped := iter.findStringEnd()
82 | if end == -1 {
83 | if !iter.loadMore() {
84 | iter.ReportError("skipString", "incomplete string")
85 | return
86 | }
87 | if escaped {
88 | iter.head = 1 // skip the first char as last char read is \
89 | }
90 | } else {
91 | iter.head = end
92 | return
93 | }
94 | }
95 | }
96 |
97 | // adapted from: https://github.com/buger/jsonparser/blob/master/parser.go
98 | // Tries to find the end of string
99 | // Support if string contains escaped quote symbols.
100 | func (iter *Iterator) findStringEnd() (int, bool) {
101 | escaped := false
102 | for i := iter.head; i < iter.tail; i++ {
103 | c := iter.buf[i]
104 | if c == '"' {
105 | if !escaped {
106 | return i + 1, false
107 | }
108 | j := i - 1
109 | for {
110 | if j < iter.head || iter.buf[j] != '\\' {
111 | // even number of backslashes
112 | // either end of buffer, or " found
113 | return i + 1, true
114 | }
115 | j--
116 | if j < iter.head || iter.buf[j] != '\\' {
117 | // odd number of backslashes
118 | // it is \" or \\\"
119 | break
120 | }
121 | j--
122 | }
123 | } else if c == '\\' {
124 | escaped = true
125 | }
126 | }
127 | j := iter.tail - 1
128 | for {
129 | if j < iter.head || iter.buf[j] != '\\' {
130 | // even number of backslashes
131 | // either end of buffer, or " found
132 | return -1, false // do not end with \
133 | }
134 | j--
135 | if j < iter.head || iter.buf[j] != '\\' {
136 | // odd number of backslashes
137 | // it is \" or \\\"
138 | break
139 | }
140 | j--
141 |
142 | }
143 | return -1, true // end with \
144 | }
145 |
--------------------------------------------------------------------------------
/any_str.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | )
7 |
8 | type stringAny struct {
9 | baseAny
10 | val string
11 | }
12 |
13 | func (any *stringAny) Get(path ...interface{}) Any {
14 | if len(path) == 0 {
15 | return any
16 | }
17 | return &invalidAny{baseAny{}, fmt.Errorf("GetIndex %v from simple value", path)}
18 | }
19 |
20 | func (any *stringAny) Parse() *Iterator {
21 | return nil
22 | }
23 |
24 | func (any *stringAny) ValueType() ValueType {
25 | return StringValue
26 | }
27 |
28 | func (any *stringAny) MustBeValid() Any {
29 | return any
30 | }
31 |
32 | func (any *stringAny) LastError() error {
33 | return nil
34 | }
35 |
36 | func (any *stringAny) ToBool() bool {
37 | str := any.ToString()
38 | if str == "0" {
39 | return false
40 | }
41 | for _, c := range str {
42 | switch c {
43 | case ' ', '\n', '\r', '\t':
44 | default:
45 | return true
46 | }
47 | }
48 | return false
49 | }
50 |
51 | func (any *stringAny) ToInt() int {
52 | return int(any.ToInt64())
53 |
54 | }
55 |
56 | func (any *stringAny) ToInt32() int32 {
57 | return int32(any.ToInt64())
58 | }
59 |
60 | func (any *stringAny) ToInt64() int64 {
61 | if any.val == "" {
62 | return 0
63 | }
64 |
65 | flag := 1
66 | startPos := 0
67 | endPos := 0
68 | if any.val[0] == '+' || any.val[0] == '-' {
69 | startPos = 1
70 | }
71 |
72 | if any.val[0] == '-' {
73 | flag = -1
74 | }
75 |
76 | for i := startPos; i < len(any.val); i++ {
77 | if any.val[i] >= '0' && any.val[i] <= '9' {
78 | endPos = i + 1
79 | } else {
80 | break
81 | }
82 | }
83 | parsed, _ := strconv.ParseInt(any.val[startPos:endPos], 10, 64)
84 | return int64(flag) * parsed
85 | }
86 |
87 | func (any *stringAny) ToUint() uint {
88 | return uint(any.ToUint64())
89 | }
90 |
91 | func (any *stringAny) ToUint32() uint32 {
92 | return uint32(any.ToUint64())
93 | }
94 |
95 | func (any *stringAny) ToUint64() uint64 {
96 | if any.val == "" {
97 | return 0
98 | }
99 |
100 | startPos := 0
101 | endPos := 0
102 |
103 | if any.val[0] == '-' {
104 | return 0
105 | }
106 | if any.val[0] == '+' {
107 | startPos = 1
108 | }
109 |
110 | for i := startPos; i < len(any.val); i++ {
111 | if any.val[i] >= '0' && any.val[i] <= '9' {
112 | endPos = i + 1
113 | } else {
114 | break
115 | }
116 | }
117 | parsed, _ := strconv.ParseUint(any.val[startPos:endPos], 10, 64)
118 | return parsed
119 | }
120 |
121 | func (any *stringAny) ToFloat32() float32 {
122 | return float32(any.ToFloat64())
123 | }
124 |
125 | func (any *stringAny) ToFloat64() float64 {
126 | if len(any.val) == 0 {
127 | return 0
128 | }
129 |
130 | // first char invalid
131 | if any.val[0] != '+' && any.val[0] != '-' && (any.val[0] > '9' || any.val[0] < '0') {
132 | return 0
133 | }
134 |
135 | // extract valid num expression from string
136 | // eg 123true => 123, -12.12xxa => -12.12
137 | endPos := 1
138 | for i := 1; i < len(any.val); i++ {
139 | if any.val[i] == '.' || any.val[i] == 'e' || any.val[i] == 'E' || any.val[i] == '+' || any.val[i] == '-' {
140 | endPos = i + 1
141 | continue
142 | }
143 |
144 | // end position is the first char which is not digit
145 | if any.val[i] >= '0' && any.val[i] <= '9' {
146 | endPos = i + 1
147 | } else {
148 | endPos = i
149 | break
150 | }
151 | }
152 | parsed, _ := strconv.ParseFloat(any.val[:endPos], 64)
153 | return parsed
154 | }
155 |
156 | func (any *stringAny) ToString() string {
157 | return any.val
158 | }
159 |
160 | func (any *stringAny) WriteTo(stream *Stream) {
161 | stream.WriteString(any.val)
162 | }
163 |
164 | func (any *stringAny) GetInterface() interface{} {
165 | return any.val
166 | }
167 |
--------------------------------------------------------------------------------
/iter_skip.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import "fmt"
4 |
5 | // ReadNil reads a json object as nil and
6 | // returns whether it's a nil or not
7 | func (iter *Iterator) ReadNil() (ret bool) {
8 | c := iter.nextToken()
9 | if c == 'n' {
10 | iter.skipThreeBytes('u', 'l', 'l') // null
11 | return true
12 | }
13 | iter.unreadByte()
14 | return false
15 | }
16 |
17 | // ReadBool reads a json object as BoolValue
18 | func (iter *Iterator) ReadBool() (ret bool) {
19 | c := iter.nextToken()
20 | if c == 't' {
21 | iter.skipThreeBytes('r', 'u', 'e')
22 | return true
23 | }
24 | if c == 'f' {
25 | iter.skipFourBytes('a', 'l', 's', 'e')
26 | return false
27 | }
28 | iter.ReportError("ReadBool", "expect t or f, but found "+string([]byte{c}))
29 | return
30 | }
31 |
32 | // SkipAndReturnBytes skip next JSON element, and return its content as []byte.
33 | // The []byte can be kept, it is a copy of data.
34 | func (iter *Iterator) SkipAndReturnBytes() []byte {
35 | iter.startCapture(iter.head)
36 | iter.Skip()
37 | return iter.stopCapture()
38 | }
39 |
40 | type captureBuffer struct {
41 | startedAt int
42 | captured []byte
43 | }
44 |
45 | func (iter *Iterator) startCapture(captureStartedAt int) {
46 | if iter.captured != nil {
47 | panic("already in capture mode")
48 | }
49 | iter.captureStartedAt = captureStartedAt
50 | iter.captured = make([]byte, 0, 32)
51 | }
52 |
53 | func (iter *Iterator) stopCapture() []byte {
54 | if iter.captured == nil {
55 | panic("not in capture mode")
56 | }
57 | captured := iter.captured
58 | remaining := iter.buf[iter.captureStartedAt:iter.head]
59 | iter.captureStartedAt = -1
60 | iter.captured = nil
61 | if len(captured) == 0 {
62 | copied := make([]byte, len(remaining))
63 | copy(copied, remaining)
64 | return copied
65 | }
66 | captured = append(captured, remaining...)
67 | return captured
68 | }
69 |
70 | // Skip skips a json object and positions to relatively the next json object
71 | func (iter *Iterator) Skip() {
72 | c := iter.nextToken()
73 | switch c {
74 | case '"':
75 | iter.skipString()
76 | case 'n':
77 | iter.skipThreeBytes('u', 'l', 'l') // null
78 | case 't':
79 | iter.skipThreeBytes('r', 'u', 'e') // true
80 | case 'f':
81 | iter.skipFourBytes('a', 'l', 's', 'e') // false
82 | case '0':
83 | iter.unreadByte()
84 | iter.ReadFloat32()
85 | case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9':
86 | iter.skipNumber()
87 | case '[':
88 | iter.skipArray()
89 | case '{':
90 | iter.skipObject()
91 | default:
92 | iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c))
93 | return
94 | }
95 | }
96 |
97 | func (iter *Iterator) skipFourBytes(b1, b2, b3, b4 byte) {
98 | if iter.readByte() != b1 {
99 | iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4})))
100 | return
101 | }
102 | if iter.readByte() != b2 {
103 | iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4})))
104 | return
105 | }
106 | if iter.readByte() != b3 {
107 | iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4})))
108 | return
109 | }
110 | if iter.readByte() != b4 {
111 | iter.ReportError("skipFourBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3, b4})))
112 | return
113 | }
114 | }
115 |
116 | func (iter *Iterator) skipThreeBytes(b1, b2, b3 byte) {
117 | if iter.readByte() != b1 {
118 | iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3})))
119 | return
120 | }
121 | if iter.readByte() != b2 {
122 | iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3})))
123 | return
124 | }
125 | if iter.readByte() != b3 {
126 | iter.ReportError("skipThreeBytes", fmt.Sprintf("expect %s", string([]byte{b1, b2, b3})))
127 | return
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/iter_skip_sloppy_test.go:
--------------------------------------------------------------------------------
1 | //+build jsoniter_sloppy
2 |
3 | package jsoniter
4 |
5 | import (
6 | "github.com/stretchr/testify/require"
7 | "io"
8 | "testing"
9 | )
10 |
11 | func Test_string_end(t *testing.T) {
12 | end, escaped := ParseString(ConfigDefault, `abc"`).findStringEnd()
13 | if end != 4 {
14 | t.Fatal(end)
15 | }
16 | if escaped != false {
17 | t.Fatal(escaped)
18 | }
19 | end, escaped = ParseString(ConfigDefault, `abc\\"`).findStringEnd()
20 | if end != 6 {
21 | t.Fatal(end)
22 | }
23 | if escaped != true {
24 | t.Fatal(escaped)
25 | }
26 | end, escaped = ParseString(ConfigDefault, `abc\\\\"`).findStringEnd()
27 | if end != 8 {
28 | t.Fatal(end)
29 | }
30 | if escaped != true {
31 | t.Fatal(escaped)
32 | }
33 | end, escaped = ParseString(ConfigDefault, `abc\"`).findStringEnd()
34 | if end != -1 {
35 | t.Fatal(end)
36 | }
37 | if escaped != false {
38 | t.Fatal(escaped)
39 | }
40 | end, escaped = ParseString(ConfigDefault, `abc\`).findStringEnd()
41 | if end != -1 {
42 | t.Fatal(end)
43 | }
44 | if escaped != true {
45 | t.Fatal(escaped)
46 | }
47 | end, escaped = ParseString(ConfigDefault, `abc\\`).findStringEnd()
48 | if end != -1 {
49 | t.Fatal(end)
50 | }
51 | if escaped != false {
52 | t.Fatal(escaped)
53 | }
54 | end, escaped = ParseString(ConfigDefault, `\\`).findStringEnd()
55 | if end != -1 {
56 | t.Fatal(end)
57 | }
58 | if escaped != false {
59 | t.Fatal(escaped)
60 | }
61 | end, escaped = ParseString(ConfigDefault, `\`).findStringEnd()
62 | if end != -1 {
63 | t.Fatal(end)
64 | }
65 | if escaped != true {
66 | t.Fatal(escaped)
67 | }
68 | }
69 |
70 | type StagedReader struct {
71 | r1 string
72 | r2 string
73 | r3 string
74 | r int
75 | }
76 |
77 | func (reader *StagedReader) Read(p []byte) (n int, err error) {
78 | reader.r++
79 | switch reader.r {
80 | case 1:
81 | copy(p, []byte(reader.r1))
82 | return len(reader.r1), nil
83 | case 2:
84 | copy(p, []byte(reader.r2))
85 | return len(reader.r2), nil
86 | case 3:
87 | copy(p, []byte(reader.r3))
88 | return len(reader.r3), nil
89 | default:
90 | return 0, io.EOF
91 | }
92 | }
93 |
94 | func Test_skip_string(t *testing.T) {
95 | should := require.New(t)
96 | iter := ParseString(ConfigDefault, `"abc`)
97 | iter.skipString()
98 | should.Equal(1, iter.head)
99 | iter = ParseString(ConfigDefault, `\""abc`)
100 | iter.skipString()
101 | should.Equal(3, iter.head)
102 | reader := &StagedReader{
103 | r1: `abc`,
104 | r2: `"`,
105 | }
106 | iter = Parse(ConfigDefault, reader, 4096)
107 | iter.skipString()
108 | should.Equal(1, iter.head)
109 | reader = &StagedReader{
110 | r1: `abc`,
111 | r2: `1"`,
112 | }
113 | iter = Parse(ConfigDefault, reader, 4096)
114 | iter.skipString()
115 | should.Equal(2, iter.head)
116 | reader = &StagedReader{
117 | r1: `abc\`,
118 | r2: `"`,
119 | }
120 | iter = Parse(ConfigDefault, reader, 4096)
121 | iter.skipString()
122 | should.NotNil(iter.Error)
123 | reader = &StagedReader{
124 | r1: `abc\`,
125 | r2: `""`,
126 | }
127 | iter = Parse(ConfigDefault, reader, 4096)
128 | iter.skipString()
129 | should.Equal(2, iter.head)
130 | }
131 |
132 | func Test_skip_object(t *testing.T) {
133 | iter := ParseString(ConfigDefault, `}`)
134 | iter.skipObject()
135 | if iter.head != 1 {
136 | t.Fatal(iter.head)
137 | }
138 | iter = ParseString(ConfigDefault, `a}`)
139 | iter.skipObject()
140 | if iter.head != 2 {
141 | t.Fatal(iter.head)
142 | }
143 | iter = ParseString(ConfigDefault, `{}}a`)
144 | iter.skipObject()
145 | if iter.head != 3 {
146 | t.Fatal(iter.head)
147 | }
148 | reader := &StagedReader{
149 | r1: `{`,
150 | r2: `}}a`,
151 | }
152 | iter = Parse(ConfigDefault, reader, 4096)
153 | iter.skipObject()
154 | if iter.head != 2 {
155 | t.Fatal(iter.head)
156 | }
157 | iter = ParseString(ConfigDefault, `"}"}a`)
158 | iter.skipObject()
159 | if iter.head != 4 {
160 | t.Fatal(iter.head)
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/any_tests/jsoniter_wrap_test.go:
--------------------------------------------------------------------------------
1 | package any_tests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/json-iterator/go"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func Test_wrap_and_valuetype_everything(t *testing.T) {
11 | should := require.New(t)
12 | var i interface{}
13 | any := jsoniter.Get([]byte("123"))
14 | // default of number type is float64
15 | i = float64(123)
16 | should.Equal(i, any.GetInterface())
17 |
18 | any = jsoniter.Wrap(int8(10))
19 | should.Equal(any.ValueType(), jsoniter.NumberValue)
20 | should.Equal(any.LastError(), nil)
21 | // get interface is not int8 interface
22 | // i = int8(10)
23 | // should.Equal(i, any.GetInterface())
24 |
25 | any = jsoniter.Wrap(int16(10))
26 | should.Equal(any.ValueType(), jsoniter.NumberValue)
27 | should.Equal(any.LastError(), nil)
28 | //i = int16(10)
29 | //should.Equal(i, any.GetInterface())
30 |
31 | any = jsoniter.Wrap(int32(10))
32 | should.Equal(any.ValueType(), jsoniter.NumberValue)
33 | should.Equal(any.LastError(), nil)
34 | i = int32(10)
35 | should.Equal(i, any.GetInterface())
36 | any = jsoniter.Wrap(int64(10))
37 | should.Equal(any.ValueType(), jsoniter.NumberValue)
38 | should.Equal(any.LastError(), nil)
39 | i = int64(10)
40 | should.Equal(i, any.GetInterface())
41 |
42 | any = jsoniter.Wrap(uint(10))
43 | should.Equal(any.ValueType(), jsoniter.NumberValue)
44 | should.Equal(any.LastError(), nil)
45 | // not equal
46 | //i = uint(10)
47 | //should.Equal(i, any.GetInterface())
48 | any = jsoniter.Wrap(uint8(10))
49 | should.Equal(any.ValueType(), jsoniter.NumberValue)
50 | should.Equal(any.LastError(), nil)
51 | // not equal
52 | // i = uint8(10)
53 | // should.Equal(i, any.GetInterface())
54 | any = jsoniter.Wrap(uint16(10))
55 | should.Equal(any.ValueType(), jsoniter.NumberValue)
56 | should.Equal(any.LastError(), nil)
57 | any = jsoniter.Wrap(uint32(10))
58 | should.Equal(any.ValueType(), jsoniter.NumberValue)
59 | should.Equal(any.LastError(), nil)
60 | i = uint32(10)
61 | should.Equal(i, any.GetInterface())
62 | any = jsoniter.Wrap(uint64(10))
63 | should.Equal(any.ValueType(), jsoniter.NumberValue)
64 | should.Equal(any.LastError(), nil)
65 | i = uint64(10)
66 | should.Equal(i, any.GetInterface())
67 |
68 | any = jsoniter.Wrap(float32(10))
69 | should.Equal(any.ValueType(), jsoniter.NumberValue)
70 | should.Equal(any.LastError(), nil)
71 | // not equal
72 | //i = float32(10)
73 | //should.Equal(i, any.GetInterface())
74 | any = jsoniter.Wrap(float64(10))
75 | should.Equal(any.ValueType(), jsoniter.NumberValue)
76 | should.Equal(any.LastError(), nil)
77 | i = float64(10)
78 | should.Equal(i, any.GetInterface())
79 |
80 | any = jsoniter.Wrap(true)
81 | should.Equal(any.ValueType(), jsoniter.BoolValue)
82 | should.Equal(any.LastError(), nil)
83 | i = true
84 | should.Equal(i, any.GetInterface())
85 | any = jsoniter.Wrap(false)
86 | should.Equal(any.ValueType(), jsoniter.BoolValue)
87 | should.Equal(any.LastError(), nil)
88 | i = false
89 | should.Equal(i, any.GetInterface())
90 |
91 | any = jsoniter.Wrap(nil)
92 | should.Equal(any.ValueType(), jsoniter.NilValue)
93 | should.Equal(any.LastError(), nil)
94 | i = nil
95 | should.Equal(i, any.GetInterface())
96 |
97 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, nil, 32)
98 | any.WriteTo(stream)
99 | should.Equal("null", string(stream.Buffer()))
100 | should.Equal(any.LastError(), nil)
101 |
102 | any = jsoniter.Wrap(struct{ age int }{age: 1})
103 | should.Equal(any.ValueType(), jsoniter.ObjectValue)
104 | should.Equal(any.LastError(), nil)
105 | i = struct{ age int }{age: 1}
106 | should.Equal(i, any.GetInterface())
107 |
108 | any = jsoniter.Wrap(map[string]interface{}{"abc": 1})
109 | should.Equal(any.ValueType(), jsoniter.ObjectValue)
110 | should.Equal(any.LastError(), nil)
111 | i = map[string]interface{}{"abc": 1}
112 | should.Equal(i, any.GetInterface())
113 |
114 | any = jsoniter.Wrap("abc")
115 | i = "abc"
116 | should.Equal(i, any.GetInterface())
117 | should.Equal(nil, any.LastError())
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/misc_tests/jsoniter_map_test.go:
--------------------------------------------------------------------------------
1 | package misc_tests
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "math/big"
7 | "testing"
8 |
9 | "github.com/json-iterator/go"
10 | "github.com/stretchr/testify/require"
11 | "strings"
12 | )
13 |
14 | func Test_decode_TextMarshaler_key_map(t *testing.T) {
15 | should := require.New(t)
16 | var val map[*big.Float]string
17 | should.Nil(jsoniter.UnmarshalFromString(`{"1":"2"}`, &val))
18 | str, err := jsoniter.MarshalToString(val)
19 | should.Nil(err)
20 | should.Equal(`{"1":"2"}`, str)
21 | }
22 |
23 | // case sensitive
24 | func Test_case_sensitive_field(t *testing.T){
25 | should := require.New(t)
26 | type product struct {
27 | Name string
28 | ProductID int64
29 | Number int
30 | Price float64
31 | IsOnSale bool
32 | }
33 | var str = `{"name":"Xiao mi 6","nmber":10000,"price":2499,"is_on_sale": false}`
34 | config := jsoniter.Config{CaseSensitive: true}.Froze()
35 | var gval product
36 | err := config.UnmarshalFromString(str,&gval)
37 | fmt.Println(str,"\nthe unmarshal for string result is ", gval)
38 |
39 | should.Nil(err)
40 | }
41 |
42 | // only tag field
43 | func Test_encode_only_tag_filed(t *testing.T){
44 | should := require.New(t)
45 | type product struct {
46 | Name string `json:"name"`
47 | ProductID int64 `json:"product_id,omitempty"`
48 | Number int `json:"number"`
49 | Price float64 //`json:"price"`
50 | IsOnSale bool //`json:"is_on_sale,omitempty"`
51 | }
52 | var str = `{"name":"Xiao mi 6","number":10000,"price":2499,"is_on_sale": false}`
53 | config := jsoniter.Config{OnlyTaggedField: false}.Froze()
54 | var gval product
55 | err := config.UnmarshalFromString(str,&gval)
56 | fmt.Println(str,"\nthe unmarshal for string result is ", gval)
57 |
58 | //str1, err := config.MarshalToString(group)
59 | //fmt.Println(str,"\nthe marshal result is ", str1)
60 | should.Nil(err)
61 | }
62 |
63 | // SortMapKeys
64 | func Test_encode_sort_key_map(t *testing.T){
65 | should := require.New(t)
66 | var val map[*big.Float]string
67 |
68 | config := jsoniter.Config{SortMapKeys: true}.Froze()
69 | config.UnmarshalFromString(`{"4":"1", "2":"3","1":"5"}`,&val)
70 | str, err := config.MarshalToString(val)
71 | fmt.Println(str)
72 | should.Nil(err)
73 | should.Equal(`{"1":"5","2":"3","4":"1"}`, str)
74 | }
75 |
76 | func Test_read_map_with_reader(t *testing.T) {
77 | should := require.New(t)
78 | 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}`
79 | reader := strings.NewReader(input)
80 | decoder := jsoniter.ConfigCompatibleWithStandardLibrary.NewDecoder(reader)
81 | m1 := map[string]interface{}{}
82 | should.Nil(decoder.Decode(&m1))
83 | m2 := map[string]interface{}{}
84 | should.Nil(json.Unmarshal([]byte(input), &m2))
85 | should.Equal(m2, m1)
86 | should.Equal("1.0.76", m1["note"].(map[string]interface{})["CoreServices"].(map[string]interface{})["version_name"])
87 | }
88 |
89 | func Test_map_eface_of_eface(t *testing.T) {
90 | should := require.New(t)
91 | json := jsoniter.ConfigCompatibleWithStandardLibrary
92 | output, err := json.MarshalToString(map[interface{}]interface{}{
93 | "1": 2,
94 | 3: "4",
95 | })
96 | should.NoError(err)
97 | should.Equal(`{"1":2,"3":"4"}`, output)
98 | }
99 |
--------------------------------------------------------------------------------
/reflect_optional.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | import (
4 | "github.com/modern-go/reflect2"
5 | "reflect"
6 | "unsafe"
7 | )
8 |
9 | func decoderOfOptional(ctx *ctx, typ reflect2.Type) ValDecoder {
10 | ptrType := typ.(*reflect2.UnsafePtrType)
11 | elemType := ptrType.Elem()
12 | decoder := decoderOfType(ctx, elemType)
13 | if ctx.prefix == "" && elemType.Kind() == reflect.Ptr {
14 | return &dereferenceDecoder{elemType, decoder}
15 | }
16 | return &OptionalDecoder{elemType, decoder}
17 | }
18 |
19 | func encoderOfOptional(ctx *ctx, typ reflect2.Type) ValEncoder {
20 | ptrType := typ.(*reflect2.UnsafePtrType)
21 | elemType := ptrType.Elem()
22 | elemEncoder := encoderOfType(ctx, elemType)
23 | encoder := &OptionalEncoder{elemEncoder}
24 | return encoder
25 | }
26 |
27 | type OptionalDecoder struct {
28 | ValueType reflect2.Type
29 | ValueDecoder ValDecoder
30 | }
31 |
32 | func (decoder *OptionalDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
33 | if iter.ReadNil() {
34 | *((*unsafe.Pointer)(ptr)) = nil
35 | } else {
36 | if *((*unsafe.Pointer)(ptr)) == nil {
37 | //pointer to null, we have to allocate memory to hold the value
38 | newPtr := decoder.ValueType.UnsafeNew()
39 | decoder.ValueDecoder.Decode(newPtr, iter)
40 | *((*unsafe.Pointer)(ptr)) = newPtr
41 | } else {
42 | //reuse existing instance
43 | decoder.ValueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter)
44 | }
45 | }
46 | }
47 |
48 | type dereferenceDecoder struct {
49 | // only to deference a pointer
50 | valueType reflect2.Type
51 | valueDecoder ValDecoder
52 | }
53 |
54 | func (decoder *dereferenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
55 | if *((*unsafe.Pointer)(ptr)) == nil {
56 | //pointer to null, we have to allocate memory to hold the value
57 | newPtr := decoder.valueType.UnsafeNew()
58 | decoder.valueDecoder.Decode(newPtr, iter)
59 | *((*unsafe.Pointer)(ptr)) = newPtr
60 | } else {
61 | //reuse existing instance
62 | decoder.valueDecoder.Decode(*((*unsafe.Pointer)(ptr)), iter)
63 | }
64 | }
65 |
66 | type OptionalEncoder struct {
67 | ValueEncoder ValEncoder
68 | }
69 |
70 | func (encoder *OptionalEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
71 | if *((*unsafe.Pointer)(ptr)) == nil {
72 | stream.WriteNil()
73 | } else {
74 | encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream)
75 | }
76 | }
77 |
78 | func (encoder *OptionalEncoder) IsEmpty(ptr unsafe.Pointer) bool {
79 | return *((*unsafe.Pointer)(ptr)) == nil
80 | }
81 |
82 | type dereferenceEncoder struct {
83 | ValueEncoder ValEncoder
84 | }
85 |
86 | func (encoder *dereferenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
87 | if *((*unsafe.Pointer)(ptr)) == nil {
88 | stream.WriteNil()
89 | } else {
90 | encoder.ValueEncoder.Encode(*((*unsafe.Pointer)(ptr)), stream)
91 | }
92 | }
93 |
94 | func (encoder *dereferenceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
95 | dePtr := *((*unsafe.Pointer)(ptr))
96 | if dePtr == nil {
97 | return true
98 | }
99 | return encoder.ValueEncoder.IsEmpty(dePtr)
100 | }
101 |
102 | func (encoder *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool {
103 | deReferenced := *((*unsafe.Pointer)(ptr))
104 | if deReferenced == nil {
105 | return true
106 | }
107 | isEmbeddedPtrNil, converted := encoder.ValueEncoder.(IsEmbeddedPtrNil)
108 | if !converted {
109 | return false
110 | }
111 | fieldPtr := unsafe.Pointer(deReferenced)
112 | return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr)
113 | }
114 |
115 | type referenceEncoder struct {
116 | encoder ValEncoder
117 | }
118 |
119 | func (encoder *referenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
120 | encoder.encoder.Encode(unsafe.Pointer(&ptr), stream)
121 | }
122 |
123 | func (encoder *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
124 | return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr))
125 | }
126 |
127 | type referenceDecoder struct {
128 | decoder ValDecoder
129 | }
130 |
131 | func (decoder *referenceDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
132 | decoder.decoder.Decode(unsafe.Pointer(&ptr), iter)
133 | }
134 |
--------------------------------------------------------------------------------
/any_tests/jsoniter_any_object_test.go:
--------------------------------------------------------------------------------
1 | package any_tests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/json-iterator/go"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func Test_read_object_as_any(t *testing.T) {
11 | should := require.New(t)
12 | any := jsoniter.Get([]byte(`{"a":"stream","c":"d"}`))
13 | should.Equal(`{"a":"stream","c":"d"}`, any.ToString())
14 | // partial parse
15 | should.Equal("stream", any.Get("a").ToString())
16 | should.Equal("d", any.Get("c").ToString())
17 | should.Equal(2, len(any.Keys()))
18 | any = jsoniter.Get([]byte(`{"a":"stream","c":"d"}`))
19 | // full parse
20 | should.Equal(2, len(any.Keys()))
21 | should.Equal(2, any.Size())
22 | should.True(any.ToBool())
23 | should.Equal(0, any.ToInt())
24 | should.Equal(jsoniter.ObjectValue, any.ValueType())
25 | should.Nil(any.LastError())
26 | obj := struct {
27 | A string
28 | }{}
29 | any.ToVal(&obj)
30 | should.Equal("stream", obj.A)
31 | }
32 |
33 | func Test_object_lazy_any_get(t *testing.T) {
34 | should := require.New(t)
35 | any := jsoniter.Get([]byte(`{"a":{"stream":{"c":"d"}}}`))
36 | should.Equal("d", any.Get("a", "stream", "c").ToString())
37 | }
38 |
39 | func Test_object_lazy_any_get_all(t *testing.T) {
40 | should := require.New(t)
41 | any := jsoniter.Get([]byte(`{"a":[0],"stream":[1]}`))
42 | should.Contains(any.Get('*', 0).ToString(), `"a":0`)
43 | }
44 |
45 | func Test_object_lazy_any_get_invalid(t *testing.T) {
46 | should := require.New(t)
47 | any := jsoniter.Get([]byte(`{}`))
48 | should.Equal(jsoniter.InvalidValue, any.Get("a", "stream", "c").ValueType())
49 | should.Equal(jsoniter.InvalidValue, any.Get(1).ValueType())
50 | }
51 |
52 | func Test_wrap_map_and_convert_to_any(t *testing.T) {
53 | should := require.New(t)
54 | any := jsoniter.Wrap(map[string]interface{}{"a": 1})
55 | should.True(any.ToBool())
56 | should.Equal(0, any.ToInt())
57 | should.Equal(int32(0), any.ToInt32())
58 | should.Equal(int64(0), any.ToInt64())
59 | should.Equal(float32(0), any.ToFloat32())
60 | should.Equal(float64(0), any.ToFloat64())
61 | should.Equal(uint(0), any.ToUint())
62 | should.Equal(uint32(0), any.ToUint32())
63 | should.Equal(uint64(0), any.ToUint64())
64 | }
65 |
66 | func Test_wrap_object_and_convert_to_any(t *testing.T) {
67 | should := require.New(t)
68 | type TestObject struct {
69 | Field1 string
70 | field2 string
71 | }
72 | any := jsoniter.Wrap(TestObject{"hello", "world"})
73 | should.Equal("hello", any.Get("Field1").ToString())
74 | any = jsoniter.Wrap(TestObject{"hello", "world"})
75 | should.Equal(2, any.Size())
76 | should.Equal(`{"Field1":"hello"}`, any.Get('*').ToString())
77 |
78 | should.Equal(0, any.ToInt())
79 | should.Equal(int32(0), any.ToInt32())
80 | should.Equal(int64(0), any.ToInt64())
81 | should.Equal(float32(0), any.ToFloat32())
82 | should.Equal(float64(0), any.ToFloat64())
83 | should.Equal(uint(0), any.ToUint())
84 | should.Equal(uint32(0), any.ToUint32())
85 | should.Equal(uint64(0), any.ToUint64())
86 | should.True(any.ToBool())
87 | should.Equal(`{"Field1":"hello"}`, any.ToString())
88 |
89 | // cannot pass!
90 | //stream := NewStream(ConfigDefault, nil, 32)
91 | //any.WriteTo(stream)
92 | //should.Equal(`{"Field1":"hello"}`, string(stream.Buffer()))
93 | // cannot pass!
94 |
95 | }
96 |
97 | func Test_any_within_struct(t *testing.T) {
98 | should := require.New(t)
99 | type TestObject struct {
100 | Field1 jsoniter.Any
101 | Field2 jsoniter.Any
102 | }
103 | obj := TestObject{}
104 | err := jsoniter.UnmarshalFromString(`{"Field1": "hello", "Field2": [1,2,3]}`, &obj)
105 | should.Nil(err)
106 | should.Equal("hello", obj.Field1.ToString())
107 | should.Equal("[1,2,3]", obj.Field2.ToString())
108 | }
109 |
110 | func Test_object_wrapper_any_get_all(t *testing.T) {
111 | should := require.New(t)
112 | type TestObject struct {
113 | Field1 []int
114 | Field2 []int
115 | }
116 | any := jsoniter.Wrap(TestObject{[]int{1, 2}, []int{3, 4}})
117 | should.Contains(any.Get('*', 0).ToString(), `"Field2":3`)
118 | should.Contains(any.Keys(), "Field1")
119 | should.Contains(any.Keys(), "Field2")
120 | should.NotContains(any.Keys(), "Field3")
121 | }
122 |
--------------------------------------------------------------------------------
/any_tests/jsoniter_any_array_test.go:
--------------------------------------------------------------------------------
1 | package any_tests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/json-iterator/go"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func Test_read_empty_array_as_any(t *testing.T) {
11 | should := require.New(t)
12 | any := jsoniter.Get([]byte("[]"))
13 | should.Equal(jsoniter.ArrayValue, any.Get().ValueType())
14 | should.Equal(jsoniter.InvalidValue, any.Get(0.3).ValueType())
15 | should.Equal(0, any.Size())
16 | should.Equal(jsoniter.ArrayValue, any.ValueType())
17 | should.Nil(any.LastError())
18 | should.Equal(0, any.ToInt())
19 | should.Equal(int32(0), any.ToInt32())
20 | should.Equal(int64(0), any.ToInt64())
21 | should.Equal(uint(0), any.ToUint())
22 | should.Equal(uint32(0), any.ToUint32())
23 | should.Equal(uint64(0), any.ToUint64())
24 | should.Equal(float32(0), any.ToFloat32())
25 | should.Equal(float64(0), any.ToFloat64())
26 | }
27 |
28 | func Test_read_one_element_array_as_any(t *testing.T) {
29 | should := require.New(t)
30 | any := jsoniter.Get([]byte("[1]"))
31 | should.Equal(1, any.Size())
32 | }
33 |
34 | func Test_read_two_element_array_as_any(t *testing.T) {
35 | should := require.New(t)
36 | any := jsoniter.Get([]byte("[1,2]"))
37 | should.Equal(1, any.Get(0).ToInt())
38 | should.Equal(2, any.Size())
39 | should.True(any.ToBool())
40 | should.Equal(1, any.ToInt())
41 | should.Equal([]interface{}{float64(1), float64(2)}, any.GetInterface())
42 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, nil, 32)
43 | any.WriteTo(stream)
44 | should.Equal("[1,2]", string(stream.Buffer()))
45 | arr := []int{}
46 | any.ToVal(&arr)
47 | should.Equal([]int{1, 2}, arr)
48 | }
49 |
50 | func Test_wrap_array_and_convert_to_any(t *testing.T) {
51 | should := require.New(t)
52 | any := jsoniter.Wrap([]int{1, 2, 3})
53 | any2 := jsoniter.Wrap([]int{})
54 |
55 | should.Equal("[1,2,3]", any.ToString())
56 | should.True(any.ToBool())
57 | should.False(any2.ToBool())
58 |
59 | should.Equal(1, any.ToInt())
60 | should.Equal(0, any2.ToInt())
61 | should.Equal(int32(1), any.ToInt32())
62 | should.Equal(int32(0), any2.ToInt32())
63 | should.Equal(int64(1), any.ToInt64())
64 | should.Equal(int64(0), any2.ToInt64())
65 | should.Equal(uint(1), any.ToUint())
66 | should.Equal(uint(0), any2.ToUint())
67 | should.Equal(uint32(1), any.ToUint32())
68 | should.Equal(uint32(0), any2.ToUint32())
69 | should.Equal(uint64(1), any.ToUint64())
70 | should.Equal(uint64(0), any2.ToUint64())
71 | should.Equal(float32(1), any.ToFloat32())
72 | should.Equal(float32(0), any2.ToFloat32())
73 | should.Equal(float64(1), any.ToFloat64())
74 | should.Equal(float64(0), any2.ToFloat64())
75 | should.Equal(3, any.Size())
76 | should.Equal(0, any2.Size())
77 |
78 | var i interface{} = []int{1, 2, 3}
79 | should.Equal(i, any.GetInterface())
80 | }
81 |
82 | func Test_array_lazy_any_get(t *testing.T) {
83 | should := require.New(t)
84 | any := jsoniter.Get([]byte("[1,[2,3],4]"))
85 | should.Equal(3, any.Get(1, 1).ToInt())
86 | should.Equal("[1,[2,3],4]", any.ToString())
87 | }
88 |
89 | func Test_array_lazy_any_get_all(t *testing.T) {
90 | should := require.New(t)
91 | any := jsoniter.Get([]byte("[[1],[2],[3,4]]"))
92 | should.Equal("[1,2,3]", any.Get('*', 0).ToString())
93 | any = jsoniter.Get([]byte("[[[1],[2],[3,4]]]"), 0, '*', 0)
94 | should.Equal("[1,2,3]", any.ToString())
95 | }
96 |
97 | func Test_array_wrapper_any_get_all(t *testing.T) {
98 | should := require.New(t)
99 | any := jsoniter.Wrap([][]int{
100 | {1, 2},
101 | {3, 4},
102 | {5, 6},
103 | })
104 | should.Equal("[1,3,5]", any.Get('*', 0).ToString())
105 | should.Equal(jsoniter.ArrayValue, any.ValueType())
106 | should.True(any.ToBool())
107 | should.Equal(1, any.Get(0, 0).ToInt())
108 | }
109 |
110 | func Test_array_lazy_any_get_invalid(t *testing.T) {
111 | should := require.New(t)
112 | any := jsoniter.Get([]byte("[]"))
113 | should.Equal(jsoniter.InvalidValue, any.Get(1, 1).ValueType())
114 | should.NotNil(any.Get(1, 1).LastError())
115 | should.Equal(jsoniter.InvalidValue, any.Get("1").ValueType())
116 | should.NotNil(any.Get("1").LastError())
117 | }
118 |
119 | func Test_invalid_array(t *testing.T) {
120 | should := require.New(t)
121 | any := jsoniter.Get([]byte("["), 0)
122 | should.Equal(jsoniter.InvalidValue, any.ValueType())
123 | }
124 |
--------------------------------------------------------------------------------
/benchmarks/jsoniter_large_file_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/json-iterator/go"
6 | "io/ioutil"
7 | "os"
8 | "testing"
9 | )
10 |
11 | //func Test_large_file(t *testing.T) {
12 | // file, err := os.Open("/tmp/large-file.json")
13 | // if err != nil {
14 | // t.Fatal(err)
15 | // }
16 | // iter := Parse(file, 4096)
17 | // count := 0
18 | // for iter.ReadArray() {
19 | // iter.Skip()
20 | // count++
21 | // }
22 | // if count != 11351 {
23 | // t.Fatal(count)
24 | // }
25 | //}
26 |
27 | func init() {
28 | ioutil.WriteFile("large-file.json", []byte(`[{
29 | "person": {
30 | "id": "d50887ca-a6ce-4e59-b89f-14f0b5d03b03",
31 | "name": {
32 | "fullName": "Leonid Bugaev",
33 | "givenName": "Leonid",
34 | "familyName": "Bugaev"
35 | },
36 | "email": "leonsbox@gmail.com",
37 | "gender": "male",
38 | "location": "Saint Petersburg, Saint Petersburg, RU",
39 | "geo": {
40 | "city": "Saint Petersburg",
41 | "state": "Saint Petersburg",
42 | "country": "Russia",
43 | "lat": 59.9342802,
44 | "lng": 30.3350986
45 | },
46 | "bio": "Senior engineer at Granify.com",
47 | "site": "http://flickfaver.com",
48 | "avatar": "https://d1ts43dypk8bqh.cloudfront.net/v1/avatars/d50887ca-a6ce-4e59-b89f-14f0b5d03b03",
49 | "employment": {
50 | "name": "www.latera.ru",
51 | "title": "Software Engineer",
52 | "domain": "gmail.com"
53 | },
54 | "facebook": {
55 | "handle": "leonid.bugaev"
56 | },
57 | "github": {
58 | "handle": "buger",
59 | "id": 14009,
60 | "avatar": "https://avatars.githubusercontent.com/u/14009?v=3",
61 | "company": "Granify",
62 | "blog": "http://leonsbox.com",
63 | "followers": 95,
64 | "following": 10
65 | },
66 | "twitter": {
67 | "handle": "flickfaver",
68 | "id": 77004410,
69 | "bio": null,
70 | "followers": 2,
71 | "following": 1,
72 | "statuses": 5,
73 | "favorites": 0,
74 | "location": "",
75 | "site": "http://flickfaver.com",
76 | "avatar": null
77 | },
78 | "linkedin": {
79 | "handle": "in/leonidbugaev"
80 | },
81 | "googleplus": {
82 | "handle": null
83 | },
84 | "angellist": {
85 | "handle": "leonid-bugaev",
86 | "id": 61541,
87 | "bio": "Senior engineer at Granify.com",
88 | "blog": "http://buger.github.com",
89 | "site": "http://buger.github.com",
90 | "followers": 41,
91 | "avatar": "https://d1qb2nb5cznatu.cloudfront.net/users/61541-medium_jpg?1405474390"
92 | },
93 | "klout": {
94 | "handle": null,
95 | "score": null
96 | },
97 | "foursquare": {
98 | "handle": null
99 | },
100 | "aboutme": {
101 | "handle": "leonid.bugaev",
102 | "bio": null,
103 | "avatar": null
104 | },
105 | "gravatar": {
106 | "handle": "buger",
107 | "urls": [
108 | ],
109 | "avatar": "http://1.gravatar.com/avatar/f7c8edd577d13b8930d5522f28123510",
110 | "avatars": [
111 | {
112 | "url": "http://1.gravatar.com/avatar/f7c8edd577d13b8930d5522f28123510",
113 | "type": "thumbnail"
114 | }
115 | ]
116 | },
117 | "fuzzy": false
118 | },
119 | "company": "hello"
120 | }]`), 0666)
121 | }
122 |
123 | /*
124 | 200000 8886 ns/op 4336 B/op 6 allocs/op
125 | 50000 34244 ns/op 6744 B/op 14 allocs/op
126 | */
127 | func Benchmark_jsoniter_large_file(b *testing.B) {
128 | b.ReportAllocs()
129 | for n := 0; n < b.N; n++ {
130 | file, _ := os.Open("large-file.json")
131 | iter := jsoniter.Parse(jsoniter.ConfigDefault, file, 4096)
132 | count := 0
133 | iter.ReadArrayCB(func(iter *jsoniter.Iterator) bool {
134 | // Skip() is strict by default, use --tags jsoniter-sloppy to skip without validation
135 | iter.Skip()
136 | count++
137 | return true
138 | })
139 | file.Close()
140 | if iter.Error != nil {
141 | b.Error(iter.Error)
142 | }
143 | }
144 | }
145 |
146 | func Benchmark_json_large_file(b *testing.B) {
147 | b.ReportAllocs()
148 | for n := 0; n < b.N; n++ {
149 | file, _ := os.Open("large-file.json")
150 | bytes, _ := ioutil.ReadAll(file)
151 | file.Close()
152 | result := []struct{}{}
153 | err := json.Unmarshal(bytes, &result)
154 | if err != nil {
155 | b.Error(err)
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/misc_tests/jsoniter_object_test.go:
--------------------------------------------------------------------------------
1 | package misc_tests
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 |
7 | "github.com/json-iterator/go"
8 | "github.com/stretchr/testify/require"
9 | "strings"
10 | "time"
11 | )
12 |
13 | func Test_empty_object(t *testing.T) {
14 | should := require.New(t)
15 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `{}`)
16 | field := iter.ReadObject()
17 | should.Equal("", field)
18 | iter = jsoniter.ParseString(jsoniter.ConfigDefault, `{}`)
19 | iter.ReadObjectCB(func(iter *jsoniter.Iterator, field string) bool {
20 | should.FailNow("should not call")
21 | return true
22 | })
23 | }
24 |
25 | func Test_one_field(t *testing.T) {
26 | should := require.New(t)
27 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `{"a": "stream"}`)
28 | field := iter.ReadObject()
29 | should.Equal("a", field)
30 | value := iter.ReadString()
31 | should.Equal("stream", value)
32 | field = iter.ReadObject()
33 | should.Equal("", field)
34 | iter = jsoniter.ParseString(jsoniter.ConfigDefault, `{"a": "stream"}`)
35 | should.True(iter.ReadObjectCB(func(iter *jsoniter.Iterator, field string) bool {
36 | should.Equal("a", field)
37 | iter.Skip()
38 | return true
39 | }))
40 |
41 | }
42 |
43 | func Test_two_field(t *testing.T) {
44 | should := require.New(t)
45 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `{ "a": "stream" , "c": "d" }`)
46 | field := iter.ReadObject()
47 | should.Equal("a", field)
48 | value := iter.ReadString()
49 | should.Equal("stream", value)
50 | field = iter.ReadObject()
51 | should.Equal("c", field)
52 | value = iter.ReadString()
53 | should.Equal("d", value)
54 | field = iter.ReadObject()
55 | should.Equal("", field)
56 | iter = jsoniter.ParseString(jsoniter.ConfigDefault, `{"field1": "1", "field2": 2}`)
57 | for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
58 | switch field {
59 | case "field1":
60 | iter.ReadString()
61 | case "field2":
62 | iter.ReadInt64()
63 | default:
64 | iter.ReportError("bind object", "unexpected field")
65 | }
66 | }
67 | }
68 |
69 | func Test_write_object(t *testing.T) {
70 | should := require.New(t)
71 | buf := &bytes.Buffer{}
72 | stream := jsoniter.NewStream(jsoniter.Config{IndentionStep: 2}.Froze(), buf, 4096)
73 | stream.WriteObjectStart()
74 | stream.WriteObjectField("hello")
75 | stream.WriteInt(1)
76 | stream.WriteMore()
77 | stream.WriteObjectField("world")
78 | stream.WriteInt(2)
79 | stream.WriteObjectEnd()
80 | stream.Flush()
81 | should.Nil(stream.Error)
82 | should.Equal("{\n \"hello\": 1,\n \"world\": 2\n}", buf.String())
83 | }
84 |
85 | func Test_reader_and_load_more(t *testing.T) {
86 | should := require.New(t)
87 | type TestObject struct {
88 | CreatedAt time.Time
89 | }
90 | reader := strings.NewReader(`
91 | {
92 | "agency": null,
93 | "candidateId": 0,
94 | "candidate": "Blah Blah",
95 | "bookingId": 0,
96 | "shiftId": 1,
97 | "shiftTypeId": 0,
98 | "shift": "Standard",
99 | "bonus": 0,
100 | "bonusNI": 0,
101 | "days": [],
102 | "totalHours": 27,
103 | "expenses": [],
104 | "weekEndingDateSystem": "2016-10-09",
105 | "weekEndingDateClient": "2016-10-09",
106 | "submittedAt": null,
107 | "submittedById": null,
108 | "approvedAt": "2016-10-10T18:38:04Z",
109 | "approvedById": 0,
110 | "authorisedAt": "2016-10-10T18:38:04Z",
111 | "authorisedById": 0,
112 | "invoicedAt": "2016-10-10T20:00:00Z",
113 | "revokedAt": null,
114 | "revokedById": null,
115 | "revokeReason": null,
116 | "rejectedAt": null,
117 | "rejectedById": null,
118 | "rejectReasonCode": null,
119 | "rejectReason": null,
120 | "createdAt": "2016-10-03T00:00:00Z",
121 | "updatedAt": "2016-11-09T10:26:13Z",
122 | "updatedById": null,
123 | "overrides": [],
124 | "bookingApproverId": null,
125 | "bookingApprover": null,
126 | "status": "approved"
127 | }
128 | `)
129 | decoder := jsoniter.ConfigCompatibleWithStandardLibrary.NewDecoder(reader)
130 | obj := TestObject{}
131 | should.Nil(decoder.Decode(&obj))
132 | }
133 |
134 | func Test_unmarshal_into_existing_value(t *testing.T) {
135 | should := require.New(t)
136 | type TestObject struct {
137 | Field1 int
138 | Field2 interface{}
139 | }
140 | var obj TestObject
141 | m := map[string]interface{}{}
142 | obj.Field2 = &m
143 | cfg := jsoniter.Config{UseNumber: true}.Froze()
144 | err := cfg.Unmarshal([]byte(`{"Field1":1,"Field2":{"k":"v"}}`), &obj)
145 | should.NoError(err)
146 | should.Equal(map[string]interface{}{
147 | "k": "v",
148 | }, m)
149 | }
150 |
--------------------------------------------------------------------------------
/value_tests/float_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "fmt"
7 | "github.com/json-iterator/go"
8 | "github.com/stretchr/testify/require"
9 | "strconv"
10 | "testing"
11 | )
12 |
13 | func Test_read_float(t *testing.T) {
14 | inputs := []string{
15 | `1.1`, `1000`, `9223372036854775807`, `12.3`, `-12.3`, `720368.54775807`, `720368.547758075`,
16 | `1e1`, `1e+1`, `1e-1`, `1E1`, `1E+1`, `1E-1`, `-1e1`, `-1e+1`, `-1e-1`,
17 | }
18 | for _, input := range inputs {
19 | // non-streaming
20 | t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
21 | should := require.New(t)
22 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, input+",")
23 | expected, err := strconv.ParseFloat(input, 32)
24 | should.Nil(err)
25 | should.Equal(float32(expected), iter.ReadFloat32())
26 | })
27 | t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
28 | should := require.New(t)
29 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, input+",")
30 | expected, err := strconv.ParseFloat(input, 64)
31 | should.Nil(err)
32 | should.Equal(expected, iter.ReadFloat64())
33 | })
34 | // streaming
35 | t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
36 | should := require.New(t)
37 | iter := jsoniter.Parse(jsoniter.ConfigDefault, bytes.NewBufferString(input+","), 2)
38 | expected, err := strconv.ParseFloat(input, 32)
39 | should.Nil(err)
40 | should.Equal(float32(expected), iter.ReadFloat32())
41 | })
42 | t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
43 | should := require.New(t)
44 | iter := jsoniter.Parse(jsoniter.ConfigDefault, bytes.NewBufferString(input+","), 2)
45 | val := float64(0)
46 | err := json.Unmarshal([]byte(input), &val)
47 | should.Nil(err)
48 | should.Equal(val, iter.ReadFloat64())
49 | })
50 | }
51 | }
52 |
53 | func Test_write_float32(t *testing.T) {
54 | vals := []float32{0, 1, -1, 99, 0xff, 0xfff, 0xffff, 0xfffff, 0xffffff, 0x4ffffff, 0xfffffff,
55 | -0x4ffffff, -0xfffffff, 1.2345, 1.23456, 1.234567, 1.001}
56 | for _, val := range vals {
57 | t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
58 | should := require.New(t)
59 | buf := &bytes.Buffer{}
60 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, buf, 4096)
61 | stream.WriteFloat32Lossy(val)
62 | stream.Flush()
63 | should.Nil(stream.Error)
64 | output, err := json.Marshal(val)
65 | should.Nil(err)
66 | should.Equal(string(output), buf.String())
67 | })
68 | t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
69 | should := require.New(t)
70 | buf := &bytes.Buffer{}
71 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, buf, 4096)
72 | stream.WriteVal(val)
73 | stream.Flush()
74 | should.Nil(stream.Error)
75 | output, err := json.Marshal(val)
76 | should.Nil(err)
77 | should.Equal(string(output), buf.String())
78 | })
79 | }
80 | should := require.New(t)
81 | buf := &bytes.Buffer{}
82 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, buf, 10)
83 | stream.WriteRaw("abcdefg")
84 | stream.WriteFloat32Lossy(1.123456)
85 | stream.Flush()
86 | should.Nil(stream.Error)
87 | should.Equal("abcdefg1.123456", buf.String())
88 |
89 | stream = jsoniter.NewStream(jsoniter.ConfigDefault, nil, 0)
90 | stream.WriteFloat32(float32(0.0000001))
91 | should.Equal("1e-07", string(stream.Buffer()))
92 | }
93 |
94 | func Test_write_float64(t *testing.T) {
95 | vals := []float64{0, 1, -1, 99, 0xff, 0xfff, 0xffff, 0xfffff, 0xffffff, 0x4ffffff, 0xfffffff,
96 | -0x4ffffff, -0xfffffff, 1.2345, 1.23456, 1.234567, 1.001}
97 | for _, val := range vals {
98 | t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
99 | should := require.New(t)
100 | buf := &bytes.Buffer{}
101 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, buf, 4096)
102 | stream.WriteFloat64Lossy(val)
103 | stream.Flush()
104 | should.Nil(stream.Error)
105 | should.Equal(strconv.FormatFloat(val, 'f', -1, 64), buf.String())
106 | })
107 | t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
108 | should := require.New(t)
109 | buf := &bytes.Buffer{}
110 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, buf, 4096)
111 | stream.WriteVal(val)
112 | stream.Flush()
113 | should.Nil(stream.Error)
114 | should.Equal(strconv.FormatFloat(val, 'f', -1, 64), buf.String())
115 | })
116 | }
117 | should := require.New(t)
118 | buf := &bytes.Buffer{}
119 | stream := jsoniter.NewStream(jsoniter.ConfigDefault, buf, 10)
120 | stream.WriteRaw("abcdefg")
121 | stream.WriteFloat64Lossy(1.123456)
122 | stream.Flush()
123 | should.Nil(stream.Error)
124 | should.Equal("abcdefg1.123456", buf.String())
125 |
126 | stream = jsoniter.NewStream(jsoniter.ConfigDefault, nil, 0)
127 | stream.WriteFloat64(float64(0.0000001))
128 | should.Equal("1e-07", string(stream.Buffer()))
129 | }
130 |
--------------------------------------------------------------------------------
/type_tests/struct_embedded_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | func init() {
4 | testCases = append(testCases,
5 | (*struct {
6 | EmbeddedFloat64
7 | })(nil),
8 | (*struct {
9 | EmbeddedInt32
10 | })(nil),
11 | (*struct {
12 | F1 float64
13 | StringMarshaler
14 | F2 int32
15 | })(nil),
16 | (*struct {
17 | EmbeddedMapStringString
18 | })(nil),
19 | (*struct {
20 | *EmbeddedFloat64
21 | })(nil),
22 | (*struct {
23 | *EmbeddedInt32
24 | })(nil),
25 | (*struct {
26 | *EmbeddedMapStringString
27 | })(nil),
28 | (*struct {
29 | *EmbeddedSliceString
30 | })(nil),
31 | (*struct {
32 | *EmbeddedString
33 | })(nil),
34 | (*struct {
35 | *EmbeddedStruct
36 | })(nil),
37 | (*struct {
38 | EmbeddedSliceString
39 | })(nil),
40 | (*struct {
41 | EmbeddedString
42 | })(nil),
43 | (*struct {
44 | EmbeddedString `json:"othername"`
45 | })(nil),
46 | (*struct {
47 | EmbeddedStruct
48 | })(nil),
49 | (*struct {
50 | F1 float64
51 | StringTextMarshaler
52 | F2 int32
53 | })(nil),
54 | (*OverlapDifferentLevels)(nil),
55 | (*IgnoreDeeperLevel)(nil),
56 | (*SameLevel1BothTagged)(nil),
57 | (*SameLevel1NoTags)(nil),
58 | (*SameLevel1Tagged)(nil),
59 | (*SameLevel2BothTagged)(nil),
60 | (*SameLevel2NoTags)(nil),
61 | (*SameLevel2Tagged)(nil),
62 | (*EmbeddedPtr)(nil),
63 | )
64 | }
65 |
66 | type EmbeddedFloat64 float64
67 | type EmbeddedInt32 int32
68 | type EmbeddedMapStringString map[string]string
69 | type EmbeddedSliceString []string
70 | type EmbeddedString string
71 | type EmbeddedStruct struct {
72 | String string
73 | Int int32
74 | Float float64
75 | Struct struct {
76 | X string
77 | }
78 | Slice []string
79 | Map map[string]string
80 | }
81 |
82 | type OverlapDifferentLevelsE1 struct {
83 | F1 int32
84 | }
85 |
86 | type OverlapDifferentLevelsE2 struct {
87 | F2 string
88 | }
89 |
90 | type OverlapDifferentLevels struct {
91 | OverlapDifferentLevelsE1
92 | OverlapDifferentLevelsE2
93 | F1 string
94 | }
95 |
96 | type IgnoreDeeperLevelDoubleEmbedded struct {
97 | F1 int32 `json:"F1"`
98 | }
99 |
100 | type IgnoreDeeperLevelE1 struct {
101 | IgnoreDeeperLevelDoubleEmbedded
102 | F1 int32
103 | }
104 |
105 | type IgnoreDeeperLevelE2 struct {
106 | F1 int32 `json:"F1"`
107 | IgnoreDeeperLevelDoubleEmbedded
108 | }
109 |
110 | type IgnoreDeeperLevel struct {
111 | IgnoreDeeperLevelE1
112 | IgnoreDeeperLevelE2
113 | }
114 |
115 | type SameLevel1BothTaggedE1 struct {
116 | F1 int32 `json:"F1"`
117 | }
118 |
119 | type SameLevel1BothTaggedE2 struct {
120 | F1 int32 `json:"F1"`
121 | }
122 |
123 | type SameLevel1BothTagged struct {
124 | SameLevel1BothTaggedE1
125 | SameLevel1BothTaggedE2
126 | }
127 |
128 | type SameLevel1NoTagsE1 struct {
129 | F1 int32
130 | }
131 |
132 | type SameLevel1NoTagsE2 struct {
133 | F1 int32
134 | }
135 |
136 | type SameLevel1NoTags struct {
137 | SameLevel1NoTagsE1
138 | SameLevel1NoTagsE2
139 | }
140 |
141 | type SameLevel1TaggedE1 struct {
142 | F1 int32
143 | }
144 |
145 | type SameLevel1TaggedE2 struct {
146 | F1 int32 `json:"F1"`
147 | }
148 |
149 | type SameLevel1Tagged struct {
150 | SameLevel1TaggedE1
151 | SameLevel1TaggedE2
152 | }
153 |
154 | type SameLevel2BothTaggedDE1 struct {
155 | F1 int32 `json:"F1"`
156 | }
157 |
158 | type SameLevel2BothTaggedE1 struct {
159 | SameLevel2BothTaggedDE1
160 | }
161 |
162 | // DoubleEmbedded2 TEST ONLY
163 | type SameLevel2BothTaggedDE2 struct {
164 | F1 int32 `json:"F1"`
165 | }
166 |
167 | // Embedded2 TEST ONLY
168 | type SameLevel2BothTaggedE2 struct {
169 | SameLevel2BothTaggedDE2
170 | }
171 |
172 | type SameLevel2BothTagged struct {
173 | SameLevel2BothTaggedE1
174 | SameLevel2BothTaggedE2
175 | }
176 |
177 | type SameLevel2NoTagsDE1 struct {
178 | F1 int32
179 | }
180 |
181 | type SameLevel2NoTagsE1 struct {
182 | SameLevel2NoTagsDE1
183 | }
184 |
185 | type SameLevel2NoTagsDE2 struct {
186 | F1 int32
187 | }
188 |
189 | type SameLevel2NoTagsE2 struct {
190 | SameLevel2NoTagsDE2
191 | }
192 |
193 | type SameLevel2NoTags struct {
194 | SameLevel2NoTagsE1
195 | SameLevel2NoTagsE2
196 | }
197 |
198 | // DoubleEmbedded1 TEST ONLY
199 | type SameLevel2TaggedDE1 struct {
200 | F1 int32
201 | }
202 |
203 | // Embedded1 TEST ONLY
204 | type SameLevel2TaggedE1 struct {
205 | SameLevel2TaggedDE1
206 | }
207 |
208 | // DoubleEmbedded2 TEST ONLY
209 | type SameLevel2TaggedDE2 struct {
210 | F1 int32 `json:"F1"`
211 | }
212 |
213 | // Embedded2 TEST ONLY
214 | type SameLevel2TaggedE2 struct {
215 | SameLevel2TaggedDE2
216 | }
217 |
218 | type SameLevel2Tagged struct {
219 | SameLevel2TaggedE1
220 | SameLevel2TaggedE2
221 | }
222 |
223 | type EmbeddedPtrO1 struct {
224 | O1F string
225 | }
226 |
227 | type EmbeddedPtrOption struct {
228 | O1 *EmbeddedPtrO1
229 | }
230 |
231 | type EmbeddedPtr struct {
232 | EmbeddedPtrOption `json:","`
233 | }
234 |
--------------------------------------------------------------------------------
/misc_tests/jsoniter_interface_test.go:
--------------------------------------------------------------------------------
1 | package misc_tests
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/json-iterator/go"
6 | "github.com/stretchr/testify/require"
7 | "io"
8 | "testing"
9 | )
10 |
11 | func Test_nil_non_empty_interface(t *testing.T) {
12 | type TestObject struct {
13 | Field []io.Closer
14 | }
15 | should := require.New(t)
16 | obj := TestObject{}
17 | b := []byte(`{"Field":["AAA"]}`)
18 | should.NotNil(json.Unmarshal(b, &obj))
19 | should.NotNil(jsoniter.Unmarshal(b, &obj))
20 | }
21 |
22 | func Test_nil_out_null_interface(t *testing.T) {
23 | type TestData struct {
24 | Field interface{} `json:"field"`
25 | }
26 | should := require.New(t)
27 |
28 | var boolVar bool
29 | obj := TestData{
30 | Field: &boolVar,
31 | }
32 |
33 | data1 := []byte(`{"field": true}`)
34 |
35 | err := jsoniter.Unmarshal(data1, &obj)
36 | should.NoError(err)
37 | should.Equal(true, *(obj.Field.(*bool)))
38 |
39 | data2 := []byte(`{"field": null}`)
40 |
41 | err = jsoniter.Unmarshal(data2, &obj)
42 | should.NoError(err)
43 | should.Nil(obj.Field)
44 |
45 | // Checking stdlib behavior matches.
46 | obj2 := TestData{
47 | Field: &boolVar,
48 | }
49 |
50 | err = json.Unmarshal(data1, &obj2)
51 | should.NoError(err)
52 | should.Equal(true, *(obj2.Field.(*bool)))
53 |
54 | err = json.Unmarshal(data2, &obj2)
55 | should.NoError(err)
56 | should.Equal(nil, obj2.Field)
57 | }
58 |
59 | func Test_overwrite_interface_ptr_value_with_nil(t *testing.T) {
60 | type Wrapper struct {
61 | Payload interface{} `json:"payload,omitempty"`
62 | }
63 | type Payload struct {
64 | Value int `json:"val,omitempty"`
65 | }
66 |
67 | should := require.New(t)
68 |
69 | payload := &Payload{}
70 | wrapper := &Wrapper{
71 | Payload: &payload,
72 | }
73 |
74 | err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
75 | should.NoError(err)
76 | should.Equal(&payload, wrapper.Payload)
77 | should.Equal(42, (*(wrapper.Payload.(**Payload))).Value)
78 |
79 | err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
80 | should.NoError(err)
81 | should.Equal(&payload, wrapper.Payload)
82 | should.Equal((*Payload)(nil), payload)
83 |
84 | payload = &Payload{}
85 | wrapper = &Wrapper{
86 | Payload: &payload,
87 | }
88 |
89 | err = jsoniter.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
90 | should.Equal(nil, err)
91 | should.Equal(&payload, wrapper.Payload)
92 | should.Equal(42, (*(wrapper.Payload.(**Payload))).Value)
93 |
94 | err = jsoniter.Unmarshal([]byte(`{"payload": null}`), &wrapper)
95 | should.NoError(err)
96 | should.Equal(&payload, wrapper.Payload)
97 | should.Equal((*Payload)(nil), payload)
98 | }
99 |
100 | func Test_overwrite_interface_value_with_nil(t *testing.T) {
101 | type Wrapper struct {
102 | Payload interface{} `json:"payload,omitempty"`
103 | }
104 | type Payload struct {
105 | Value int `json:"val,omitempty"`
106 | }
107 |
108 | should := require.New(t)
109 |
110 | payload := &Payload{}
111 | wrapper := &Wrapper{
112 | Payload: payload,
113 | }
114 |
115 | err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
116 | should.NoError(err)
117 | should.Equal(42, wrapper.Payload.(*Payload).Value)
118 |
119 | err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
120 | should.NoError(err)
121 | should.Equal(nil, wrapper.Payload)
122 | should.Equal(42, payload.Value)
123 |
124 | payload = &Payload{}
125 | wrapper = &Wrapper{
126 | Payload: payload,
127 | }
128 |
129 | err = jsoniter.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
130 | should.Equal(nil, err)
131 | should.Equal(42, wrapper.Payload.(*Payload).Value)
132 |
133 | err = jsoniter.Unmarshal([]byte(`{"payload": null}`), &wrapper)
134 | should.Equal(nil, err)
135 | should.Equal(nil, wrapper.Payload)
136 | should.Equal(42, payload.Value)
137 | }
138 |
139 | func Test_unmarshal_into_nil(t *testing.T) {
140 | type Payload struct {
141 | Value int `json:"val,omitempty"`
142 | }
143 | type Wrapper struct {
144 | Payload interface{} `json:"payload,omitempty"`
145 | }
146 |
147 | should := require.New(t)
148 |
149 | var payload *Payload
150 | wrapper := &Wrapper{
151 | Payload: payload,
152 | }
153 |
154 | err := json.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
155 | should.NoError(err)
156 | should.NotNil(wrapper.Payload)
157 | should.Nil(payload)
158 |
159 | err = json.Unmarshal([]byte(`{"payload": null}`), &wrapper)
160 | should.NoError(err)
161 | should.Nil(wrapper.Payload)
162 | should.Nil(payload)
163 |
164 | payload = nil
165 | wrapper = &Wrapper{
166 | Payload: payload,
167 | }
168 |
169 | err = jsoniter.Unmarshal([]byte(`{"payload": {"val": 42}}`), &wrapper)
170 | should.NoError(err)
171 | should.NotNil(wrapper.Payload)
172 | should.Nil(payload)
173 |
174 | err = jsoniter.Unmarshal([]byte(`{"payload": null}`), &wrapper)
175 | should.NoError(err)
176 | should.Nil(wrapper.Payload)
177 | should.Nil(payload)
178 | }
179 |
--------------------------------------------------------------------------------
/extension_tests/decoder_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "bytes"
5 | "github.com/json-iterator/go"
6 | "github.com/stretchr/testify/require"
7 | "strconv"
8 | "testing"
9 | "time"
10 | "unsafe"
11 | )
12 |
13 | func Test_customize_type_decoder(t *testing.T) {
14 | t.Skip()
15 | jsoniter.RegisterTypeDecoderFunc("time.Time", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
16 | t, err := time.ParseInLocation("2006-01-02 15:04:05", iter.ReadString(), time.UTC)
17 | if err != nil {
18 | iter.Error = err
19 | return
20 | }
21 | *((*time.Time)(ptr)) = t
22 | })
23 | //defer jsoniter.ConfigDefault.(*frozenConfig).cleanDecoders()
24 | val := time.Time{}
25 | err := jsoniter.Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val)
26 | if err != nil {
27 | t.Fatal(err)
28 | }
29 | year, month, day := val.Date()
30 | if year != 2016 || month != 12 || day != 5 {
31 | t.Fatal(val)
32 | }
33 | }
34 |
35 | func Test_customize_byte_array_encoder(t *testing.T) {
36 | t.Skip()
37 | //jsoniter.ConfigDefault.(*frozenConfig).cleanEncoders()
38 | should := require.New(t)
39 | jsoniter.RegisterTypeEncoderFunc("[]uint8", func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
40 | t := *((*[]byte)(ptr))
41 | stream.WriteString(string(t))
42 | }, nil)
43 | //defer jsoniter.ConfigDefault.(*frozenConfig).cleanEncoders()
44 | val := []byte("abc")
45 | str, err := jsoniter.MarshalToString(val)
46 | should.Nil(err)
47 | should.Equal(`"abc"`, str)
48 | }
49 |
50 | func Test_customize_field_decoder(t *testing.T) {
51 | type Tom struct {
52 | field1 string
53 | }
54 | jsoniter.RegisterFieldDecoderFunc("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
55 | *((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
56 | })
57 | //defer jsoniter.ConfigDefault.(*frozenConfig).cleanDecoders()
58 | tom := Tom{}
59 | err := jsoniter.Unmarshal([]byte(`{"field1": 100}`), &tom)
60 | if err != nil {
61 | t.Fatal(err)
62 | }
63 | }
64 |
65 | func Test_recursive_empty_interface_customization(t *testing.T) {
66 | t.Skip()
67 | var obj interface{}
68 | jsoniter.RegisterTypeDecoderFunc("interface {}", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
69 | switch iter.WhatIsNext() {
70 | case jsoniter.NumberValue:
71 | *(*interface{})(ptr) = iter.ReadInt64()
72 | default:
73 | *(*interface{})(ptr) = iter.Read()
74 | }
75 | })
76 | should := require.New(t)
77 | jsoniter.Unmarshal([]byte("[100]"), &obj)
78 | should.Equal([]interface{}{int64(100)}, obj)
79 | }
80 |
81 | type MyInterface interface {
82 | Hello() string
83 | }
84 |
85 | type MyString string
86 |
87 | func (ms MyString) Hello() string {
88 | return string(ms)
89 | }
90 |
91 | func Test_read_custom_interface(t *testing.T) {
92 | t.Skip()
93 | should := require.New(t)
94 | var val MyInterface
95 | jsoniter.RegisterTypeDecoderFunc("jsoniter.MyInterface", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
96 | *((*MyInterface)(ptr)) = MyString(iter.ReadString())
97 | })
98 | err := jsoniter.UnmarshalFromString(`"hello"`, &val)
99 | should.Nil(err)
100 | should.Equal("hello", val.Hello())
101 | }
102 |
103 | const flow1 = `
104 | {"A":"hello"}
105 | {"A":"hello"}
106 | {"A":"hello"}
107 | {"A":"hello"}
108 | {"A":"hello"}`
109 |
110 | const flow2 = `
111 | {"A":"hello"}
112 | {"A":"hello"}
113 | {"A":"hello"}
114 | {"A":"hello"}
115 | {"A":"hello"}
116 | `
117 |
118 | type (
119 | Type1 struct {
120 | A string
121 | }
122 |
123 | Type2 struct {
124 | A string
125 | }
126 | )
127 |
128 | func (t *Type2) UnmarshalJSON(data []byte) error {
129 | return nil
130 | }
131 |
132 | func (t *Type2) MarshalJSON() ([]byte, error) {
133 | return nil, nil
134 | }
135 |
136 | func TestType1NoFinalLF(t *testing.T) {
137 | reader := bytes.NewReader([]byte(flow1))
138 | dec := jsoniter.NewDecoder(reader)
139 |
140 | i := 0
141 | for dec.More() {
142 | data := &Type1{}
143 | if err := dec.Decode(data); err != nil {
144 | t.Errorf("at %v got %v", i, err)
145 | }
146 | i++
147 | }
148 | }
149 |
150 | func TestType1FinalLF(t *testing.T) {
151 | reader := bytes.NewReader([]byte(flow2))
152 | dec := jsoniter.NewDecoder(reader)
153 |
154 | i := 0
155 | for dec.More() {
156 | data := &Type1{}
157 | if err := dec.Decode(data); err != nil {
158 | t.Errorf("at %v got %v", i, err)
159 | }
160 | i++
161 | }
162 | }
163 |
164 | func TestType2NoFinalLF(t *testing.T) {
165 | reader := bytes.NewReader([]byte(flow1))
166 | dec := jsoniter.NewDecoder(reader)
167 |
168 | i := 0
169 | for dec.More() {
170 | data := &Type2{}
171 | if err := dec.Decode(data); err != nil {
172 | t.Errorf("at %v got %v", i, err)
173 | }
174 | i++
175 | }
176 | }
177 |
178 | func TestType2FinalLF(t *testing.T) {
179 | reader := bytes.NewReader([]byte(flow2))
180 | dec := jsoniter.NewDecoder(reader)
181 |
182 | i := 0
183 | for dec.More() {
184 | data := &Type2{}
185 | if err := dec.Decode(data); err != nil {
186 | t.Errorf("at %v got %v", i, err)
187 | }
188 | i++
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/skip_tests/jsoniter_skip_test.go:
--------------------------------------------------------------------------------
1 | package skip_tests
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "testing"
7 |
8 | "github.com/json-iterator/go"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func Test_skip_number_in_array(t *testing.T) {
13 | should := require.New(t)
14 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[-0.12, "stream"]`)
15 | iter.ReadArray()
16 | iter.Skip()
17 | iter.ReadArray()
18 | should.Nil(iter.Error)
19 | should.Equal("stream", iter.ReadString())
20 | }
21 |
22 | func Test_skip_string_in_array(t *testing.T) {
23 | should := require.New(t)
24 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `["hello", "stream"]`)
25 | iter.ReadArray()
26 | iter.Skip()
27 | iter.ReadArray()
28 | should.Nil(iter.Error)
29 | should.Equal("stream", iter.ReadString())
30 | }
31 |
32 | func Test_skip_null(t *testing.T) {
33 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[null , "stream"]`)
34 | iter.ReadArray()
35 | iter.Skip()
36 | iter.ReadArray()
37 | if iter.ReadString() != "stream" {
38 | t.FailNow()
39 | }
40 | }
41 |
42 | func Test_skip_true(t *testing.T) {
43 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[true , "stream"]`)
44 | iter.ReadArray()
45 | iter.Skip()
46 | iter.ReadArray()
47 | if iter.ReadString() != "stream" {
48 | t.FailNow()
49 | }
50 | }
51 |
52 | func Test_skip_false(t *testing.T) {
53 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[false , "stream"]`)
54 | iter.ReadArray()
55 | iter.Skip()
56 | iter.ReadArray()
57 | if iter.ReadString() != "stream" {
58 | t.FailNow()
59 | }
60 | }
61 |
62 | func Test_skip_array(t *testing.T) {
63 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[[1, [2, [3], 4]], "stream"]`)
64 | iter.ReadArray()
65 | iter.Skip()
66 | iter.ReadArray()
67 | if iter.ReadString() != "stream" {
68 | t.FailNow()
69 | }
70 | }
71 |
72 | func Test_skip_empty_array(t *testing.T) {
73 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[ [ ], "stream"]`)
74 | iter.ReadArray()
75 | iter.Skip()
76 | iter.ReadArray()
77 | if iter.ReadString() != "stream" {
78 | t.FailNow()
79 | }
80 | }
81 |
82 | func Test_skip_nested(t *testing.T) {
83 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`)
84 | iter.ReadArray()
85 | iter.Skip()
86 | iter.ReadArray()
87 | if iter.ReadString() != "stream" {
88 | t.FailNow()
89 | }
90 | }
91 |
92 | func Test_skip_and_return_bytes(t *testing.T) {
93 | should := require.New(t)
94 | iter := jsoniter.ParseString(jsoniter.ConfigDefault, `[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`)
95 | iter.ReadArray()
96 | skipped := iter.SkipAndReturnBytes()
97 | should.Equal(`{"a" : [{"stream": "c"}], "d": 102 }`, string(skipped))
98 | }
99 |
100 | func Test_skip_and_return_bytes_with_reader(t *testing.T) {
101 | should := require.New(t)
102 | iter := jsoniter.Parse(jsoniter.ConfigDefault, bytes.NewBufferString(`[ {"a" : [{"stream": "c"}], "d": 102 }, "stream"]`), 4)
103 | iter.ReadArray()
104 | skipped := iter.SkipAndReturnBytes()
105 | should.Equal(`{"a" : [{"stream": "c"}], "d": 102 }`, string(skipped))
106 | }
107 |
108 | func Test_skip_empty(t *testing.T) {
109 | should := require.New(t)
110 | should.NotNil(jsoniter.Get([]byte("")).LastError())
111 | }
112 |
113 | type TestResp struct {
114 | Code uint64
115 | }
116 |
117 | func Benchmark_jsoniter_skip(b *testing.B) {
118 | input := []byte(`
119 | {
120 | "_shards":{
121 | "total" : 5,
122 | "successful" : 5,
123 | "failed" : 0
124 | },
125 | "hits":{
126 | "total" : 1,
127 | "hits" : [
128 | {
129 | "_index" : "twitter",
130 | "_type" : "tweet",
131 | "_id" : "1",
132 | "_source" : {
133 | "user" : "kimchy",
134 | "postDate" : "2009-11-15T14:12:12",
135 | "message" : "trying out Elasticsearch"
136 | }
137 | }
138 | ]
139 | },
140 | "code": 200
141 | }`)
142 | for n := 0; n < b.N; n++ {
143 | result := TestResp{}
144 | iter := jsoniter.ParseBytes(jsoniter.ConfigDefault, input)
145 | for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
146 | switch field {
147 | case "code":
148 | result.Code = iter.ReadUint64()
149 | default:
150 | iter.Skip()
151 | }
152 | }
153 | }
154 | }
155 |
156 | func Benchmark_json_skip(b *testing.B) {
157 | input := []byte(`
158 | {
159 | "_shards":{
160 | "total" : 5,
161 | "successful" : 5,
162 | "failed" : 0
163 | },
164 | "hits":{
165 | "total" : 1,
166 | "hits" : [
167 | {
168 | "_index" : "twitter",
169 | "_type" : "tweet",
170 | "_id" : "1",
171 | "_source" : {
172 | "user" : "kimchy",
173 | "postDate" : "2009-11-15T14:12:12",
174 | "message" : "trying out Elasticsearch"
175 | }
176 | }
177 | ]
178 | },
179 | "code": 200
180 | }`)
181 | for n := 0; n < b.N; n++ {
182 | result := TestResp{}
183 | json.Unmarshal(input, &result)
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/api_tests/config_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "encoding/json"
5 | "testing"
6 |
7 | "github.com/json-iterator/go"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func Test_use_number_for_unmarshal(t *testing.T) {
12 | should := require.New(t)
13 | api := jsoniter.Config{UseNumber: true}.Froze()
14 | var obj interface{}
15 | should.Nil(api.UnmarshalFromString("123", &obj))
16 | should.Equal(json.Number("123"), obj)
17 | }
18 |
19 | func Test_customize_float_marshal(t *testing.T) {
20 | should := require.New(t)
21 | json := jsoniter.Config{MarshalFloatWith6Digits: true}.Froze()
22 | str, err := json.MarshalToString(float32(1.23456789))
23 | should.Nil(err)
24 | should.Equal("1.234568", str)
25 | }
26 |
27 | func Test_customize_tag_key(t *testing.T) {
28 |
29 | type TestObject struct {
30 | Field string `orm:"field"`
31 | }
32 |
33 | should := require.New(t)
34 | json := jsoniter.Config{TagKey: "orm"}.Froze()
35 | str, err := json.MarshalToString(TestObject{"hello"})
36 | should.Nil(err)
37 | should.Equal(`{"field":"hello"}`, str)
38 | }
39 |
40 | func Test_read_large_number_as_interface(t *testing.T) {
41 | should := require.New(t)
42 | var val interface{}
43 | err := jsoniter.Config{UseNumber: true}.Froze().UnmarshalFromString(`123456789123456789123456789`, &val)
44 | should.Nil(err)
45 | output, err := jsoniter.MarshalToString(val)
46 | should.Nil(err)
47 | should.Equal(`123456789123456789123456789`, output)
48 | }
49 |
50 | type caseSensitiveStruct struct {
51 | A string `json:"a"`
52 | B string `json:"b,omitempty"`
53 | C *C `json:"C,omitempty"`
54 | }
55 |
56 | type C struct {
57 | D int64 `json:"D,omitempty"`
58 | E *E `json:"e,omitempty"`
59 | }
60 |
61 | type E struct {
62 | F string `json:"F,omitempty"`
63 | }
64 |
65 | func Test_CaseSensitive(t *testing.T) {
66 | should := require.New(t)
67 |
68 | testCases := []struct {
69 | input string
70 | expectedOutput string
71 | caseSensitive bool
72 | }{
73 | {
74 | input: `{"A":"foo","B":"bar"}`,
75 | expectedOutput: `{"a":"foo","b":"bar"}`,
76 | caseSensitive: false,
77 | },
78 | {
79 | input: `{"a":"foo","b":"bar"}`,
80 | expectedOutput: `{"a":"foo","b":"bar"}`,
81 | caseSensitive: true,
82 | },
83 | {
84 | input: `{"a":"foo","b":"bar","C":{"D":10}}`,
85 | expectedOutput: `{"a":"foo","b":"bar","C":{"D":10}}`,
86 | caseSensitive: true,
87 | },
88 | {
89 | input: `{"a":"foo","B":"bar","c":{"d":10}}`,
90 | expectedOutput: `{"a":"foo"}`,
91 | caseSensitive: true,
92 | },
93 | {
94 | input: `{"a":"foo","C":{"d":10}}`,
95 | expectedOutput: `{"a":"foo","C":{}}`,
96 | caseSensitive: true,
97 | },
98 | {
99 | input: `{"a":"foo","C":{"D":10,"e":{"f":"baz"}}}`,
100 | expectedOutput: `{"a":"foo","C":{"D":10,"e":{}}}`,
101 | caseSensitive: true,
102 | },
103 | {
104 | input: `{"a":"foo","C":{"D":10,"e":{"F":"baz"}}}`,
105 | expectedOutput: `{"a":"foo","C":{"D":10,"e":{"F":"baz"}}}`,
106 | caseSensitive: true,
107 | },
108 | {
109 | input: `{"A":"foo","c":{"d":10,"E":{"f":"baz"}}}`,
110 | expectedOutput: `{"a":"foo","C":{"D":10,"e":{"F":"baz"}}}`,
111 | caseSensitive: false,
112 | },
113 | }
114 |
115 | for _, tc := range testCases {
116 | val := caseSensitiveStruct{}
117 | err := jsoniter.Config{CaseSensitive: tc.caseSensitive}.Froze().UnmarshalFromString(tc.input, &val)
118 | should.Nil(err)
119 |
120 | output, err := jsoniter.MarshalToString(val)
121 | should.Nil(err)
122 | should.Equal(tc.expectedOutput, output)
123 | }
124 | }
125 |
126 | type structWithElevenFields struct {
127 | A string `json:"A,omitempty"`
128 | B string `json:"B,omitempty"`
129 | C string `json:"C,omitempty"`
130 | D string `json:"d,omitempty"`
131 | E string `json:"e,omitempty"`
132 | F string `json:"f,omitempty"`
133 | G string `json:"g,omitempty"`
134 | H string `json:"h,omitempty"`
135 | I string `json:"i,omitempty"`
136 | J string `json:"j,omitempty"`
137 | K string `json:"k,omitempty"`
138 | }
139 |
140 | func Test_CaseSensitive_MoreThanTenFields(t *testing.T) {
141 | should := require.New(t)
142 |
143 | testCases := []struct {
144 | input string
145 | expectedOutput string
146 | caseSensitive bool
147 | }{
148 | {
149 | input: `{"A":"1","B":"2","C":"3","d":"4","e":"5","f":"6","g":"7","h":"8","i":"9","j":"10","k":"11"}`,
150 | expectedOutput: `{"A":"1","B":"2","C":"3","d":"4","e":"5","f":"6","g":"7","h":"8","i":"9","j":"10","k":"11"}`,
151 | caseSensitive: true,
152 | },
153 | {
154 | input: `{"a":"1","b":"2","c":"3","D":"4","E":"5","F":"6"}`,
155 | expectedOutput: `{"A":"1","B":"2","C":"3","d":"4","e":"5","f":"6"}`,
156 | caseSensitive: false,
157 | },
158 | {
159 | input: `{"A":"1","b":"2","d":"4","E":"5"}`,
160 | expectedOutput: `{"A":"1","d":"4"}`,
161 | caseSensitive: true,
162 | },
163 | }
164 |
165 | for _, tc := range testCases {
166 | val := structWithElevenFields{}
167 | err := jsoniter.Config{CaseSensitive: tc.caseSensitive}.Froze().UnmarshalFromString(tc.input, &val)
168 | should.Nil(err)
169 |
170 | output, err := jsoniter.MarshalToString(val)
171 | should.Nil(err)
172 | should.Equal(tc.expectedOutput, output)
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/stream_int.go:
--------------------------------------------------------------------------------
1 | package jsoniter
2 |
3 | var digits []uint32
4 |
5 | func init() {
6 | digits = make([]uint32, 1000)
7 | for i := uint32(0); i < 1000; i++ {
8 | digits[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i%10 + '0'
9 | if i < 10 {
10 | digits[i] += 2 << 24
11 | } else if i < 100 {
12 | digits[i] += 1 << 24
13 | }
14 | }
15 | }
16 |
17 | func writeFirstBuf(space []byte, v uint32) []byte {
18 | start := v >> 24
19 | if start == 0 {
20 | space = append(space, byte(v>>16), byte(v>>8))
21 | } else if start == 1 {
22 | space = append(space, byte(v>>8))
23 | }
24 | space = append(space, byte(v))
25 | return space
26 | }
27 |
28 | func writeBuf(buf []byte, v uint32) []byte {
29 | return append(buf, byte(v>>16), byte(v>>8), byte(v))
30 | }
31 |
32 | // WriteUint8 write uint8 to stream
33 | func (stream *Stream) WriteUint8(val uint8) {
34 | stream.buf = writeFirstBuf(stream.buf, digits[val])
35 | }
36 |
37 | // WriteInt8 write int8 to stream
38 | func (stream *Stream) WriteInt8(nval int8) {
39 | var val uint8
40 | if nval < 0 {
41 | val = uint8(-nval)
42 | stream.buf = append(stream.buf, '-')
43 | } else {
44 | val = uint8(nval)
45 | }
46 | stream.buf = writeFirstBuf(stream.buf, digits[val])
47 | }
48 |
49 | // WriteUint16 write uint16 to stream
50 | func (stream *Stream) WriteUint16(val uint16) {
51 | q1 := val / 1000
52 | if q1 == 0 {
53 | stream.buf = writeFirstBuf(stream.buf, digits[val])
54 | return
55 | }
56 | r1 := val - q1*1000
57 | stream.buf = writeFirstBuf(stream.buf, digits[q1])
58 | stream.buf = writeBuf(stream.buf, digits[r1])
59 | return
60 | }
61 |
62 | // WriteInt16 write int16 to stream
63 | func (stream *Stream) WriteInt16(nval int16) {
64 | var val uint16
65 | if nval < 0 {
66 | val = uint16(-nval)
67 | stream.buf = append(stream.buf, '-')
68 | } else {
69 | val = uint16(nval)
70 | }
71 | stream.WriteUint16(val)
72 | }
73 |
74 | // WriteUint32 write uint32 to stream
75 | func (stream *Stream) WriteUint32(val uint32) {
76 | q1 := val / 1000
77 | if q1 == 0 {
78 | stream.buf = writeFirstBuf(stream.buf, digits[val])
79 | return
80 | }
81 | r1 := val - q1*1000
82 | q2 := q1 / 1000
83 | if q2 == 0 {
84 | stream.buf = writeFirstBuf(stream.buf, digits[q1])
85 | stream.buf = writeBuf(stream.buf, digits[r1])
86 | return
87 | }
88 | r2 := q1 - q2*1000
89 | q3 := q2 / 1000
90 | if q3 == 0 {
91 | stream.buf = writeFirstBuf(stream.buf, digits[q2])
92 | } else {
93 | r3 := q2 - q3*1000
94 | stream.buf = append(stream.buf, byte(q3+'0'))
95 | stream.buf = writeBuf(stream.buf, digits[r3])
96 | }
97 | stream.buf = writeBuf(stream.buf, digits[r2])
98 | stream.buf = writeBuf(stream.buf, digits[r1])
99 | }
100 |
101 | // WriteInt32 write int32 to stream
102 | func (stream *Stream) WriteInt32(nval int32) {
103 | var val uint32
104 | if nval < 0 {
105 | val = uint32(-nval)
106 | stream.buf = append(stream.buf, '-')
107 | } else {
108 | val = uint32(nval)
109 | }
110 | stream.WriteUint32(val)
111 | }
112 |
113 | // WriteUint64 write uint64 to stream
114 | func (stream *Stream) WriteUint64(val uint64) {
115 | q1 := val / 1000
116 | if q1 == 0 {
117 | stream.buf = writeFirstBuf(stream.buf, digits[val])
118 | return
119 | }
120 | r1 := val - q1*1000
121 | q2 := q1 / 1000
122 | if q2 == 0 {
123 | stream.buf = writeFirstBuf(stream.buf, digits[q1])
124 | stream.buf = writeBuf(stream.buf, digits[r1])
125 | return
126 | }
127 | r2 := q1 - q2*1000
128 | q3 := q2 / 1000
129 | if q3 == 0 {
130 | stream.buf = writeFirstBuf(stream.buf, digits[q2])
131 | stream.buf = writeBuf(stream.buf, digits[r2])
132 | stream.buf = writeBuf(stream.buf, digits[r1])
133 | return
134 | }
135 | r3 := q2 - q3*1000
136 | q4 := q3 / 1000
137 | if q4 == 0 {
138 | stream.buf = writeFirstBuf(stream.buf, digits[q3])
139 | stream.buf = writeBuf(stream.buf, digits[r3])
140 | stream.buf = writeBuf(stream.buf, digits[r2])
141 | stream.buf = writeBuf(stream.buf, digits[r1])
142 | return
143 | }
144 | r4 := q3 - q4*1000
145 | q5 := q4 / 1000
146 | if q5 == 0 {
147 | stream.buf = writeFirstBuf(stream.buf, digits[q4])
148 | stream.buf = writeBuf(stream.buf, digits[r4])
149 | stream.buf = writeBuf(stream.buf, digits[r3])
150 | stream.buf = writeBuf(stream.buf, digits[r2])
151 | stream.buf = writeBuf(stream.buf, digits[r1])
152 | return
153 | }
154 | r5 := q4 - q5*1000
155 | q6 := q5 / 1000
156 | if q6 == 0 {
157 | stream.buf = writeFirstBuf(stream.buf, digits[q5])
158 | } else {
159 | stream.buf = writeFirstBuf(stream.buf, digits[q6])
160 | r6 := q5 - q6*1000
161 | stream.buf = writeBuf(stream.buf, digits[r6])
162 | }
163 | stream.buf = writeBuf(stream.buf, digits[r5])
164 | stream.buf = writeBuf(stream.buf, digits[r4])
165 | stream.buf = writeBuf(stream.buf, digits[r3])
166 | stream.buf = writeBuf(stream.buf, digits[r2])
167 | stream.buf = writeBuf(stream.buf, digits[r1])
168 | }
169 |
170 | // WriteInt64 write int64 to stream
171 | func (stream *Stream) WriteInt64(nval int64) {
172 | var val uint64
173 | if nval < 0 {
174 | val = uint64(-nval)
175 | stream.buf = append(stream.buf, '-')
176 | } else {
177 | val = uint64(nval)
178 | }
179 | stream.WriteUint64(val)
180 | }
181 |
182 | // WriteInt write int to stream
183 | func (stream *Stream) WriteInt(val int) {
184 | stream.WriteInt64(int64(val))
185 | }
186 |
187 | // WriteUint write uint to stream
188 | func (stream *Stream) WriteUint(val uint) {
189 | stream.WriteUint64(uint64(val))
190 | }
191 |
--------------------------------------------------------------------------------
/value_tests/struct_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "time"
7 | )
8 |
9 | func init() {
10 | var pString = func(val string) *string {
11 | return &val
12 | }
13 | epoch := time.Unix(0, 0)
14 | unmarshalCases = append(unmarshalCases, unmarshalCase{
15 | ptr: (*struct {
16 | Field interface{}
17 | })(nil),
18 | input: `{"Field": "hello"}`,
19 | }, unmarshalCase{
20 | ptr: (*struct {
21 | Field interface{}
22 | })(nil),
23 | input: `{"Field": "hello"} `,
24 | }, unmarshalCase{
25 | ptr: (*struct {
26 | Field int `json:"field"`
27 | })(nil),
28 | input: `{"field": null}`,
29 | }, unmarshalCase{
30 | ptr: (*struct {
31 | ID int `json:"id"`
32 | Payload map[string]interface{} `json:"payload"`
33 | buf *bytes.Buffer
34 | })(nil),
35 | input: ` {"id":1, "payload":{"account":"123","password":"456"}}`,
36 | }, unmarshalCase{
37 | ptr: (*struct {
38 | Field1 string
39 | })(nil),
40 | input: `{"Field\"1":"hello"}`,
41 | }, unmarshalCase{
42 | ptr: (*struct {
43 | Field1 string
44 | })(nil),
45 | input: `{"\u0046ield1":"hello"}`,
46 | }, unmarshalCase{
47 | ptr: (*struct {
48 | Field1 *string
49 | Field2 *string
50 | })(nil),
51 | input: `{"field1": null, "field2": "world"}`,
52 | }, unmarshalCase{
53 | ptr: (*struct {
54 | Field1 string
55 | Field2 json.RawMessage
56 | })(nil),
57 | input: `{"field1": "hello", "field2":[1,2,3]}`,
58 | }, unmarshalCase{
59 | ptr: (*struct {
60 | a int
61 | b <-chan int
62 | C int
63 | d *time.Timer
64 | })(nil),
65 | input: `{"a": 444, "b":"bad", "C":256, "d":{"not":"a timer"}}`,
66 | }, unmarshalCase{
67 | ptr: (*struct {
68 | A string
69 | B string
70 | C string
71 | D string
72 | E string
73 | F string
74 | G string
75 | H string
76 | I string
77 | J string
78 | K string
79 | })(nil),
80 | input: `{"a":"1","b":"2","c":"3","d":"4","e":"5","f":"6","g":"7","h":"8","i":"9","j":"10","k":"11"}`,
81 | }, unmarshalCase{
82 | ptr: (*struct {
83 | T float64 `json:"T"`
84 | })(nil),
85 | input: `{"t":10.0}`,
86 | }, unmarshalCase{
87 | ptr: (*struct {
88 | T float64 `json:"T"`
89 | })(nil),
90 | input: `{"T":10.0}`,
91 | }, unmarshalCase{
92 | ptr: (*struct {
93 | T float64 `json:"t"`
94 | })(nil),
95 | input: `{"T":10.0}`,
96 | }, unmarshalCase{
97 | ptr: (*struct {
98 | KeyString string `json:"key_string"`
99 | Type string `json:"type"`
100 | Asks [][2]float64 `json:"asks"`
101 | })(nil),
102 | input: `{"key_string": "KEYSTRING","type": "TYPE","asks": [[1e+66,1]]}`,
103 | })
104 | marshalCases = append(marshalCases,
105 | struct {
106 | Field map[string]interface{}
107 | }{
108 | map[string]interface{}{"hello": "world"},
109 | },
110 | struct {
111 | Field map[string]interface{}
112 | Field2 string
113 | }{
114 | map[string]interface{}{"hello": "world"}, "",
115 | },
116 | struct {
117 | Field interface{}
118 | }{
119 | 1024,
120 | },
121 | struct {
122 | Field MyInterface
123 | }{
124 | MyString("hello"),
125 | },
126 | struct {
127 | F *float64
128 | }{},
129 | struct {
130 | *time.Time
131 | }{&epoch},
132 | struct {
133 | *StructVarious
134 | }{&StructVarious{}},
135 | struct {
136 | *StructVarious
137 | Field int
138 | }{nil, 10},
139 | struct {
140 | Field1 int
141 | Field2 [1]*float64
142 | }{},
143 | struct {
144 | Field interface{} `json:"field,omitempty"`
145 | }{},
146 | struct {
147 | Field MyInterface `json:"field,omitempty"`
148 | }{},
149 | struct {
150 | Field MyInterface `json:"field,omitempty"`
151 | }{MyString("hello")},
152 | struct {
153 | Field json.Marshaler `json:"field"`
154 | }{},
155 | struct {
156 | Field MyInterface `json:"field"`
157 | }{},
158 | struct {
159 | Field MyInterface `json:"field"`
160 | }{MyString("hello")},
161 | struct {
162 | Field1 string `json:"field-1,omitempty"`
163 | Field2 func() `json:"-"`
164 | }{},
165 | structRecursive{},
166 | struct {
167 | *CacheItem
168 |
169 | // Omit bad keys
170 | OmitMaxAge omit `json:"cacheAge,omitempty"`
171 |
172 | // Add nice keys
173 | MaxAge int `json:"max_age"`
174 | }{
175 | CacheItem: &CacheItem{
176 | Key: "value",
177 | MaxAge: 100,
178 | },
179 | MaxAge: 20,
180 | },
181 | structOrder{},
182 | struct {
183 | Field1 *string
184 | Field2 *string
185 | }{Field2: pString("world")},
186 | struct {
187 | a int
188 | b <-chan int
189 | C int
190 | d *time.Timer
191 | }{
192 | a: 42,
193 | b: make(<-chan int, 10),
194 | C: 21,
195 | d: time.NewTimer(10 * time.Second),
196 | },
197 | )
198 | }
199 |
200 | type StructVarious struct {
201 | Field0 string
202 | Field1 []string
203 | Field2 map[string]interface{}
204 | }
205 |
206 | type structRecursive struct {
207 | Field1 string
208 | Me *structRecursive
209 | }
210 |
211 | type omit *struct{}
212 | type CacheItem struct {
213 | Key string `json:"key"`
214 | MaxAge int `json:"cacheAge"`
215 | }
216 |
217 | type orderA struct {
218 | Field2 string
219 | }
220 |
221 | type orderC struct {
222 | Field5 string
223 | }
224 |
225 | type orderB struct {
226 | Field4 string
227 | orderC
228 | Field6 string
229 | }
230 |
231 | type structOrder struct {
232 | Field1 string
233 | orderA
234 | Field3 string
235 | orderB
236 | Field7 string
237 | }
238 |
--------------------------------------------------------------------------------