├── 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 | [![Sourcegraph](https://sourcegraph.com/github.com/json-iterator/go/-/badge.svg)](https://sourcegraph.com/github.com/json-iterator/go?badge) 2 | [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/json-iterator/go) 3 | [![Build Status](https://travis-ci.org/json-iterator/go.svg?branch=master)](https://travis-ci.org/json-iterator/go) 4 | [![codecov](https://codecov.io/gh/json-iterator/go/branch/master/graph/badge.svg)](https://codecov.io/gh/json-iterator/go) 5 | [![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go) 6 | [![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/json-iterator/go/master/LICENSE) 7 | [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](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 | ![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png) 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 [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](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 | --------------------------------------------------------------------------------