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

115 Commits

Author SHA1 Message Date
45bbb40a9f #34 implement NewEncoder 2017-06-02 18:46:44 +08:00
e36f926072 fix random go test failure 2017-06-02 17:34:40 +08:00
59e71bacc8 #36 handle anonymous 2017-06-02 16:52:20 +08:00
5cb0d35610 eof is not error 2017-06-02 16:06:33 +08:00
69b742e73a #34 support More() and Buffered() 2017-06-02 16:00:12 +08:00
a7f992f0e1 #35 fix json.Number matches string 2017-06-02 15:43:58 +08:00
4cc44e7380 #34 add decoder adapter 2017-06-02 15:38:20 +08:00
5310d4aa9a syntax highlight 2017-06-02 11:20:54 +08:00
2051e3b8ae simplify readme 2017-06-02 11:20:24 +08:00
fe9fa8900e #31 support json.RawMessage 2017-06-02 10:50:23 +08:00
ad3a7fde32 #30 support json.Number 2017-06-02 10:21:43 +08:00
377b892102 support big float and int 2017-05-31 12:40:50 +08:00
707ed3b091 support non empty interface 2017-05-27 00:36:21 +08:00
a7a7c7879a allocate less buffer for writing to []byte 2017-05-26 07:52:54 +08:00
f20f74519d RegisterTypeEncoder and RegisterTypeDecoder should have higher priority 2017-05-24 23:39:34 +08:00
7d2ae80c37 #27 support json.Unmarshaler 2017-05-24 16:04:11 +08:00
f6f159e108 #27 support json.Marshaler 2017-05-24 14:34:00 +08:00
e5a1e704ad #25 make fielding binding case insensitive 2017-05-24 13:16:09 +08:00
7d5f90261e #28 extension should support specifying encoder 2017-05-24 10:58:56 +08:00
6126a6d3ca #23 hide unexported fields by default 2017-05-24 09:39:11 +08:00
5fbe4e387d #21 #22 marshal float precisely by default 2017-05-24 09:08:15 +08:00
fc44cb2d91 #26 do not enforce pointer as optional 2017-05-23 18:46:11 +08:00
7e046e6aa7 simplify read string, and support null 2017-05-23 18:32:39 +08:00
5488fde97f fix one field struct interface{} optimization compatibility 2017-05-23 17:44:50 +08:00
53f8d370b5 fix wrap any 2017-05-19 19:44:27 +08:00
3f1fcaff87 demonstrate how to customize float encoding 2017-05-11 08:00:50 +08:00
1df353727b customize []byte encoder 2017-05-06 20:52:36 +08:00
b893a0359d trim end space 2017-05-05 17:44:09 +08:00
a92111261c fix struct with one pointer field 2017-05-05 17:27:41 +08:00
91b9e828b7 support recursive type 2017-05-05 16:51:05 +08:00
6bd835aeb1 test type encoder 2017-05-05 08:22:19 +08:00
90888390bc fix readFloat64SlowPath not advancing the cursor 2017-05-02 10:15:21 +08:00
ccb972f58c merge 2017-04-28 09:10:06 +08:00
8711c74c85 support Any as field type 2017-04-28 09:09:24 +08:00
abcf2759ed Merge pull request #14 from eruca/master
fix the omitempty bug
2017-04-18 10:23:05 +10:00
e5476f70e7 #16 fix slice of map 2017-04-16 14:05:08 +08:00
b986d86f26 add test 2017-03-11 18:19:39 +08:00
9a138f8b6a fix bug of another comma added
previous code will add comma if the field is empty when is not first, like 
```
{"account":"1120","name":"nick",,"department":"fsaf","role":1,"privilege":32,,"created_at":1489226500}
```
2017-03-11 18:17:34 +08:00
d1aa59e34e #12 implement omitempty 2017-03-08 07:38:25 -08:00
ceb8c8a733 create map if nil 2017-03-07 18:36:58 -08:00
62028f1ede Merge pull request #11 from Kisesy/patch-1
fix #10
2017-02-26 09:42:45 -06:00
696f962eda fix https://github.com/json-iterator/go/issues/10
Update feature_iter_string.go

Update feature_iter_string.go
2017-02-25 13:30:55 +08:00
9d1feb5431 fix tests 2017-02-12 22:49:45 +08:00
9670a03165 fix issue on 32bit platform 2017-02-09 13:50:06 +08:00
17cbb770f0 fix issue on 32bit platform 2017-02-09 13:35:58 +08:00
da7ed7809b use hash for field dispatching 2017-02-08 13:46:28 +08:00
14f696c6f5 Merge branch 'master' of https://github.com/json-iterator/go 2017-02-07 09:24:46 +08:00
2922666717 fix read int 2017-02-07 09:24:36 +08:00
06078a3afb Merge pull request #8 from smartczy/patch-1
Update README.md
2017-02-04 07:25:34 -06:00
232e0df179 Update README.md
modify the useage of function Read().
2017-02-04 14:34:00 +08:00
6880076b44 fix map[string]interface{} in struct 2017-02-03 18:44:54 +08:00
1e91dbbf58 map any support get all 2017-01-31 23:16:40 +08:00
bf459b9a49 object lazy any support get all 2017-01-31 20:26:35 +08:00
498ab96d90 array any support get all 2017-01-31 20:10:16 +08:00
edb96991a8 add all integer types 2017-01-29 16:55:32 +08:00
10a1fb8762 wrap map 2017-01-28 23:11:29 +08:00
95823d0bf1 wrap object 2017-01-28 22:45:03 +08:00
64c9bd0b1c wrap array 2017-01-28 21:11:36 +08:00
fa16f3c75c wrap string 2017-01-26 16:41:49 +08:00
cf4113fc22 wrap float 2017-01-26 16:33:16 +08:00
85edb698c8 Any Get will never return nil 2017-01-26 16:24:01 +08:00
9abc2f52b0 add Any GetInterface 2017-01-26 15:44:10 +08:00
97472ecd96 expose Parse from Any 2017-01-26 15:40:38 +08:00
4d7e181f9f implement Any WriteTo 2017-01-26 14:56:31 +08:00
9b587c0f22 suport encode interface 2017-01-26 00:25:17 +08:00
ce1a1f1e98 test reading into custom interface 2017-01-25 23:25:25 +08:00
f1c4dbde29 support map of interface{} 2017-01-25 22:43:57 +08:00
94ae645ab9 array/object to bool/int 2017-01-24 23:13:58 +08:00
ee54218b0a lazy array get 2017-01-24 22:56:18 +08:00
fa165c684f array lazy iterator 2017-01-24 22:47:56 +08:00
8656482625 array lazy fill and full fill 2017-01-24 22:36:16 +08:00
2d647f04ca implement lazy object three iteration way 2017-01-24 00:23:07 +08:00
38d613acf2 bool any 2017-01-23 08:45:57 +08:00
b9fe012eea string any 2017-01-23 08:33:43 +08:00
d49ea1bc49 float any 2017-01-22 23:38:55 +08:00
ba410b045b int lazy any 2017-01-22 23:29:48 +08:00
9df37bbd68 remove any 2017-01-22 19:36:19 +08:00
9c2b1d24b3 optimize true/false/null: 2017-01-22 19:28:14 +08:00
1163c348f6 fix write string 2017-01-22 00:04:08 +08:00
102cd8748e fix write int 2017-01-21 23:22:38 +08:00
8345c731dd rename 2017-01-21 17:11:38 +08:00
1d29fa38ef read to interface{} 2017-01-21 16:09:38 +08:00
928bc4ce72 ReadArrayCB 2017-01-20 13:54:51 +08:00
80c86e63b1 read object cb 2017-01-20 12:56:49 +08:00
d14b025931 make ReadObject return safe string 2017-01-20 12:40:52 +08:00
a73e48e8bf optimize read nil/true/false 2017-01-18 23:33:40 +08:00
6efc6c44ac test read string and read string as slice 2017-01-16 23:57:09 +08:00
e7ff7339b2 optimize read string 2017-01-16 23:43:20 +08:00
b9e3f01bfd fix int min max 2017-01-16 09:01:44 +08:00
54a69f1da2 fix read int ranges 2017-01-15 23:17:17 +08:00
399ee3faaa optimize read int32 2017-01-15 22:50:31 +08:00
c3c57d61b5 optimize read float64 2017-01-15 18:08:49 +08:00
5b2a731963 implement readFloat32 fast path 2017-01-15 17:30:02 +08:00
a57c8c6202 test array of interface 2017-01-09 21:00:01 +08:00
1f0a0e9a2d encode optional 2017-01-09 20:51:09 +08:00
90fc0b822f array encoder 2017-01-09 19:48:57 +08:00
552afb3625 struct encoder 2017-01-09 19:19:48 +08:00
5b0609f901 support int/string encode 2017-01-09 17:47:21 +08:00
bdbf8dcd42 write float64 2017-01-07 23:32:54 +08:00
ba3c30799b write float 32 2017-01-07 23:06:48 +08:00
e034897e69 write array 2017-01-07 22:16:20 +08:00
21549b9fd8 write object 2017-01-07 22:08:45 +08:00
5e50b3e11c write int 2017-01-07 21:25:23 +08:00
6f57d41461 add stream 2017-01-07 12:28:16 +08:00
5af8cc4b09 split files 2017-01-07 07:49:50 +08:00
c78023531e add more tests 2017-01-06 20:27:48 +08:00
101dfdbb2a fix 4 fields object decoding 2017-01-06 20:17:47 +08:00
c70437c6b9 Merge pull request #5 from hanbang-wang/master
Formated, doced. Also fixed few minor bugs.
2017-01-05 21:41:45 +08:00
d63a00f0bf Formated, doced. Also fixed few minor bugs. 2017-01-05 21:23:08 +08:00
97849e019f fix read any; reuse existing obj for optional 2017-01-05 13:53:38 +08:00
247a23a637 remove skipWhitespaces 2017-01-05 09:16:41 +08:00
e7ec3988a6 fix tag field name not used bug 2016-12-19 12:12:15 +08:00
c7d0dd5b66 Merge branch 'master' of https://github.com/json-iterator/go 2016-12-17 17:38:33 +08:00
7d5f2aed7b update extension 2016-12-17 17:38:13 +08:00
e38192e48f #3 fix nextToken 2016-12-16 00:25:35 +08:00
62 changed files with 11310 additions and 2948 deletions

View File

@ -1,61 +1,39 @@
[![rcard](https://goreportcard.com/badge/github.com/json-iterator/go)](https://goreportcard.com/report/github.com/json-iterator/go)
jsoniter (json-iterator) is fast and flexible JSON parser available in [Java](https://github.com/json-iterator/java) and [Go](https://github.com/json-iterator/go) jsoniter (json-iterator) is fast and flexible JSON parser available in [Java](https://github.com/json-iterator/java) and [Go](https://github.com/json-iterator/go)
# Why jsoniter? # Usage
* Jsoniter is the fastest JSON parser. It could be up to 10x faster than normal parser, data binding included. Shameless self [benchmark](http://jsoniter.com/benchmark.html) 100% compatibility with standard lib
* Extremely flexible api. You can mix and match three different styles: bind-api, any-api or iterator-api. Checkout your [api choices](http://jsoniter.com/api.html)
* Unique iterator api can iterate through JSON directly, zero memory allocation! See how [iterator](http://jsoniter.com/api.html#iterator-api) works
# Show off Replace
Here is a quick show off, for more complete report you can checkout the full [benchmark](http://jsoniter.com/benchmark.html) with [in-depth optimization](http://jsoniter.com/benchmark.html#optimization-used) to back the numbers up ```go
import "encoding/json"
json.Marshal(&data)
```
![go-medium](http://jsoniter.com/benchmarks/go-medium.png) with
# Bind-API is the best
Bind-api should always be the first choice. Given this JSON document `[0,1,2,3]`
Parse with Go bind-api
```go ```go
import "github.com/json-iterator/go" import "github.com/json-iterator/go"
iter := jsoniter.ParseString(`[0,1,2,3]`) jsoniter.Marshal(&data)
val := []int{}
iter.Read(&val)
fmt.Println(val[3])
``` ```
# Iterator-API for quick extraction Replace
When you do not need to get all the data back, just extract some. ```go
import "encoding/json"
json.Unmarshal(input, &data)
```
Parse with Go iterator-api with
```go ```go
import "github.com/json-iterator/go" import "github.com/json-iterator/go"
iter := ParseString(`[0, [1, 2], [3, 4], 5]`) jsoniter.Unmarshal(input, &data)
count := 0
for iter.ReadArray() {
iter.skip()
count++
}
fmt.Println(count) // 4
``` ```
# Any-API for maximum flexibility
Parse with Go any-api
```go
import "github.com/json-iterator/go"
iter := jsoniter.ParseString(`[{"field1":"11","field2":"12"},{"field1":"21","field2":"22"}]`)
val := iter.ReadAny()
fmt.Println(val.ToInt(1, "field2")) // 22
```
Notice you can extract from nested data structure, and convert any type to the type to you want.
# How to get # How to get
``` ```

427
any.go
View File

@ -1,427 +0,0 @@
package jsoniter
import (
"fmt"
"reflect"
"strconv"
)
type Any struct {
val interface{}
Error error
LastAccessed interface{}
}
func MakeAny(val interface{}) *Any {
return &Any{val, nil, nil}
}
func (any *Any) Get(keys ...interface{}) interface{} {
ret, err := getPath(any.val, keys...)
any.LastAccessed = ret
if err != nil {
any.Error = err
return "";
}
return ret
}
func (any *Any) GetValueType(keys ...interface{}) ValueType {
ret, err := getPath(any.val, keys...)
any.LastAccessed = ret
if err != nil {
any.Error = err
return Invalid;
}
switch reflect.TypeOf(ret).Kind() {
case reflect.Uint8:
return Number;
case reflect.Int8:
return Number;
case reflect.Uint16:
return Number;
case reflect.Int16:
return Number;
case reflect.Uint32:
return Number;
case reflect.Int32:
return Number;
case reflect.Uint64:
return Number;
case reflect.Int64:
return Number;
case reflect.Int:
return Number;
case reflect.Uint:
return Number;
case reflect.Float32:
return Number;
case reflect.Float64:
return Number;
case reflect.String:
return String;
case reflect.Bool:
return Bool;
case reflect.Array:
return Array;
case reflect.Struct:
return Object;
default:
return Invalid
}
}
func (any *Any) ToString(keys ...interface{}) string {
ret, err := getPath(any.val, keys...)
any.LastAccessed = ret
if err != nil {
any.Error = err
return "";
}
switch ret := ret.(type) {
case uint8:
return strconv.FormatInt(int64(ret), 10);
case int8:
return strconv.FormatInt(int64(ret), 10);
case uint16:
return strconv.FormatInt(int64(ret), 10);
case int16:
return strconv.FormatInt(int64(ret), 10);
case uint32:
return strconv.FormatInt(int64(ret), 10);
case int32:
return strconv.FormatInt(int64(ret), 10);
case uint64:
return strconv.FormatUint(uint64(ret), 10);
case int64:
return strconv.FormatInt(int64(ret), 10);
case int:
return strconv.FormatInt(int64(ret), 10);
case uint:
return strconv.FormatInt(int64(ret), 10);
case float32:
return strconv.FormatFloat(float64(ret), 'E', -1, 32);
case float64:
return strconv.FormatFloat(ret, 'E', -1, 64);
case string:
return ret
default:
return fmt.Sprintf("%v", ret)
}
}
func (any *Any) ToUint8(keys ...interface{}) uint8 {
ret, err := getPathAsInt64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return uint8(ret)
}
func (any *Any) ToInt8(keys ...interface{}) int8 {
ret, err := getPathAsInt64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return int8(ret)
}
func (any *Any) ToUint16(keys ...interface{}) uint16 {
ret, err := getPathAsInt64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return uint16(ret)
}
func (any *Any) ToInt16(keys ...interface{}) int16 {
ret, err := getPathAsInt64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return int16(ret)
}
func (any *Any) ToUint32(keys ...interface{}) uint32 {
ret, err := getPathAsInt64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return uint32(ret)
}
func (any *Any) ToInt32(keys ...interface{}) int32 {
ret, err := getPathAsInt64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return int32(ret)
}
func (any *Any) ToUint64(keys ...interface{}) uint64 {
ret, err := getPathAsUint64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return uint64(ret)
}
func (any *Any) ToInt64(keys ...interface{}) int64 {
ret, err := getPathAsInt64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return int64(ret)
}
func (any *Any) ToInt(keys ...interface{}) int {
ret, err := getPathAsInt64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return int(ret)
}
func (any *Any) ToUint(keys ...interface{}) uint {
ret, err := getPathAsInt64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return uint(ret)
}
func (any *Any) ToFloat32(keys ...interface{}) float32 {
ret, err := getPathAsFloat64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return float32(ret)
}
func (any *Any) ToFloat64(keys ...interface{}) float64 {
ret, err := getPathAsFloat64(any, keys...)
if err != nil {
any.Error = err
return 0;
}
return ret
}
func (any *Any) ToBool(keys ...interface{}) bool {
ret, err := getPath(any.val, keys...)
any.LastAccessed = ret
if err != nil {
any.Error = err
return false;
}
typedRet, ok := ret.(bool)
if !ok {
any.Error = fmt.Errorf("%v is not bool", ret)
return false;
}
return typedRet
}
func (any *Any) IsNull(keys ...interface{}) bool {
ret, err := getPath(any.val, keys...)
any.LastAccessed = ret
if err != nil {
any.Error = err
return false;
}
return reflect.ValueOf(ret).IsNil()
}
func getPathAsInt64(any *Any, keys ...interface{}) (int64, error) {
ret, err := getPath(any.val, keys...)
any.LastAccessed = ret
if err != nil {
any.Error = err
return 0, err
}
switch ret := ret.(type) {
case uint8:
return int64(ret), nil;
case int8:
return int64(ret), nil;
case uint16:
return int64(ret), nil;
case int16:
return int64(ret), nil;
case uint32:
return int64(ret), nil;
case int32:
return int64(ret), nil;
case uint64:
return int64(ret), nil;
case int64:
return int64(ret), nil;
case int:
return int64(ret), nil;
case uint:
return int64(ret), nil;
case float32:
return int64(ret), nil;
case float64:
return int64(ret), nil;
case string:
intVal, err := strconv.ParseInt(ret, 10, 64)
if err != nil {
return 0, err
}
return intVal, nil;
default:
return 0, fmt.Errorf("%v is not number", ret)
}
}
func getPathAsUint64(any *Any, keys ...interface{}) (uint64, error) {
ret, err := getPath(any.val, keys...)
any.LastAccessed = ret
if err != nil {
any.Error = err
return 0, err
}
switch ret := ret.(type) {
case uint8:
return uint64(ret), nil;
case int8:
return uint64(ret), nil;
case uint16:
return uint64(ret), nil;
case int16:
return uint64(ret), nil;
case uint32:
return uint64(ret), nil;
case int32:
return uint64(ret), nil;
case uint64:
return uint64(ret), nil;
case int64:
return uint64(ret), nil;
case int:
return uint64(ret), nil;
case uint:
return uint64(ret), nil;
case float32:
return uint64(ret), nil;
case float64:
return uint64(ret), nil;
case string:
intVal, err := strconv.ParseUint(ret, 10, 64)
if err != nil {
return 0, err
}
return intVal, nil;
default:
return 0, fmt.Errorf("%v is not number", ret)
}
}
func getPathAsFloat64(any *Any, keys ...interface{}) (float64, error) {
ret, err := getPath(any.val, keys...)
any.LastAccessed = ret
if err != nil {
any.Error = err
return 0, err
}
switch ret := ret.(type) {
case uint8:
return float64(ret), nil;
case int8:
return float64(ret), nil;
case uint16:
return float64(ret), nil;
case int16:
return float64(ret), nil;
case uint32:
return float64(ret), nil;
case int32:
return float64(ret), nil;
case uint64:
return float64(ret), nil;
case int64:
return float64(ret), nil;
case int:
return float64(ret), nil;
case uint:
return float64(ret), nil;
case float32:
return float64(ret), nil;
case float64:
return float64(ret), nil;
case string:
floatVal, err := strconv.ParseFloat(ret, 64)
if err != nil {
return 0, err
}
return floatVal, nil;
default:
return 0, fmt.Errorf("%v is not number", ret)
}
}
func getPath(val interface{}, keys ...interface{}) (interface{}, error) {
if (len(keys) == 0) {
return val, nil;
}
switch key := keys[0].(type) {
case string:
nextVal, err := getFromMap(val, key)
if err != nil {
return nil, err
}
nextKeys := make([]interface{}, len(keys) - 1)
copy(nextKeys, keys[1:])
return getPath(nextVal, nextKeys...)
case int:
nextVal, err := getFromArray(val, key)
if err != nil {
return nil, err
}
nextKeys := make([]interface{}, len(keys) - 1)
copy(nextKeys, keys[1:])
return getPath(nextVal, nextKeys...)
default:
return nil, fmt.Errorf("%v is not string or int", keys[0]);
}
return getPath(val, keys);
}
func getFromMap(val interface{}, key string) (interface{}, error) {
mapVal, ok := val.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("%v is not map[string]interface{}", val)
}
ret, found := mapVal[key]
if !found {
return nil, fmt.Errorf("%v not found in %v", key, mapVal)
}
return ret, nil
}
func getFromArray(val interface{}, key int) (interface{}, error) {
arrayVal, ok := val.([]interface{})
if !ok {
return nil, fmt.Errorf("%v is not []interface{}", val)
}
if key >= len(arrayVal) {
return nil, fmt.Errorf("%v exceed %v", key, arrayVal)
}
if key < 0 {
return nil, fmt.Errorf("%v exceed %v", key, arrayVal)
}
return arrayVal[key], nil
}

View File

@ -1,72 +0,0 @@
package jsoniter
import (
"testing"
"fmt"
)
func Test_get_from_map(t *testing.T) {
any := Any{val: map[string]interface{}{
"hello": "world",
}}
if any.ToString("hello") != "world" {
t.FailNow()
}
}
func Test_get_from_array(t *testing.T) {
any := Any{val: []interface{}{
"hello", "world",
}}
if any.ToString(1) != "world" {
t.FailNow()
}
}
func Test_get_int(t *testing.T) {
any := Any{val: []interface{}{
1, 2, 3,
}}
if any.ToInt(1) != 2 {
t.FailNow()
}
}
func Test_is_null(t *testing.T) {
any := Any{val: []interface{}{
1, 2, 3,
}}
if any.IsNull() != false {
t.FailNow()
}
}
func Test_get_bool(t *testing.T) {
any := Any{val: []interface{}{
true, true, false,
}}
if any.ToBool(1) != true {
t.FailNow()
}
}
func Test_nested_read(t *testing.T) {
any := Any{val: []interface{}{
true, map[string]interface{}{
"hello": "world",
}, false,
}}
if any.ToString(1, "hello") != "world" {
fmt.Println(any.Error)
t.FailNow()
}
}
func Test_int_to_string(t *testing.T) {
any := Any{val: []interface{}{
true, 5, false,
}}
if any.ToString(1) != "5" {
t.FailNow()
}
}

1017
assert/assertions.go Normal file

File diff suppressed because it is too large Load Diff

147
feature_adapter.go Normal file
View File

@ -0,0 +1,147 @@
package jsoniter
import (
"io"
"bytes"
)
// Unmarshal adapts to json/encoding APIs
func Unmarshal(data []byte, v interface{}) error {
data = data[:lastNotSpacePos(data)]
iter := ParseBytes(data)
iter.ReadVal(v)
if iter.head == iter.tail {
iter.loadMore()
}
if iter.Error == io.EOF {
return nil
}
if iter.Error == nil {
iter.reportError("Unmarshal", "there are bytes left after unmarshal")
}
return iter.Error
}
func UnmarshalAny(data []byte) (Any, error) {
data = data[:lastNotSpacePos(data)]
iter := ParseBytes(data)
any := iter.ReadAny()
if iter.head == iter.tail {
iter.loadMore()
}
if iter.Error == io.EOF {
return any, nil
}
if iter.Error == nil {
iter.reportError("UnmarshalAny", "there are bytes left after unmarshal")
}
return any, iter.Error
}
func lastNotSpacePos(data []byte) int {
for i := len(data) - 1; i >= 0; i-- {
if data[i] != ' ' && data[i] != '\t' && data[i] != '\r' && data[i] != '\n' {
return i + 1
}
}
return 0
}
func UnmarshalFromString(str string, v interface{}) error {
data := []byte(str)
data = data[:lastNotSpacePos(data)]
iter := ParseBytes(data)
iter.ReadVal(v)
if iter.head == iter.tail {
iter.loadMore()
}
if iter.Error == io.EOF {
return nil
}
if iter.Error == nil {
iter.reportError("UnmarshalFromString", "there are bytes left after unmarshal")
}
return iter.Error
}
func UnmarshalAnyFromString(str string) (Any, error) {
data := []byte(str)
data = data[:lastNotSpacePos(data)]
iter := ParseBytes(data)
any := iter.ReadAny()
if iter.head == iter.tail {
iter.loadMore()
}
if iter.Error == io.EOF {
return any, nil
}
if iter.Error == nil {
iter.reportError("UnmarshalAnyFromString", "there are bytes left after unmarshal")
}
return nil, iter.Error
}
func Marshal(v interface{}) ([]byte, error) {
buf := &bytes.Buffer{}
stream := NewStream(buf, 512)
stream.WriteVal(v)
stream.Flush()
if stream.Error != nil {
return nil, stream.Error
}
return buf.Bytes(), nil
}
func MarshalToString(v interface{}) (string, error) {
buf, err := Marshal(v)
if err != nil {
return "", err
}
return string(buf), nil
}
func NewDecoder(reader io.Reader) *AdaptedDecoder {
iter := Parse(reader, 512)
return &AdaptedDecoder{iter}
}
type AdaptedDecoder struct {
iter *Iterator
}
func (adapter *AdaptedDecoder) Decode(obj interface{}) error {
adapter.iter.ReadVal(obj)
err := adapter.iter.Error
if err == io.EOF {
return nil
}
return adapter.iter.Error
}
func (adapter *AdaptedDecoder) More() bool {
return adapter.iter.head != adapter.iter.tail
}
func (adapter *AdaptedDecoder) Buffered() io.Reader {
remaining := adapter.iter.buf[adapter.iter.head:adapter.iter.tail]
return bytes.NewReader(remaining)
}
func NewEncoder(writer io.Writer) *AdaptedEncoder {
stream := NewStream(writer, 512)
return &AdaptedEncoder{stream}
}
type AdaptedEncoder struct {
stream *Stream
}
func (adapter *AdaptedEncoder) Encode(val interface{}) error {
adapter.stream.WriteVal(val)
adapter.stream.Flush()
return adapter.stream.Error
}
func (adapter *AdaptedEncoder) SetIndent(prefix, indent string) {
// not implemented yet
}

304
feature_any.go Normal file
View File

@ -0,0 +1,304 @@
package jsoniter
import (
"fmt"
"reflect"
)
type Any interface {
LastError() error
ValueType() ValueType
ToBool() bool
ToInt() int
ToInt32() int32
ToInt64() int64
ToUint() uint
ToUint32() uint32
ToUint64() uint64
ToFloat32() float32
ToFloat64() float64
ToString() string
Get(path ...interface{}) Any
Size() int
Keys() []string
IterateObject() (func() (string, Any, bool), bool)
IterateArray() (func() (Any, bool), bool)
GetArray() []Any
SetArray(newList []Any) bool
GetObject() map[string]Any
SetObject(map[string]Any) bool
GetInterface() interface{}
WriteTo(stream *Stream)
Parse() *Iterator
}
type baseAny struct{}
func (any *baseAny) Get(path ...interface{}) Any {
return &invalidAny{baseAny{}, fmt.Errorf("Get %v from simple value", path)}
}
func (any *baseAny) Size() int {
return 0
}
func (any *baseAny) Keys() []string {
return []string{}
}
func (any *baseAny) IterateObject() (func() (string, Any, bool), bool) {
return nil, false
}
func (any *baseAny) IterateArray() (func() (Any, bool), bool) {
return nil, false
}
func (any *baseAny) GetArray() []Any {
return []Any{}
}
func (any *baseAny) SetArray(newList []Any) bool {
return false
}
func (any *baseAny) GetObject() map[string]Any {
return map[string]Any{}
}
func (any *baseAny) SetObject(map[string]Any) bool {
return false
}
func WrapInt32(val int32) Any {
return &int32Any{baseAny{}, val}
}
func WrapInt64(val int64) Any {
return &int64Any{baseAny{}, val}
}
func WrapUint32(val uint32) Any {
return &uint32Any{baseAny{}, val}
}
func WrapUint64(val uint64) Any {
return &uint64Any{baseAny{}, val}
}
func WrapFloat64(val float64) Any {
return &floatAny{baseAny{}, val}
}
func WrapString(val string) Any {
return &stringAny{baseAny{}, nil, val}
}
func Wrap(val interface{}) Any {
if val == nil {
return &nilAny{}
}
asAny, isAny := val.(Any)
if isAny {
return asAny
}
type_ := reflect.TypeOf(val)
switch type_.Kind() {
case reflect.Slice:
return wrapArray(val)
case reflect.Struct:
return wrapStruct(val)
case reflect.Map:
return wrapMap(val)
case reflect.String:
return WrapString(val.(string))
case reflect.Int:
return WrapInt64(int64(val.(int)))
case reflect.Int8:
return WrapInt32(int32(val.(int8)))
case reflect.Int16:
return WrapInt32(int32(val.(int16)))
case reflect.Int32:
return WrapInt32(val.(int32))
case reflect.Int64:
return WrapInt64(val.(int64))
case reflect.Uint:
return WrapUint64(uint64(val.(uint)))
case reflect.Uint8:
return WrapUint32(uint32(val.(uint8)))
case reflect.Uint16:
return WrapUint32(uint32(val.(uint16)))
case reflect.Uint32:
return WrapUint32(uint32(val.(uint32)))
case reflect.Uint64:
return WrapUint64(val.(uint64))
case reflect.Float32:
return WrapFloat64(float64(val.(float32)))
case reflect.Float64:
return WrapFloat64(val.(float64))
case reflect.Bool:
if val.(bool) == true {
return &trueAny{}
} else {
return &falseAny{}
}
}
return &invalidAny{baseAny{}, fmt.Errorf("unsupported type: %v", type_)}
}
func (iter *Iterator) ReadAny() Any {
return iter.readAny(nil)
}
func (iter *Iterator) readAny(reusableIter *Iterator) Any {
c := iter.nextToken()
switch c {
case '"':
return iter.readStringAny(reusableIter)
case 'n':
iter.skipFixedBytes(3) // null
return &nilAny{}
case 't':
iter.skipFixedBytes(3) // true
return &trueAny{}
case 'f':
iter.skipFixedBytes(4) // false
return &falseAny{}
case '{':
return iter.readObjectAny(reusableIter)
case '[':
return iter.readArrayAny(reusableIter)
default:
return iter.readNumberAny(reusableIter, c)
}
}
func (iter *Iterator) readNumberAny(reusableIter *Iterator, firstByte byte) Any {
dotFound := false
lazyBuf := make([]byte, 1, 8)
lazyBuf[0] = firstByte
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
if c == '.' {
dotFound = true
continue
}
switch c {
case ' ', '\n', '\r', '\t', ',', '}', ']':
lazyBuf = append(lazyBuf, iter.buf[iter.head:i]...)
iter.head = i
if dotFound {
return &float64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
} else {
if firstByte == '-' {
return &int64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
} else {
return &uint64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
}
}
}
}
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.head = iter.tail
if dotFound {
return &float64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
} else {
if firstByte == '-' {
return &int64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
} else {
return &uint64LazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
}
}
}
}
}
func (iter *Iterator) readStringAny(reusableIter *Iterator) Any {
lazyBuf := make([]byte, 1, 8)
lazyBuf[0] = '"'
for {
end, escaped := iter.findStringEnd()
if end == -1 {
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.reportError("readStringAny", "incomplete string")
return &invalidAny{}
}
if escaped {
iter.head = 1 // skip the first char as last char read is \
}
} else {
lazyBuf = append(lazyBuf, iter.buf[iter.head:end]...)
iter.head = end
return &stringLazyAny{baseAny{}, lazyBuf, reusableIter, nil, ""}
}
}
}
func (iter *Iterator) readObjectAny(reusableIter *Iterator) Any {
level := 1
lazyBuf := make([]byte, 1, 32)
lazyBuf[0] = '{'
for {
start := iter.head
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '{': // If open symbol, increase level
level++
case '}': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
lazyBuf = append(lazyBuf, iter.buf[start:iter.head]...)
return &objectLazyAny{baseAny{}, lazyBuf, reusableIter, nil, nil, lazyBuf}
}
}
}
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.reportError("skipObject", "incomplete object")
return &invalidAny{}
}
}
}
func (iter *Iterator) readArrayAny(reusableIter *Iterator) Any {
level := 1
lazyBuf := make([]byte, 1, 32)
lazyBuf[0] = '['
for {
start := iter.head
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '[': // If open symbol, increase level
level++
case ']': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
lazyBuf = append(lazyBuf, iter.buf[start:iter.head]...)
return &arrayLazyAny{baseAny{}, lazyBuf, reusableIter, nil, nil, lazyBuf}
}
}
}
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
if !iter.loadMore() {
iter.reportError("skipArray", "incomplete array")
return &invalidAny{}
}
}
}

539
feature_any_array.go Normal file
View File

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

129
feature_any_bool.go Normal file
View File

@ -0,0 +1,129 @@
package jsoniter
type trueAny struct {
baseAny
}
func (any *trueAny) LastError() error {
return nil
}
func (any *trueAny) ToBool() bool {
return true
}
func (any *trueAny) ToInt() int {
return 1
}
func (any *trueAny) ToInt32() int32 {
return 1
}
func (any *trueAny) ToInt64() int64 {
return 1
}
func (any *trueAny) ToUint() uint {
return 1
}
func (any *trueAny) ToUint32() uint32 {
return 1
}
func (any *trueAny) ToUint64() uint64 {
return 1
}
func (any *trueAny) ToFloat32() float32 {
return 1
}
func (any *trueAny) ToFloat64() float64 {
return 1
}
func (any *trueAny) ToString() string {
return "true"
}
func (any *trueAny) WriteTo(stream *Stream) {
stream.WriteTrue()
}
func (any *trueAny) Parse() *Iterator {
return nil
}
func (any *trueAny) GetInterface() interface{} {
return true
}
func (any *trueAny) ValueType() ValueType {
return Bool
}
type falseAny struct {
baseAny
}
func (any *falseAny) LastError() error {
return nil
}
func (any *falseAny) ToBool() bool {
return false
}
func (any *falseAny) ToInt() int {
return 0
}
func (any *falseAny) ToInt32() int32 {
return 0
}
func (any *falseAny) ToInt64() int64 {
return 0
}
func (any *falseAny) ToUint() uint {
return 0
}
func (any *falseAny) ToUint32() uint32 {
return 0
}
func (any *falseAny) ToUint64() uint64 {
return 0
}
func (any *falseAny) ToFloat32() float32 {
return 0
}
func (any *falseAny) ToFloat64() float64 {
return 0
}
func (any *falseAny) ToString() string {
return "false"
}
func (any *falseAny) WriteTo(stream *Stream) {
stream.WriteFalse()
}
func (any *falseAny) Parse() *Iterator {
return nil
}
func (any *falseAny) GetInterface() interface{} {
return false
}
func (any *falseAny) ValueType() ValueType {
return Bool
}

166
feature_any_float.go Normal file
View File

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

70
feature_any_int32.go Normal file
View File

@ -0,0 +1,70 @@
package jsoniter
import (
"strconv"
)
type int32Any struct {
baseAny
val int32
}
func (any *int32Any) LastError() error {
return nil
}
func (any *int32Any) ValueType() ValueType {
return Number
}
func (any *int32Any) ToBool() bool {
return any.val != 0
}
func (any *int32Any) ToInt() int {
return int(any.val)
}
func (any *int32Any) ToInt32() int32 {
return any.val
}
func (any *int32Any) ToInt64() int64 {
return int64(any.val)
}
func (any *int32Any) ToUint() uint {
return uint(any.val)
}
func (any *int32Any) ToUint32() uint32 {
return uint32(any.val)
}
func (any *int32Any) ToUint64() uint64 {
return uint64(any.val)
}
func (any *int32Any) ToFloat32() float32 {
return float32(any.val)
}
func (any *int32Any) ToFloat64() float64 {
return float64(any.val)
}
func (any *int32Any) ToString() string {
return strconv.FormatInt(int64(any.val), 10)
}
func (any *int32Any) WriteTo(stream *Stream) {
stream.WriteInt32(any.val)
}
func (any *int32Any) Parse() *Iterator {
return nil
}
func (any *int32Any) GetInterface() interface{} {
return any.val
}

166
feature_any_int64.go Normal file
View File

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

75
feature_any_invalid.go Normal file
View File

@ -0,0 +1,75 @@
package jsoniter
import "fmt"
type invalidAny struct {
baseAny
err error
}
func (any *invalidAny) LastError() error {
return any.err
}
func (any *invalidAny) ValueType() ValueType {
return Invalid
}
func (any *invalidAny) ToBool() bool {
return false
}
func (any *invalidAny) ToInt() int {
return 0
}
func (any *invalidAny) ToInt32() int32 {
return 0
}
func (any *invalidAny) ToInt64() int64 {
return 0
}
func (any *invalidAny) ToUint() uint {
return 0
}
func (any *invalidAny) ToUint32() uint32 {
return 0
}
func (any *invalidAny) ToUint64() uint64 {
return 0
}
func (any *invalidAny) ToFloat32() float32 {
return 0
}
func (any *invalidAny) ToFloat64() float64 {
return 0
}
func (any *invalidAny) ToString() string {
return ""
}
func (any *invalidAny) WriteTo(stream *Stream) {
}
func (any *invalidAny) Get(path ...interface{}) Any {
if any.err == nil {
return &invalidAny{baseAny{}, fmt.Errorf("get %v from invalid", path)}
} else {
return &invalidAny{baseAny{}, fmt.Errorf("%v, get %v from invalid", any.err, path)}
}
}
func (any *invalidAny) Parse() *Iterator {
return nil
}
func (any *invalidAny) GetInterface() interface{} {
return nil
}

65
feature_any_nil.go Normal file
View File

@ -0,0 +1,65 @@
package jsoniter
type nilAny struct {
baseAny
}
func (any *nilAny) LastError() error {
return nil
}
func (any *nilAny) ValueType() ValueType {
return Nil
}
func (any *nilAny) ToBool() bool {
return false
}
func (any *nilAny) ToInt() int {
return 0
}
func (any *nilAny) ToInt32() int32 {
return 0
}
func (any *nilAny) ToInt64() int64 {
return 0
}
func (any *nilAny) ToUint() uint {
return 0
}
func (any *nilAny) ToUint32() uint32 {
return 0
}
func (any *nilAny) ToUint64() uint64 {
return 0
}
func (any *nilAny) ToFloat32() float32 {
return 0
}
func (any *nilAny) ToFloat64() float64 {
return 0
}
func (any *nilAny) ToString() string {
return ""
}
func (any *nilAny) WriteTo(stream *Stream) {
stream.WriteNil()
}
func (any *nilAny) Parse() *Iterator {
return nil
}
func (any *nilAny) GetInterface() interface{} {
return nil
}

848
feature_any_object.go Normal file
View File

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

231
feature_any_string.go Normal file
View File

@ -0,0 +1,231 @@
package jsoniter
import (
"io"
"strconv"
)
type stringLazyAny struct{
baseAny
buf []byte
iter *Iterator
err error
cache string
}
func (any *stringLazyAny) ValueType() ValueType {
return String
}
func (any *stringLazyAny) Parse() *Iterator {
iter := any.iter
if iter == nil {
iter = NewIterator()
any.iter = iter
}
iter.ResetBytes(any.buf)
return iter
}
func (any *stringLazyAny) fillCache() {
if any.err != nil {
return
}
iter := any.Parse()
any.cache = iter.ReadString()
if iter.Error != io.EOF {
iter.reportError("stringLazyAny", "there are bytes left")
}
any.err = iter.Error
}
func (any *stringLazyAny) LastError() error {
return any.err
}
func (any *stringLazyAny) ToBool() bool {
str := any.ToString()
if str == "false" {
return false
}
for _, c := range str {
switch c {
case ' ', '\n', '\r', '\t':
default:
return true
}
}
return false
}
func (any *stringLazyAny) ToInt() int {
iter := any.Parse()
iter.head++
val := iter.ReadInt()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToInt32() int32 {
iter := any.Parse()
iter.head++
val := iter.ReadInt32()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToInt64() int64 {
iter := any.Parse()
iter.head++
val := iter.ReadInt64()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToUint() uint {
iter := any.Parse()
iter.head++
val := iter.ReadUint()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToUint32() uint32 {
iter := any.Parse()
iter.head++
val := iter.ReadUint32()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToUint64() uint64 {
iter := any.Parse()
iter.head++
val := iter.ReadUint64()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToFloat32() float32 {
iter := any.Parse()
iter.head++
val := iter.ReadFloat32()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToFloat64() float64 {
iter := any.Parse()
iter.head++
val := iter.ReadFloat64()
any.err = iter.Error
return val
}
func (any *stringLazyAny) ToString() string {
any.fillCache()
return any.cache
}
func (any *stringLazyAny) WriteTo(stream *Stream) {
stream.Write(any.buf)
}
func (any *stringLazyAny) GetInterface() interface{} {
any.fillCache()
return any.cache
}
type stringAny struct{
baseAny
err error
val string
}
func (any *stringAny) Parse() *Iterator {
return nil
}
func (any *stringAny) ValueType() ValueType {
return String
}
func (any *stringAny) LastError() error {
return any.err
}
func (any *stringAny) ToBool() bool {
str := any.ToString()
if str == "false" {
return false
}
for _, c := range str {
switch c {
case ' ', '\n', '\r', '\t':
default:
return true
}
}
return false
}
func (any *stringAny) ToInt() int {
parsed, err := strconv.ParseInt(any.val, 10, 64)
any.err = err
return int(parsed)
}
func (any *stringAny) ToInt32() int32 {
parsed, err := strconv.ParseInt(any.val, 10, 32)
any.err = err
return int32(parsed)
}
func (any *stringAny) ToInt64() int64 {
parsed, err := strconv.ParseInt(any.val, 10, 64)
any.err = err
return parsed
}
func (any *stringAny) ToUint() uint {
parsed, err := strconv.ParseUint(any.val, 10, 64)
any.err = err
return uint(parsed)
}
func (any *stringAny) ToUint32() uint32 {
parsed, err := strconv.ParseUint(any.val, 10, 32)
any.err = err
return uint32(parsed)
}
func (any *stringAny) ToUint64() uint64 {
parsed, err := strconv.ParseUint(any.val, 10, 64)
any.err = err
return parsed
}
func (any *stringAny) ToFloat32() float32 {
parsed, err := strconv.ParseFloat(any.val, 32)
any.err = err
return float32(parsed)
}
func (any *stringAny) ToFloat64() float64 {
parsed, err := strconv.ParseFloat(any.val, 64)
any.err = err
return parsed
}
func (any *stringAny) ToString() string {
return any.val
}
func (any *stringAny) WriteTo(stream *Stream) {
stream.WriteString(any.val)
}
func (any *stringAny) GetInterface() interface{} {
return any.val
}

70
feature_any_uint32.go Normal file
View File

@ -0,0 +1,70 @@
package jsoniter
import (
"strconv"
)
type uint32Any struct {
baseAny
val uint32
}
func (any *uint32Any) LastError() error {
return nil
}
func (any *uint32Any) ValueType() ValueType {
return Number
}
func (any *uint32Any) ToBool() bool {
return any.val != 0
}
func (any *uint32Any) ToInt() int {
return int(any.val)
}
func (any *uint32Any) ToInt32() int32 {
return int32(any.val)
}
func (any *uint32Any) ToInt64() int64 {
return int64(any.val)
}
func (any *uint32Any) ToUint() uint {
return uint(any.val)
}
func (any *uint32Any) ToUint32() uint32 {
return any.val
}
func (any *uint32Any) ToUint64() uint64 {
return uint64(any.val)
}
func (any *uint32Any) ToFloat32() float32 {
return float32(any.val)
}
func (any *uint32Any) ToFloat64() float64 {
return float64(any.val)
}
func (any *uint32Any) ToString() string {
return strconv.FormatInt(int64(any.val), 10)
}
func (any *uint32Any) WriteTo(stream *Stream) {
stream.WriteUint32(any.val)
}
func (any *uint32Any) Parse() *Iterator {
return nil
}
func (any *uint32Any) GetInterface() interface{} {
return any.val
}

167
feature_any_uint64.go Normal file
View File

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

279
feature_iter.go Normal file
View File

@ -0,0 +1,279 @@
package jsoniter
import (
"encoding/base64"
"fmt"
"io"
)
type ValueType int
const (
Invalid ValueType = iota
String
Number
Nil
Bool
Array
Object
)
var hexDigits []byte
var valueTypes []ValueType
func init() {
hexDigits = make([]byte, 256)
for i := 0; i < len(hexDigits); i++ {
hexDigits[i] = 255
}
for i := '0'; i <= '9'; i++ {
hexDigits[i] = byte(i - '0')
}
for i := 'a'; i <= 'f'; i++ {
hexDigits[i] = byte((i - 'a') + 10)
}
for i := 'A'; i <= 'F'; i++ {
hexDigits[i] = byte((i - 'A') + 10)
}
valueTypes = make([]ValueType, 256)
for i := 0; i < len(valueTypes); i++ {
valueTypes[i] = Invalid
}
valueTypes['"'] = String
valueTypes['-'] = Number
valueTypes['0'] = Number
valueTypes['1'] = Number
valueTypes['2'] = Number
valueTypes['3'] = Number
valueTypes['4'] = Number
valueTypes['5'] = Number
valueTypes['6'] = Number
valueTypes['7'] = Number
valueTypes['8'] = Number
valueTypes['9'] = Number
valueTypes['t'] = Bool
valueTypes['f'] = Bool
valueTypes['n'] = Nil
valueTypes['['] = Array
valueTypes['{'] = Object
}
// Iterator is a fast and flexible JSON parser
type Iterator struct {
reader io.Reader
buf []byte
head int
tail int
Error error
}
// Create creates an empty Iterator instance
func NewIterator() *Iterator {
return &Iterator{
reader: nil,
buf: nil,
head: 0,
tail: 0,
}
}
// Parse parses a json buffer in io.Reader into an Iterator instance
func Parse(reader io.Reader, bufSize int) *Iterator {
return &Iterator{
reader: reader,
buf: make([]byte, bufSize),
head: 0,
tail: 0,
}
}
// ParseBytes parses a json byte slice into an Iterator instance
func ParseBytes(input []byte) *Iterator {
return &Iterator{
reader: nil,
buf: input,
head: 0,
tail: len(input),
}
}
// ParseString parses a json string into an Iterator instance
func ParseString(input string) *Iterator {
return ParseBytes([]byte(input))
}
// Reset can reset an Iterator instance for another json buffer in io.Reader
func (iter *Iterator) Reset(reader io.Reader) *Iterator {
iter.reader = reader
iter.head = 0
iter.tail = 0
return iter
}
// ResetBytes can reset an Iterator instance for another json byte slice
func (iter *Iterator) ResetBytes(input []byte) *Iterator {
iter.reader = nil
iter.Error = nil
iter.buf = input
iter.head = 0
iter.tail = len(input)
return iter
}
// WhatIsNext gets ValueType of relatively next json object
func (iter *Iterator) WhatIsNext() ValueType {
valueType := valueTypes[iter.nextToken()]
iter.unreadByte()
return valueType
}
func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\t', '\r':
continue
}
iter.head = i
return false
}
return true
}
func (iter *Iterator) nextToken() byte {
// a variation of skip whitespaces, returning the next non-whitespace token
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\t', '\r':
continue
}
iter.head = i + 1
return c
}
if !iter.loadMore() {
return 0
}
}
}
func (iter *Iterator) reportError(operation string, msg string) {
if iter.Error != nil {
if iter.Error != io.EOF {
return
}
}
peekStart := iter.head - 10
if peekStart < 0 {
peekStart = 0
}
iter.Error = fmt.Errorf("%s: %s, parsing %v ...%s... at %s", operation, msg, iter.head,
string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
}
// CurrentBuffer gets current buffer as string
func (iter *Iterator) CurrentBuffer() string {
peekStart := iter.head - 10
if peekStart < 0 {
peekStart = 0
}
return fmt.Sprintf("parsing %v ...|%s|... at %s", iter.head,
string(iter.buf[peekStart:iter.head]), string(iter.buf[0:iter.tail]))
}
func (iter *Iterator) readByte() (ret byte) {
if iter.head == iter.tail {
if iter.loadMore() {
ret = iter.buf[iter.head]
iter.head++
return ret
}
return 0
}
ret = iter.buf[iter.head]
iter.head++
return ret
}
func (iter *Iterator) loadMore() bool {
if iter.reader == nil {
if iter.Error == nil {
iter.Error = io.EOF
}
return false
}
for {
n, err := iter.reader.Read(iter.buf)
if n == 0 {
if err != nil {
if iter.Error == nil {
iter.Error = err
}
return false
}
} else {
iter.head = 0
iter.tail = n
return true
}
}
}
func (iter *Iterator) unreadByte() {
if iter.head == 0 {
iter.reportError("unreadByte", "unread too many bytes")
return
}
iter.head--
return
}
func (iter *Iterator) Read() interface{} {
valueType := iter.WhatIsNext()
switch valueType {
case String:
return iter.ReadString()
case Number:
return iter.ReadFloat64()
case Nil:
iter.skipFixedBytes(4) // null
return nil
case Bool:
return iter.ReadBool()
case Array:
arr := []interface{}{}
iter.ReadArrayCB(func(iter *Iterator) bool {
arr = append(arr, iter.Read())
return true
})
return arr
case Object:
obj := map[string]interface{}{}
iter.ReadObjectCB(func(Iter *Iterator, field string) bool {
obj[field] = iter.Read()
return true
})
return obj
default:
iter.reportError("Read", fmt.Sprintf("unexpected value type: %v", valueType))
return nil
}
}
// ReadBase64 reads a json object as Base64 in byte slice
func (iter *Iterator) ReadBase64() (ret []byte) {
src := iter.ReadStringAsSlice()
if iter.Error != nil {
return
}
b64 := base64.StdEncoding
ret = make([]byte, b64.DecodedLen(len(src)))
n, err := b64.Decode(ret, src)
if err != nil {
iter.Error = err
return
}
return ret[:n]
}

51
feature_iter_array.go Normal file
View File

@ -0,0 +1,51 @@
package jsoniter
func (iter *Iterator) ReadArray() (ret bool) {
c := iter.nextToken()
switch c {
case 'n':
iter.skipFixedBytes(3)
return false // null
case '[':
c = iter.nextToken()
if c != ']' {
iter.unreadByte()
return true
}
return false
case ']':
return false
case ',':
return true
default:
iter.reportError("ReadArray", "expect [ or , or ] or n, but found: " + string([]byte{c}))
return
}
}
func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) {
c := iter.nextToken()
if c == '[' {
c = iter.nextToken()
if c != ']' {
iter.unreadByte()
if !callback(iter) {
return false
}
for iter.nextToken() == ',' {
if !callback(iter) {
return false
}
}
return true
}
return true
}
if c == 'n' {
iter.skipFixedBytes(3)
return true // null
}
iter.reportError("ReadArrayCB", "expect [ or n, but found: " + string([]byte{c}))
return false
}

239
feature_iter_float.go Normal file
View File

@ -0,0 +1,239 @@
package jsoniter
import (
"io"
"strconv"
"unsafe"
"math/big"
)
var floatDigits []int8
const invalidCharForNumber = int8(-1)
const endOfNumber = int8(-2)
const dotInNumber = int8(-3)
func init() {
floatDigits = make([]int8, 256)
for i := 0; i < len(floatDigits); i++ {
floatDigits[i] = invalidCharForNumber
}
for i := int8('0'); i <= int8('9'); i++ {
floatDigits[i] = i - int8('0')
}
floatDigits[','] = endOfNumber
floatDigits[']'] = endOfNumber
floatDigits['}'] = endOfNumber
floatDigits[' '] = endOfNumber
floatDigits['\t'] = endOfNumber
floatDigits['\n'] = endOfNumber
floatDigits['.'] = dotInNumber
}
func (iter *Iterator) ReadBigFloat() (ret *big.Float) {
str := iter.readNumberAsString()
if iter.Error != nil && iter.Error != io.EOF {
return nil
}
prec := 64
if len(str) > prec {
prec = len(str)
}
val, _, err := big.ParseFloat(str, 10, uint(prec), big.ToZero)
if err != nil {
iter.Error = err
return nil
}
return val
}
func (iter *Iterator) ReadBigInt() (ret *big.Int) {
str := iter.readNumberAsString()
if iter.Error != nil && iter.Error != io.EOF {
return nil
}
ret = big.NewInt(0)
var success bool
ret, success = ret.SetString(str, 10)
if !success {
iter.reportError("ReadBigInt", "invalid big int")
return nil
}
return ret
}
func (iter *Iterator) ReadFloat32() (ret float32) {
c := iter.nextToken()
if c == '-' {
return -iter.readPositiveFloat32()
} else {
iter.unreadByte()
return iter.readPositiveFloat32()
}
}
func (iter *Iterator) readPositiveFloat32() (ret float32) {
value := uint64(0)
c := byte(' ')
i := iter.head
non_decimal_loop:
for ; i < iter.tail; i++ {
c = iter.buf[i]
ind := floatDigits[c]
switch ind {
case invalidCharForNumber:
return iter.readFloat32SlowPath()
case endOfNumber:
iter.head = i
return float32(value)
case dotInNumber:
break non_decimal_loop
}
if value > uint64SafeToMultiple10 {
return iter.readFloat32SlowPath()
}
value = (value << 3) + (value << 1) + uint64(ind); // value = value * 10 + ind;
}
if c == '.' {
i++
decimalPlaces := 0;
for ; i < iter.tail; i++ {
c = iter.buf[i]
ind := floatDigits[c];
switch ind {
case endOfNumber:
if decimalPlaces > 0 && decimalPlaces < len(POW10) {
iter.head = i
return float32(float64(value) / float64(POW10[decimalPlaces]))
}
// too many decimal places
return iter.readFloat32SlowPath()
case invalidCharForNumber:
fallthrough
case dotInNumber:
return iter.readFloat32SlowPath()
}
decimalPlaces++
if value > uint64SafeToMultiple10 {
return iter.readFloat32SlowPath()
}
value = (value << 3) + (value << 1) + uint64(ind)
}
}
return iter.readFloat32SlowPath()
}
func (iter *Iterator) readNumberAsString() (ret string) {
strBuf := [16]byte{}
str := strBuf[0:0]
load_loop:
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case '-', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
str = append(str, c)
continue
default:
iter.head = i
break load_loop
}
}
if !iter.loadMore() {
break
}
}
if iter.Error != nil && iter.Error != io.EOF {
return
}
if len(str) == 0 {
iter.reportError("readNumberAsString", "invalid number")
}
return *(*string)(unsafe.Pointer(&str))
}
func (iter *Iterator) readFloat32SlowPath() (ret float32) {
str := iter.readNumberAsString()
if iter.Error != nil && iter.Error != io.EOF {
return
}
val, err := strconv.ParseFloat(str, 32)
if err != nil {
iter.Error = err
return
}
return float32(val)
}
func (iter *Iterator) ReadFloat64() (ret float64) {
c := iter.nextToken()
if c == '-' {
return -iter.readPositiveFloat64()
} else {
iter.unreadByte()
return iter.readPositiveFloat64()
}
}
func (iter *Iterator) readPositiveFloat64() (ret float64) {
value := uint64(0)
c := byte(' ')
i := iter.head
non_decimal_loop:
for ; i < iter.tail; i++ {
c = iter.buf[i]
ind := floatDigits[c]
switch ind {
case invalidCharForNumber:
return iter.readFloat64SlowPath()
case endOfNumber:
iter.head = i
return float64(value)
case dotInNumber:
break non_decimal_loop
}
if value > uint64SafeToMultiple10 {
return iter.readFloat64SlowPath()
}
value = (value << 3) + (value << 1) + uint64(ind); // value = value * 10 + ind;
}
if c == '.' {
i++
decimalPlaces := 0;
for ; i < iter.tail; i++ {
c = iter.buf[i]
ind := floatDigits[c];
switch ind {
case endOfNumber:
if decimalPlaces > 0 && decimalPlaces < len(POW10) {
iter.head = i
return float64(value) / float64(POW10[decimalPlaces])
}
// too many decimal places
return iter.readFloat64SlowPath()
case invalidCharForNumber:
fallthrough
case dotInNumber:
return iter.readFloat64SlowPath()
}
decimalPlaces++
if value > uint64SafeToMultiple10 {
return iter.readFloat64SlowPath()
}
value = (value << 3) + (value << 1) + uint64(ind)
}
}
return iter.readFloat64SlowPath()
}
func (iter *Iterator) readFloat64SlowPath() (ret float64) {
str := iter.readNumberAsString()
if iter.Error != nil && iter.Error != io.EOF {
return
}
val, err := strconv.ParseFloat(str, 64)
if err != nil {
iter.Error = err
return
}
return val
}

259
feature_iter_int.go Normal file
View File

@ -0,0 +1,259 @@
package jsoniter
import (
"strconv"
)
var intDigits []int8
const uint32SafeToMultiply10 = uint32(0xffffffff) / 10 - 1
const uint64SafeToMultiple10 = uint64(0xffffffffffffffff) / 10 - 1
const int64Max = uint64(0x7fffffffffffffff)
const int32Max = uint32(0x7fffffff)
const int16Max = uint32(0x7fff)
const uint16Max = uint32(0xffff)
const int8Max = uint32(0x7fff)
const uint8Max = uint32(0xffff)
func init() {
intDigits = make([]int8, 256)
for i := 0; i < len(floatDigits); i++ {
intDigits[i] = invalidCharForNumber
}
for i := int8('0'); i <= int8('9'); i++ {
intDigits[i] = i - int8('0')
}
}
func (iter *Iterator) ReadUint() uint {
return uint(iter.ReadUint64())
}
func (iter *Iterator) ReadInt() int {
return int(iter.ReadInt64())
}
func (iter *Iterator) ReadInt8() (ret int8) {
c := iter.nextToken()
if c == '-' {
val := iter.readUint32(iter.readByte())
if val > int8Max + 1 {
iter.reportError("ReadInt8", "overflow: " + strconv.FormatInt(int64(val), 10))
return
}
return -int8(val)
} else {
val := iter.readUint32(c)
if val > int8Max {
iter.reportError("ReadInt8", "overflow: " + strconv.FormatInt(int64(val), 10))
return
}
return int8(val)
}
}
func (iter *Iterator) ReadUint8() (ret uint8) {
val := iter.readUint32(iter.nextToken())
if val > uint8Max {
iter.reportError("ReadUint8", "overflow: " + strconv.FormatInt(int64(val), 10))
return
}
return uint8(val)
}
func (iter *Iterator) ReadInt16() (ret int16) {
c := iter.nextToken()
if c == '-' {
val := iter.readUint32(iter.readByte())
if val > int16Max + 1 {
iter.reportError("ReadInt16", "overflow: " + strconv.FormatInt(int64(val), 10))
return
}
return -int16(val)
} else {
val := iter.readUint32(c)
if val > int16Max {
iter.reportError("ReadInt16", "overflow: " + strconv.FormatInt(int64(val), 10))
return
}
return int16(val)
}
}
func (iter *Iterator) ReadUint16() (ret uint16) {
val := iter.readUint32(iter.nextToken())
if val > uint16Max {
iter.reportError("ReadUint16", "overflow: " + strconv.FormatInt(int64(val), 10))
return
}
return uint16(val)
}
func (iter *Iterator) ReadInt32() (ret int32) {
c := iter.nextToken()
if c == '-' {
val := iter.readUint32(iter.readByte())
if val > int32Max + 1 {
iter.reportError("ReadInt32", "overflow: " + strconv.FormatInt(int64(val), 10))
return
}
return -int32(val)
} else {
val := iter.readUint32(c)
if val > int32Max {
iter.reportError("ReadInt32", "overflow: " + strconv.FormatInt(int64(val), 10))
return
}
return int32(val)
}
}
func (iter *Iterator) ReadUint32() (ret uint32) {
return iter.readUint32(iter.nextToken())
}
func (iter *Iterator) readUint32(c byte) (ret uint32) {
ind := intDigits[c]
if ind == 0 {
return 0 // single zero
}
if ind == invalidCharForNumber {
iter.reportError("readUint32", "unexpected character: " + string([]byte{byte(ind)}))
return
}
value := uint32(ind)
if iter.tail - iter.head > 10 {
i := iter.head
ind2 := intDigits[iter.buf[i]]
if ind2 == invalidCharForNumber {
iter.head = i
return value
}
i++
ind3 := intDigits[iter.buf[i]]
if ind3 == invalidCharForNumber {
iter.head = i
return value * 10 + uint32(ind2)
}
//iter.head = i + 1
//value = value * 100 + uint32(ind2) * 10 + uint32(ind3)
i++
ind4 := intDigits[iter.buf[i]]
if ind4 == invalidCharForNumber {
iter.head = i
return value * 100 + uint32(ind2) * 10 + uint32(ind3)
}
i++
ind5 := intDigits[iter.buf[i]]
if ind5 == invalidCharForNumber {
iter.head = i
return value * 1000 + uint32(ind2) * 100 + uint32(ind3) * 10 + uint32(ind4)
}
i++
ind6 := intDigits[iter.buf[i]]
if ind6 == invalidCharForNumber {
iter.head = i
return value * 10000 + uint32(ind2) * 1000 + uint32(ind3) * 100 + uint32(ind4) * 10 + uint32(ind5)
}
i++
ind7 := intDigits[iter.buf[i]]
if ind7 == invalidCharForNumber {
iter.head = i
return value * 100000 + uint32(ind2) * 10000 + uint32(ind3) * 1000 + uint32(ind4) * 100 + uint32(ind5) * 10 + uint32(ind6)
}
i++
ind8 := intDigits[iter.buf[i]]
if ind8 == invalidCharForNumber {
iter.head = i
return value * 1000000 + uint32(ind2) * 100000 + uint32(ind3) * 10000 + uint32(ind4) * 1000 + uint32(ind5) * 100 + uint32(ind6) * 10 + uint32(ind7)
}
i++
ind9 := intDigits[iter.buf[i]]
value = value * 10000000 + uint32(ind2) * 1000000 + uint32(ind3) * 100000 + uint32(ind4) * 10000 + uint32(ind5) * 1000 + uint32(ind6) * 100 + uint32(ind7) * 10 + uint32(ind8)
iter.head = i
if ind9 == invalidCharForNumber {
return value
}
}
for {
for i := iter.head; i < iter.tail; i++ {
ind = intDigits[iter.buf[i]]
if ind == invalidCharForNumber {
iter.head = i
return value
}
if value > uint32SafeToMultiply10 {
value2 := (value << 3) + (value << 1) + uint32(ind)
if value2 < value {
iter.reportError("readUint32", "overflow")
return
} else {
value = value2
continue
}
}
value = (value << 3) + (value << 1) + uint32(ind)
}
if (!iter.loadMore()) {
return value
}
}
}
func (iter *Iterator) ReadInt64() (ret int64) {
c := iter.nextToken()
if c == '-' {
val := iter.readUint64(iter.readByte())
if val > int64Max + 1 {
iter.reportError("ReadInt64", "overflow: " + strconv.FormatUint(uint64(val), 10))
return
}
return -int64(val)
} else {
val := iter.readUint64(c)
if val > int64Max {
iter.reportError("ReadInt64", "overflow: " + strconv.FormatUint(uint64(val), 10))
return
}
return int64(val)
}
}
func (iter *Iterator) ReadUint64() uint64 {
return iter.readUint64(iter.nextToken())
}
func (iter *Iterator) readUint64(c byte) (ret uint64) {
ind := intDigits[c]
if ind == 0 {
return 0 // single zero
}
if ind == invalidCharForNumber {
iter.reportError("readUint64", "unexpected character: " + string([]byte{byte(ind)}))
return
}
value := uint64(ind)
for {
for i := iter.head; i < iter.tail; i++ {
ind = intDigits[iter.buf[i]]
if ind == invalidCharForNumber {
iter.head = i
return value
}
if value > uint64SafeToMultiple10 {
value2 := (value << 3) + (value << 1) + uint64(ind)
if value2 < value {
iter.reportError("readUint64", "overflow")
return
} else {
value = value2
continue
}
}
value = (value << 3) + (value << 1) + uint64(ind)
}
if (!iter.loadMore()) {
return value
}
}
}

154
feature_iter_object.go Normal file
View File

@ -0,0 +1,154 @@
package jsoniter
import (
"fmt"
"unicode"
)
func (iter *Iterator) ReadObject() (ret string) {
c := iter.nextToken()
switch c {
case 'n':
iter.skipFixedBytes(3)
return "" // null
case '{':
c = iter.nextToken()
if c == '"' {
iter.unreadByte()
return string(iter.readObjectFieldAsBytes())
}
if c == '}' {
return "" // end of object
}
iter.reportError("ReadObject", `expect " after {`)
return
case ',':
return string(iter.readObjectFieldAsBytes())
case '}':
return "" // end of object
default:
iter.reportError("ReadObject", fmt.Sprintf(`expect { or , or } or n, but found %s`, string([]byte{c})))
return
}
}
func (iter *Iterator) readFieldHash() int32 {
hash := int64(0x811c9dc5)
c := iter.nextToken()
if c == '"' {
for {
for i := iter.head; i < iter.tail; i++ {
// require ascii string and no escape
b := iter.buf[i]
if 'A' <= b && b <= 'Z' {
b += 'a' - 'A'
}
if b == '"' {
iter.head = i+1
c = iter.nextToken()
if c != ':' {
iter.reportError("readFieldHash", `expect :, but found ` + string([]byte{c}))
}
return int32(hash)
}
hash ^= int64(b)
hash *= 0x1000193
}
if !iter.loadMore() {
iter.reportError("readFieldHash", `incomplete field name`)
return 0
}
}
}
iter.reportError("readFieldHash", `expect ", but found ` + string([]byte{c}))
return 0
}
func calcHash(str string) int32 {
hash := int64(0x811c9dc5)
for _, b := range str {
hash ^= int64(unicode.ToLower(b))
hash *= 0x1000193
}
return int32(hash)
}
func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
c := iter.nextToken()
if c == '{' {
c = iter.nextToken()
if c == '"' {
iter.unreadByte()
field := string(iter.readObjectFieldAsBytes())
if !callback(iter, field) {
return false
}
for iter.nextToken() == ',' {
field := string(iter.readObjectFieldAsBytes())
if !callback(iter, field) {
return false
}
}
return true
}
if c == '}' {
return true
}
iter.reportError("ReadObjectCB", `expect " after }`)
return false
}
if c == 'n' {
iter.skipFixedBytes(3)
return true // null
}
iter.reportError("ReadObjectCB", `expect { or n`)
return false
}
func (iter *Iterator) readObjectStart() bool {
c := iter.nextToken()
if c == '{' {
c = iter.nextToken()
if c == '}' {
return false
}
iter.unreadByte()
return true
} else if c == 'n' {
iter.skipFixedBytes(3)
return false
}
iter.reportError("readObjectStart", "expect { or n")
return false
}
func (iter *Iterator) readObjectFieldAsBytes() (ret []byte) {
str := iter.ReadStringAsSlice()
if iter.skipWhitespacesWithoutLoadMore() {
if ret == nil {
ret = make([]byte, len(str))
copy(ret, str)
}
if !iter.loadMore() {
return
}
}
if iter.buf[iter.head] != ':' {
iter.reportError("readObjectFieldAsBytes", "expect : after object field")
return
}
iter.head++
if iter.skipWhitespacesWithoutLoadMore() {
if ret == nil {
ret = make([]byte, len(str))
copy(ret, str)
}
if !iter.loadMore() {
return
}
}
if ret == nil {
return str
}
return ret
}

218
feature_iter_skip.go Normal file
View File

@ -0,0 +1,218 @@
package jsoniter
import "fmt"
// ReadNil reads a json object as nil and
// returns whether it's a nil or not
func (iter *Iterator) ReadNil() (ret bool) {
c := iter.nextToken()
if c == 'n' {
iter.skipFixedBytes(3) // null
return true
}
iter.unreadByte()
return false
}
// ReadBool reads a json object as Bool
func (iter *Iterator) ReadBool() (ret bool) {
c := iter.nextToken()
if c == 't' {
iter.skipFixedBytes(3)
return true
}
if c == 'f' {
iter.skipFixedBytes(4)
return false
}
iter.reportError("ReadBool", "expect t or f")
return
}
func (iter *Iterator) SkipAndReturnBytes() []byte {
if iter.reader != nil {
panic("reader input does not support this api")
}
before := iter.head
iter.Skip()
after := iter.head
return iter.buf[before:after]
}
// Skip skips a json object and positions to relatively the next json object
func (iter *Iterator) Skip() {
c := iter.nextToken()
switch c {
case '"':
iter.skipString()
case 'n', 't':
iter.skipFixedBytes(3) // null or true
case 'f':
iter.skipFixedBytes(4) // false
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
iter.skipUntilBreak()
case '[':
iter.skipArray()
case '{':
iter.skipObject()
default:
iter.reportError("Skip", fmt.Sprintf("do not know how to skip: %v", c))
return
}
}
func (iter *Iterator) skipString() {
for {
end, escaped := iter.findStringEnd()
if end == -1 {
if !iter.loadMore() {
iter.reportError("skipString", "incomplete string")
return
}
if escaped {
iter.head = 1 // skip the first char as last char read is \
}
} else {
iter.head = end
return
}
}
}
// adapted from: https://github.com/buger/jsonparser/blob/master/parser.go
// Tries to find the end of string
// Support if string contains escaped quote symbols.
func (iter *Iterator) findStringEnd() (int, bool) {
escaped := false
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
if c == '"' {
if !escaped {
return i + 1, false
}
j := i - 1
for {
if j < iter.head || iter.buf[j] != '\\' {
// even number of backslashes
// either end of buffer, or " found
return i + 1, true
}
j--
if j < iter.head || iter.buf[j] != '\\' {
// odd number of backslashes
// it is \" or \\\"
break
}
j--
}
} else if c == '\\' {
escaped = true
}
}
j := iter.tail - 1
for {
if j < iter.head || iter.buf[j] != '\\' {
// even number of backslashes
// either end of buffer, or " found
return -1, false // do not end with \
}
j--
if j < iter.head || iter.buf[j] != '\\' {
// odd number of backslashes
// it is \" or \\\"
break
}
j--
}
return -1, true // end with \
}
func (iter *Iterator) skipArray() {
level := 1
for {
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '[': // If open symbol, increase level
level++
case ']': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
return
}
}
}
if !iter.loadMore() {
iter.reportError("skipObject", "incomplete array")
return
}
}
}
func (iter *Iterator) skipObject() {
level := 1
for {
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '{': // If open symbol, increase level
level++
case '}': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
return
}
}
}
if !iter.loadMore() {
iter.reportError("skipObject", "incomplete object")
return
}
}
}
func (iter *Iterator) skipUntilBreak() {
// true, false, null, number
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\r', '\t', ',', '}', ']':
iter.head = i
return
}
}
if !iter.loadMore() {
return
}
}
}
func (iter *Iterator) skipFixedBytes(n int) {
iter.head += n;
if (iter.head >= iter.tail) {
more := iter.head - iter.tail;
if !iter.loadMore() {
if more > 0 {
iter.reportError("skipFixedBytes", "unexpected end");
}
return
}
iter.head += more;
}
}

197
feature_iter_string.go Normal file
View File

@ -0,0 +1,197 @@
package jsoniter
import (
"unicode/utf16"
)
func (iter *Iterator) ReadString() (ret string) {
c := iter.nextToken()
if c == '"' {
for i := iter.head ; i < iter.tail; i++ {
c := iter.buf[i]
if c == '"' {
ret = string(iter.buf[iter.head:i])
iter.head = i + 1
return ret
} else if c == '\\' {
break
}
}
return iter.readStringSlowPath()
} else if c == 'n' {
iter.skipFixedBytes(3)
return ""
}
iter.reportError("ReadString", `expects " or n`)
return
}
func (iter *Iterator) readStringSlowPath() (ret string) {
var str []byte
var c byte
for iter.Error == nil {
c = iter.readByte()
if c == '"' {
return string(str)
}
if c == '\\' {
c = iter.readByte()
switch c {
case 'u', 'U':
r := iter.readU4()
if utf16.IsSurrogate(r) {
c = iter.readByte()
if iter.Error != nil {
return
}
if c != '\\' {
iter.reportError("ReadString",
`expects \u after utf16 surrogate, but \ not found`)
return
}
c = iter.readByte()
if iter.Error != nil {
return
}
if c != 'u' && c != 'U' {
iter.reportError("ReadString",
`expects \u after utf16 surrogate, but \u not found`)
return
}
r2 := iter.readU4()
if iter.Error != nil {
return
}
combined := utf16.DecodeRune(r, r2)
str = appendRune(str, combined)
} else {
str = appendRune(str, r)
}
case '"':
str = append(str, '"')
case '\\':
str = append(str, '\\')
case '/':
str = append(str, '/')
case 'b':
str = append(str, '\b')
case 'f':
str = append(str, '\f')
case 'n':
str = append(str, '\n')
case 'r':
str = append(str, '\r')
case 't':
str = append(str, '\t')
default:
iter.reportError("ReadString",
`invalid escape char after \`)
return
}
} else {
str = append(str, c)
}
}
return
}
func (iter *Iterator) ReadStringAsSlice() (ret []byte) {
c := iter.nextToken()
if c == '"' {
for i := iter.head; i < iter.tail; i++ {
// require ascii string and no escape
// for: field name, base64, number
if iter.buf[i] == '"' {
// fast path: reuse the underlying buffer
ret = iter.buf[iter.head : i]
iter.head = i + 1
return ret
}
}
readLen := iter.tail - iter.head
copied := make([]byte, readLen, readLen * 2)
copy(copied, iter.buf[iter.head:iter.tail])
iter.head = iter.tail
for iter.Error == nil {
c := iter.readByte()
if c == '"' {
return copied
}
copied = append(copied, c)
}
return copied
}
iter.reportError("ReadString", `expects " or n`)
return
}
func (iter *Iterator) readU4() (ret rune) {
for i := 0; i < 4; i++ {
c := iter.readByte()
if iter.Error != nil {
return
}
if c >= '0' && c <= '9' {
ret = ret * 16 + rune(c - '0')
} else if c >= 'a' && c <= 'f' {
ret = ret * 16 + rune(c - 'a' + 10)
} else if c >= 'A' && c <= 'F' {
ret = ret * 16 + rune(c - 'A' + 10)
} else {
iter.reportError("readU4", "expects 0~9 or a~f")
return
}
}
return ret
}
const (
t1 = 0x00 // 0000 0000
tx = 0x80 // 1000 0000
t2 = 0xC0 // 1100 0000
t3 = 0xE0 // 1110 0000
t4 = 0xF0 // 1111 0000
t5 = 0xF8 // 1111 1000
maskx = 0x3F // 0011 1111
mask2 = 0x1F // 0001 1111
mask3 = 0x0F // 0000 1111
mask4 = 0x07 // 0000 0111
rune1Max = 1 << 7 - 1
rune2Max = 1 << 11 - 1
rune3Max = 1 << 16 - 1
surrogateMin = 0xD800
surrogateMax = 0xDFFF
maxRune = '\U0010FFFF' // Maximum valid Unicode code point.
runeError = '\uFFFD' // the "error" Rune or "Unicode replacement character"
)
func appendRune(p []byte, r rune) []byte {
// Negative values are erroneous. Making it unsigned addresses the problem.
switch i := uint32(r); {
case i <= rune1Max:
p = append(p, byte(r))
return p
case i <= rune2Max:
p = append(p, t2 | byte(r >> 6))
p = append(p, tx | byte(r) & maskx)
return p
case i > maxRune, surrogateMin <= i && i <= surrogateMax:
r = runeError
fallthrough
case i <= rune3Max:
p = append(p, t3 | byte(r >> 12))
p = append(p, tx | byte(r >> 6) & maskx)
p = append(p, tx | byte(r) & maskx)
return p
default:
p = append(p, t4 | byte(r >> 18))
p = append(p, tx | byte(r >> 12) & maskx)
p = append(p, tx | byte(r >> 6) & maskx)
p = append(p, tx | byte(r) & maskx)
return p
}
}

532
feature_reflect.go Normal file
View File

@ -0,0 +1,532 @@
package jsoniter
import (
"fmt"
"reflect"
"sync/atomic"
"unsafe"
"encoding/json"
)
/*
Reflection on type to create decoders, which is then cached
Reflection on value is avoided as we can, as the reflect.Value itself will allocate, with following exceptions
1. create instance of new value, for example *int will need a int to be allocated
2. append to slice, if the existing cap is not enough, allocate will be done using Reflect.New
3. assignment to map, both key and value will be reflect.Value
For a simple struct binding, it will be reflect.Value free and allocation free
*/
type Decoder interface {
decode(ptr unsafe.Pointer, iter *Iterator)
}
type Encoder interface {
isEmpty(ptr unsafe.Pointer) bool
encode(ptr unsafe.Pointer, stream *Stream)
encodeInterface(val interface{}, stream *Stream)
}
func writeToStream(val interface{}, stream *Stream, encoder Encoder) {
e := (*emptyInterface)(unsafe.Pointer(&val))
if reflect.TypeOf(val).Kind() == reflect.Ptr {
encoder.encode(unsafe.Pointer(&e.word), stream)
} else {
encoder.encode(e.word, stream)
}
}
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
type EncoderFunc func(ptr unsafe.Pointer, stream *Stream)
type ExtensionFunc func(typ reflect.Type, field *reflect.StructField) ([]string, EncoderFunc, DecoderFunc)
type funcDecoder struct {
fun DecoderFunc
}
func (decoder *funcDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.fun(ptr, iter)
}
type funcEncoder struct {
fun EncoderFunc
}
func (encoder *funcEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
encoder.fun(ptr, stream)
}
func (encoder *funcEncoder) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (encoder *funcEncoder) isEmpty(ptr unsafe.Pointer) bool {
return false
}
var DECODERS unsafe.Pointer
var ENCODERS unsafe.Pointer
var typeDecoders map[string]Decoder
var fieldDecoders map[string]Decoder
var typeEncoders map[string]Encoder
var fieldEncoders map[string]Encoder
var extensions []ExtensionFunc
var jsonNumberType reflect.Type
var jsonRawMessageType reflect.Type
var anyType reflect.Type
var marshalerType reflect.Type
var unmarshalerType reflect.Type
func init() {
typeDecoders = map[string]Decoder{}
fieldDecoders = map[string]Decoder{}
typeEncoders = map[string]Encoder{}
fieldEncoders = map[string]Encoder{}
extensions = []ExtensionFunc{}
atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
atomic.StorePointer(&ENCODERS, unsafe.Pointer(&map[string]Encoder{}))
jsonNumberType = reflect.TypeOf((*json.Number)(nil)).Elem()
jsonRawMessageType = reflect.TypeOf((*json.RawMessage)(nil)).Elem()
anyType = reflect.TypeOf((*Any)(nil)).Elem()
marshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
}
func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
done := false
for !done {
ptr := atomic.LoadPointer(&DECODERS)
cache := *(*map[reflect.Type]Decoder)(ptr)
copied := map[reflect.Type]Decoder{}
for k, v := range cache {
copied[k] = v
}
copied[cacheKey] = decoder
done = atomic.CompareAndSwapPointer(&DECODERS, ptr, unsafe.Pointer(&copied))
}
}
func addEncoderToCache(cacheKey reflect.Type, encoder Encoder) {
done := false
for !done {
ptr := atomic.LoadPointer(&ENCODERS)
cache := *(*map[reflect.Type]Encoder)(ptr)
copied := map[reflect.Type]Encoder{}
for k, v := range cache {
copied[k] = v
}
copied[cacheKey] = encoder
done = atomic.CompareAndSwapPointer(&ENCODERS, ptr, unsafe.Pointer(&copied))
}
}
func getDecoderFromCache(cacheKey reflect.Type) Decoder {
ptr := atomic.LoadPointer(&DECODERS)
cache := *(*map[reflect.Type]Decoder)(ptr)
return cache[cacheKey]
}
func getEncoderFromCache(cacheKey reflect.Type) Encoder {
ptr := atomic.LoadPointer(&ENCODERS)
cache := *(*map[reflect.Type]Encoder)(ptr)
return cache[cacheKey]
}
// RegisterTypeDecoder can register a type for json object
func RegisterTypeDecoder(typ string, fun DecoderFunc) {
typeDecoders[typ] = &funcDecoder{fun}
}
// RegisterFieldDecoder can register a type for json field
func RegisterFieldDecoder(typ string, field string, fun DecoderFunc) {
fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = &funcDecoder{fun}
}
func RegisterTypeEncoder(typ string, fun EncoderFunc) {
typeEncoders[typ] = &funcEncoder{fun}
}
func RegisterFieldEncoder(typ string, field string, fun EncoderFunc) {
fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = &funcEncoder{fun}
}
// RegisterExtension can register a custom extension
func RegisterExtension(extension ExtensionFunc) {
extensions = append(extensions, extension)
}
// CleanDecoders cleans decoders registered
func CleanDecoders() {
typeDecoders = map[string]Decoder{}
fieldDecoders = map[string]Decoder{}
}
func CleanEncoders() {
typeEncoders = map[string]Encoder{}
fieldEncoders = map[string]Encoder{}
}
type optionalDecoder struct {
valueType reflect.Type
valueDecoder Decoder
}
func (decoder *optionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() {
*((*unsafe.Pointer)(ptr)) = nil
} else {
if *((*unsafe.Pointer)(ptr)) == nil {
// pointer to null, we have to allocate memory to hold the value
value := reflect.New(decoder.valueType)
decoder.valueDecoder.decode(unsafe.Pointer(value.Pointer()), iter)
*((*uintptr)(ptr)) = value.Pointer()
} else {
// reuse existing instance
decoder.valueDecoder.decode(*((*unsafe.Pointer)(ptr)), iter)
}
}
}
type optionalEncoder struct {
valueEncoder Encoder
}
func (encoder *optionalEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
if *((*unsafe.Pointer)(ptr)) == nil {
stream.WriteNil()
} else {
encoder.valueEncoder.encode(*((*unsafe.Pointer)(ptr)), stream)
}
}
func (encoder *optionalEncoder) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (encoder *optionalEncoder) isEmpty(ptr unsafe.Pointer) bool {
if *((*unsafe.Pointer)(ptr)) == nil {
return true
} else {
return encoder.valueEncoder.isEmpty(*((*unsafe.Pointer)(ptr)))
}
}
type placeholderEncoder struct {
valueEncoder Encoder
}
func (encoder *placeholderEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
encoder.valueEncoder.encode(ptr, stream)
}
func (encoder *placeholderEncoder) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (encoder *placeholderEncoder) isEmpty(ptr unsafe.Pointer) bool {
return encoder.valueEncoder.isEmpty(ptr)
}
type placeholderDecoder struct {
valueDecoder Decoder
}
func (decoder *placeholderDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.valueDecoder.decode(ptr, iter)
}
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ unsafe.Pointer
word unsafe.Pointer
}
// emptyInterface is the header for an interface with method (not interface{})
type nonEmptyInterface struct {
// see ../runtime/iface.go:/Itab
itab *struct {
ityp unsafe.Pointer // static interface type
typ unsafe.Pointer // dynamic concrete type
link unsafe.Pointer
bad int32
unused int32
fun [100000]unsafe.Pointer // method table
}
word unsafe.Pointer
}
// Read converts an Iterator instance into go interface, same as json.Unmarshal
func (iter *Iterator) ReadVal(obj interface{}) {
typ := reflect.TypeOf(obj)
cacheKey := typ.Elem()
cachedDecoder := getDecoderFromCache(cacheKey)
if cachedDecoder == nil {
decoder, err := decoderOfType(cacheKey)
if err != nil {
iter.Error = err
return
}
cachedDecoder = decoder
addDecoderToCache(cacheKey, decoder)
}
e := (*emptyInterface)(unsafe.Pointer(&obj))
cachedDecoder.decode(e.word, iter)
}
func (stream *Stream) WriteVal(val interface{}) {
if nil == val {
stream.WriteNil()
return
}
typ := reflect.TypeOf(val)
cacheKey := typ
cachedEncoder := getEncoderFromCache(cacheKey)
if cachedEncoder == nil {
encoder, err := encoderOfType(cacheKey)
if err != nil {
stream.Error = err
return
}
cachedEncoder = encoder
addEncoderToCache(cacheKey, encoder)
}
cachedEncoder.encodeInterface(val, stream)
}
type prefix string
func (p prefix) addToDecoder(decoder Decoder, err error) (Decoder, error) {
if err != nil {
return nil, fmt.Errorf("%s: %s", p, err.Error())
}
return decoder, err
}
func (p prefix) addToEncoder(encoder Encoder, err error) (Encoder, error) {
if err != nil {
return nil, fmt.Errorf("%s: %s", p, err.Error())
}
return encoder, err
}
func decoderOfType(typ reflect.Type) (Decoder, error) {
typeName := typ.String()
typeDecoder := typeDecoders[typeName]
if typeDecoder != nil {
return typeDecoder, nil
}
if typ.Kind() == reflect.Ptr {
typeDecoder := typeDecoders[typ.Elem().String()]
if typeDecoder != nil {
return &optionalDecoder{typ.Elem(),typeDecoder}, nil
}
}
cacheKey := typ
cachedDecoder := getDecoderFromCache(cacheKey)
if cachedDecoder != nil {
return cachedDecoder, nil
}
placeholder := &placeholderDecoder{}
addDecoderToCache(cacheKey, placeholder)
newDecoder, err := createDecoderOfType(typ)
placeholder.valueDecoder = newDecoder
addDecoderToCache(cacheKey, newDecoder)
return newDecoder, err
}
func createDecoderOfType(typ reflect.Type) (Decoder, error) {
if typ.AssignableTo(jsonRawMessageType) {
return &jsonRawMessageCodec{}, nil
}
if typ.AssignableTo(jsonNumberType) {
return &jsonNumberCodec{}, nil
}
if typ.ConvertibleTo(unmarshalerType) {
templateInterface := reflect.New(typ).Elem().Interface()
return &optionalDecoder{typ, &unmarshalerDecoder{extractInterface(templateInterface)}}, nil
}
if typ.ConvertibleTo(anyType) {
return &anyCodec{}, nil
}
switch typ.Kind() {
case reflect.String:
return &stringCodec{}, nil
case reflect.Int:
return &intCodec{}, nil
case reflect.Int8:
return &int8Codec{}, nil
case reflect.Int16:
return &int16Codec{}, nil
case reflect.Int32:
return &int32Codec{}, nil
case reflect.Int64:
return &int64Codec{}, nil
case reflect.Uint:
return &uintCodec{}, nil
case reflect.Uint8:
return &uint8Codec{}, nil
case reflect.Uint16:
return &uint16Codec{}, nil
case reflect.Uint32:
return &uint32Codec{}, nil
case reflect.Uint64:
return &uint64Codec{}, nil
case reflect.Float32:
return &float32Codec{}, nil
case reflect.Float64:
return &float64Codec{}, nil
case reflect.Bool:
return &boolCodec{}, nil
case reflect.Interface:
if typ.NumMethod() == 0 {
return &emptyInterfaceCodec{}, nil
} else {
return &nonEmptyInterfaceCodec{}, nil
}
case reflect.Struct:
return prefix(fmt.Sprintf("[%s]", typ.String())).addToDecoder(decoderOfStruct(typ))
case reflect.Slice:
return prefix("[slice]").addToDecoder(decoderOfSlice(typ))
case reflect.Map:
return prefix("[map]").addToDecoder(decoderOfMap(typ))
case reflect.Ptr:
return prefix("[optional]").addToDecoder(decoderOfOptional(typ))
default:
return nil, fmt.Errorf("unsupported type: %v", typ)
}
}
func encoderOfType(typ reflect.Type) (Encoder, error) {
typeName := typ.String()
typeEncoder := typeEncoders[typeName]
if typeEncoder != nil {
return typeEncoder, nil
}
if typ.Kind() == reflect.Ptr {
typeEncoder := typeEncoders[typ.Elem().String()]
if typeEncoder != nil {
return &optionalEncoder{typeEncoder}, nil
}
}
cacheKey := typ
cachedEncoder := getEncoderFromCache(cacheKey)
if cachedEncoder != nil {
return cachedEncoder, nil
}
placeholder := &placeholderEncoder{}
addEncoderToCache(cacheKey, placeholder)
newEncoder, err := createEncoderOfType(typ)
placeholder.valueEncoder = newEncoder
addEncoderToCache(cacheKey, newEncoder)
return newEncoder, err
}
func createEncoderOfType(typ reflect.Type) (Encoder, error) {
if typ.AssignableTo(jsonRawMessageType) {
return &jsonRawMessageCodec{}, nil
}
if typ.AssignableTo(jsonNumberType) {
return &jsonNumberCodec{}, nil
}
if typ.ConvertibleTo(marshalerType) {
templateInterface := reflect.New(typ).Elem().Interface()
return &marshalerEncoder{extractInterface(templateInterface)}, nil
}
if typ.ConvertibleTo(anyType) {
return &anyCodec{}, nil
}
kind := typ.Kind()
switch kind {
case reflect.String:
return &stringCodec{}, nil
case reflect.Int:
return &intCodec{}, nil
case reflect.Int8:
return &int8Codec{}, nil
case reflect.Int16:
return &int16Codec{}, nil
case reflect.Int32:
return &int32Codec{}, nil
case reflect.Int64:
return &int64Codec{}, nil
case reflect.Uint:
return &uintCodec{}, nil
case reflect.Uint8:
return &uint8Codec{}, nil
case reflect.Uint16:
return &uint16Codec{}, nil
case reflect.Uint32:
return &uint32Codec{}, nil
case reflect.Uint64:
return &uint64Codec{}, nil
case reflect.Float32:
return &float32Codec{}, nil
case reflect.Float64:
return &float64Codec{}, nil
case reflect.Bool:
return &boolCodec{}, nil
case reflect.Interface:
if typ.NumMethod() == 0 {
return &emptyInterfaceCodec{}, nil
} else {
return &nonEmptyInterfaceCodec{}, nil
}
case reflect.Struct:
return prefix(fmt.Sprintf("[%s]", typ.String())).addToEncoder(encoderOfStruct(typ))
case reflect.Slice:
return prefix("[slice]").addToEncoder(encoderOfSlice(typ))
case reflect.Map:
return prefix("[map]").addToEncoder(encoderOfMap(typ))
case reflect.Ptr:
return prefix("[optional]").addToEncoder(encoderOfOptional(typ))
default:
return nil, fmt.Errorf("unsupported type: %v", typ)
}
}
func decoderOfOptional(typ reflect.Type) (Decoder, error) {
elemType := typ.Elem()
decoder, err := decoderOfType(elemType)
if err != nil {
return nil, err
}
return &optionalDecoder{elemType, decoder}, nil
}
func encoderOfOptional(typ reflect.Type) (Encoder, error) {
elemType := typ.Elem()
decoder, err := encoderOfType(elemType)
if err != nil {
return nil, err
}
return &optionalEncoder{ decoder}, nil
}
func decoderOfMap(typ reflect.Type) (Decoder, error) {
decoder, err := decoderOfType(typ.Elem())
if err != nil {
return nil, err
}
mapInterface := reflect.New(typ).Interface()
return &mapDecoder{typ, typ.Elem(), decoder, extractInterface(mapInterface)}, nil
}
func extractInterface(val interface{}) emptyInterface {
return *((*emptyInterface)(unsafe.Pointer(&val)))
}
func encoderOfMap(typ reflect.Type) (Encoder, error) {
elemType := typ.Elem()
encoder, err := encoderOfType(elemType)
if err != nil {
return nil, err
}
mapInterface := reflect.New(typ).Elem().Interface()
if elemType.Kind() == reflect.Interface && elemType.NumMethod() == 0 {
return &mapInterfaceEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
} else {
return &mapEncoder{typ, elemType, encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
}
}

158
feature_reflect_array.go Normal file
View File

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

105
feature_reflect_map.go Normal file
View File

@ -0,0 +1,105 @@
package jsoniter
import (
"unsafe"
"reflect"
)
type mapDecoder struct {
mapType reflect.Type
elemType reflect.Type
elemDecoder Decoder
mapInterface emptyInterface
}
func (decoder *mapDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
// dark magic to cast unsafe.Pointer back to interface{} using reflect.Type
mapInterface := decoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface).Elem()
if realVal.IsNil() {
realVal.Set(reflect.MakeMap(realVal.Type()))
}
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
elem := reflect.New(decoder.elemType)
decoder.elemDecoder.decode(unsafe.Pointer(elem.Pointer()), iter)
// to put into map, we have to use reflection
realVal.SetMapIndex(reflect.ValueOf(string([]byte(field))), elem.Elem())
}
}
type mapEncoder struct {
mapType reflect.Type
elemType reflect.Type
elemEncoder Encoder
mapInterface emptyInterface
}
func (encoder *mapEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
mapInterface := encoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface)
stream.WriteObjectStart()
for i, key := range realVal.MapKeys() {
if i != 0 {
stream.WriteMore()
}
stream.WriteObjectField(key.String())
val := realVal.MapIndex(key).Interface()
encoder.elemEncoder.encodeInterface(val, stream)
}
stream.WriteObjectEnd()
}
func (encoder *mapEncoder) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (encoder *mapEncoder) isEmpty(ptr unsafe.Pointer) bool {
mapInterface := encoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface)
return realVal.Len() == 0
}
type mapInterfaceEncoder struct {
mapType reflect.Type
elemType reflect.Type
elemEncoder Encoder
mapInterface emptyInterface
}
func (encoder *mapInterfaceEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
mapInterface := encoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface)
stream.WriteObjectStart()
for i, key := range realVal.MapKeys() {
if i != 0 {
stream.WriteMore()
}
stream.WriteObjectField(key.String())
val := realVal.MapIndex(key).Interface()
encoder.elemEncoder.encode(unsafe.Pointer(&val), stream)
}
stream.WriteObjectEnd()
}
func (encoder *mapInterfaceEncoder) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (encoder *mapInterfaceEncoder) isEmpty(ptr unsafe.Pointer) bool {
mapInterface := encoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface)
return realVal.Len() == 0
}

450
feature_reflect_native.go Normal file
View File

@ -0,0 +1,450 @@
package jsoniter
import (
"unsafe"
"encoding/json"
)
type stringCodec struct {
}
func (codec *stringCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*string)(ptr)) = iter.ReadString()
}
func (codec *stringCodec) encode(ptr unsafe.Pointer, stream *Stream) {
str := *((*string)(ptr))
stream.WriteString(str)
}
func (encoder *stringCodec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *stringCodec) isEmpty(ptr unsafe.Pointer) bool {
return *((*string)(ptr)) == ""
}
type intCodec struct {
}
func (codec *intCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*int)(ptr)) = iter.ReadInt()
}
func (codec *intCodec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteInt(*((*int)(ptr)))
}
func (encoder *intCodec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *intCodec) isEmpty(ptr unsafe.Pointer) bool {
return *((*int)(ptr)) == 0
}
type int8Codec struct {
}
func (codec *int8Codec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*int8)(ptr)) = iter.ReadInt8()
}
func (codec *int8Codec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteInt8(*((*int8)(ptr)))
}
func (encoder *int8Codec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *int8Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*int8)(ptr)) == 0
}
type int16Codec struct {
}
func (codec *int16Codec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*int16)(ptr)) = iter.ReadInt16()
}
func (codec *int16Codec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteInt16(*((*int16)(ptr)))
}
func (encoder *int16Codec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *int16Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*int16)(ptr)) == 0
}
type int32Codec struct {
}
func (codec *int32Codec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*int32)(ptr)) = iter.ReadInt32()
}
func (codec *int32Codec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteInt32(*((*int32)(ptr)))
}
func (encoder *int32Codec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *int32Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*int32)(ptr)) == 0
}
type int64Codec struct {
}
func (codec *int64Codec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*int64)(ptr)) = iter.ReadInt64()
}
func (codec *int64Codec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteInt64(*((*int64)(ptr)))
}
func (encoder *int64Codec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *int64Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*int64)(ptr)) == 0
}
type uintCodec struct {
}
func (codec *uintCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*uint)(ptr)) = iter.ReadUint()
}
func (codec *uintCodec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint(*((*uint)(ptr)))
}
func (encoder *uintCodec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *uintCodec) isEmpty(ptr unsafe.Pointer) bool {
return *((*uint)(ptr)) == 0
}
type uint8Codec struct {
}
func (codec *uint8Codec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*uint8)(ptr)) = iter.ReadUint8()
}
func (codec *uint8Codec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint8(*((*uint8)(ptr)))
}
func (encoder *uint8Codec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *uint8Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*uint8)(ptr)) == 0
}
type uint16Codec struct {
}
func (decoder *uint16Codec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*uint16)(ptr)) = iter.ReadUint16()
}
func (codec *uint16Codec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint16(*((*uint16)(ptr)))
}
func (encoder *uint16Codec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *uint16Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*uint16)(ptr)) == 0
}
type uint32Codec struct {
}
func (codec *uint32Codec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*uint32)(ptr)) = iter.ReadUint32()
}
func (codec *uint32Codec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint32(*((*uint32)(ptr)))
}
func (encoder *uint32Codec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *uint32Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*uint32)(ptr)) == 0
}
type uint64Codec struct {
}
func (codec *uint64Codec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*uint64)(ptr)) = iter.ReadUint64()
}
func (codec *uint64Codec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteUint64(*((*uint64)(ptr)))
}
func (encoder *uint64Codec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *uint64Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*uint64)(ptr)) == 0
}
type float32Codec struct {
}
func (codec *float32Codec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*float32)(ptr)) = iter.ReadFloat32()
}
func (codec *float32Codec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteFloat32(*((*float32)(ptr)))
}
func (encoder *float32Codec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *float32Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*float32)(ptr)) == 0
}
type float64Codec struct {
}
func (codec *float64Codec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*float64)(ptr)) = iter.ReadFloat64()
}
func (codec *float64Codec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteFloat64(*((*float64)(ptr)))
}
func (encoder *float64Codec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *float64Codec) isEmpty(ptr unsafe.Pointer) bool {
return *((*float64)(ptr)) == 0
}
type boolCodec struct {
}
func (codec *boolCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*bool)(ptr)) = iter.ReadBool()
}
func (codec *boolCodec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteBool(*((*bool)(ptr)))
}
func (encoder *boolCodec) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (codec *boolCodec) isEmpty(ptr unsafe.Pointer) bool {
return !(*((*bool)(ptr)))
}
type emptyInterfaceCodec struct {
}
func (codec *emptyInterfaceCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*interface{})(ptr)) = iter.Read()
}
func (codec *emptyInterfaceCodec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteVal(*((*interface{})(ptr)))
}
func (encoder *emptyInterfaceCodec) encodeInterface(val interface{}, stream *Stream) {
stream.WriteVal(val)
}
func (codec *emptyInterfaceCodec) isEmpty(ptr unsafe.Pointer) bool {
return ptr == nil
}
type nonEmptyInterfaceCodec struct {
}
func (codec *nonEmptyInterfaceCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
nonEmptyInterface := (*nonEmptyInterface)(ptr)
var i interface{}
e := (*emptyInterface)(unsafe.Pointer(&i))
e.typ = nonEmptyInterface.itab.typ
e.word = nonEmptyInterface.word
iter.ReadVal(&i)
nonEmptyInterface.word = e.word
}
func (codec *nonEmptyInterfaceCodec) encode(ptr unsafe.Pointer, stream *Stream) {
nonEmptyInterface := (*nonEmptyInterface)(ptr)
var i interface{}
e := (*emptyInterface)(unsafe.Pointer(&i))
e.typ = nonEmptyInterface.itab.typ
e.word = nonEmptyInterface.word
stream.WriteVal(i)
}
func (encoder *nonEmptyInterfaceCodec) encodeInterface(val interface{}, stream *Stream) {
stream.WriteVal(val)
}
func (codec *nonEmptyInterfaceCodec) isEmpty(ptr unsafe.Pointer) bool {
nonEmptyInterface := (*nonEmptyInterface)(ptr)
return nonEmptyInterface.word == nil
}
type anyCodec struct {
}
func (codec *anyCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*Any)(ptr)) = iter.ReadAny()
}
func (codec *anyCodec) encode(ptr unsafe.Pointer, stream *Stream) {
(*((*Any)(ptr))).WriteTo(stream)
}
func (encoder *anyCodec) encodeInterface(val interface{}, stream *Stream) {
(val.(Any)).WriteTo(stream)
}
func (encoder *anyCodec) isEmpty(ptr unsafe.Pointer) bool {
return (*((*Any)(ptr))).Size() == 0
}
type jsonNumberCodec struct {
}
func (codec *jsonNumberCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString()))
}
func (codec *jsonNumberCodec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteRaw(string(*((*json.Number)(ptr))))
}
func (encoder *jsonNumberCodec) encodeInterface(val interface{}, stream *Stream) {
stream.WriteRaw(string(val.(json.Number)))
}
func (encoder *jsonNumberCodec) isEmpty(ptr unsafe.Pointer) bool {
return len(*((*json.Number)(ptr))) == 0
}
type jsonRawMessageCodec struct {
}
func (codec *jsonRawMessageCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*json.RawMessage)(ptr)) = json.RawMessage(iter.SkipAndReturnBytes())
}
func (codec *jsonRawMessageCodec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteRaw(string(*((*json.RawMessage)(ptr))))
}
func (encoder *jsonRawMessageCodec) encodeInterface(val interface{}, stream *Stream) {
stream.WriteRaw(string(val.(json.RawMessage)))
}
func (encoder *jsonRawMessageCodec) isEmpty(ptr unsafe.Pointer) bool {
return len(*((*json.RawMessage)(ptr))) == 0
}
type stringNumberDecoder struct {
elemDecoder Decoder
}
func (decoder *stringNumberDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
c := iter.nextToken()
if c != '"' {
iter.reportError("stringNumberDecoder", `expect "`)
return
}
decoder.elemDecoder.decode(ptr, iter)
if iter.Error != nil {
return
}
c = iter.readByte()
if c != '"' {
iter.reportError("stringNumberDecoder", `expect "`)
return
}
}
type marshalerEncoder struct {
templateInterface emptyInterface
}
func (encoder *marshalerEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
templateInterface := encoder.templateInterface
templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
marshaler := (*realInterface).(json.Marshaler)
bytes, err := marshaler.MarshalJSON()
if err != nil {
stream.Error = err
} else {
stream.Write(bytes)
}
}
func (encoder *marshalerEncoder) encodeInterface(val interface{}, stream *Stream) {
writeToStream(val, stream, encoder)
}
func (encoder *marshalerEncoder) isEmpty(ptr unsafe.Pointer) bool {
templateInterface := encoder.templateInterface
templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
marshaler := (*realInterface).(json.Marshaler)
bytes, err := marshaler.MarshalJSON()
if err != nil {
return true
} else {
return len(bytes) > 0
}
}
type unmarshalerDecoder struct {
templateInterface emptyInterface
}
func (decoder *unmarshalerDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
templateInterface := decoder.templateInterface
templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
unmarshaler := (*realInterface).(json.Unmarshaler)
bytes := iter.SkipAndReturnBytes()
err := unmarshaler.UnmarshalJSON(bytes)
if err != nil {
iter.reportError("unmarshaler", err.Error())
}
}

1142
feature_reflect_object.go Normal file

File diff suppressed because it is too large Load Diff

313
feature_stream.go Normal file
View File

@ -0,0 +1,313 @@
package jsoniter
import (
"io"
)
type Stream struct {
out io.Writer
buf []byte
n int
Error error
indention int
IndentionStep int
}
func NewStream(out io.Writer, bufSize int) *Stream {
return &Stream{out, make([]byte, bufSize), 0, nil, 0, 0}
}
func (b *Stream) Reset(out io.Writer) {
b.out = out
b.n = 0
}
// Available returns how many bytes are unused in the buffer.
func (b *Stream) Available() int {
return len(b.buf) - b.n
}
// Buffered returns the number of bytes that have been written into the current buffer.
func (b *Stream) Buffered() int {
return b.n
}
// Write writes the contents of p into the buffer.
// It returns the number of bytes written.
// If nn < len(p), it also returns an error explaining
// why the write is short.
func (b *Stream) Write(p []byte) (nn int, err error) {
for len(p) > b.Available() && b.Error == nil {
var n int
if b.Buffered() == 0 {
// Large write, empty buffer.
// Write directly from p to avoid copy.
n, b.Error = b.out.Write(p)
} else {
n = copy(b.buf[b.n:], p)
b.n += n
b.Flush()
}
nn += n
p = p[n:]
}
if b.Error != nil {
return nn, b.Error
}
n := copy(b.buf[b.n:], p)
b.n += n
nn += n
return nn, nil
}
// WriteByte writes a single byte.
func (b *Stream) writeByte(c byte) {
if b.Error != nil {
return
}
if b.Available() <= 0 && b.Flush() != nil {
return
}
b.buf[b.n] = c
b.n++
}
func (b *Stream) writeTwoBytes(c1 byte, c2 byte) {
if b.Error != nil {
return
}
if b.Available() <= 1 && b.Flush() != nil {
return
}
b.buf[b.n] = c1
b.buf[b.n + 1] = c2
b.n += 2
}
func (b *Stream) writeThreeBytes(c1 byte, c2 byte, c3 byte) {
if b.Error != nil {
return
}
if b.Available() <= 2 && b.Flush() != nil {
return
}
b.buf[b.n] = c1
b.buf[b.n + 1] = c2
b.buf[b.n + 2] = c3
b.n += 3
}
func (b *Stream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) {
if b.Error != nil {
return
}
if b.Available() <= 3 && b.Flush() != nil {
return
}
b.buf[b.n] = c1
b.buf[b.n + 1] = c2
b.buf[b.n + 2] = c3
b.buf[b.n + 3] = c4
b.n += 4
}
func (b *Stream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) {
if b.Error != nil {
return
}
if b.Available() <= 3 && b.Flush() != nil {
return
}
b.buf[b.n] = c1
b.buf[b.n + 1] = c2
b.buf[b.n + 2] = c3
b.buf[b.n + 3] = c4
b.buf[b.n + 4] = c5
b.n += 5
}
// Flush writes any buffered data to the underlying io.Writer.
func (b *Stream) Flush() error {
if b.Error != nil {
return b.Error
}
if b.n == 0 {
return nil
}
n, err := b.out.Write(b.buf[0:b.n])
if n < b.n && err == nil {
err = io.ErrShortWrite
}
if err != nil {
if n > 0 && n < b.n {
copy(b.buf[0:b.n - n], b.buf[n:b.n])
}
b.n -= n
b.Error = err
return err
}
b.n = 0
return nil
}
func (b *Stream) WriteRaw(s string) {
for len(s) > b.Available() && b.Error == nil {
n := copy(b.buf[b.n:], s)
b.n += n
s = s[n:]
b.Flush()
}
if b.Error != nil {
return
}
n := copy(b.buf[b.n:], s)
b.n += n
}
func (stream *Stream) WriteString(s string) {
valLen := len(s)
toWriteLen := valLen
bufLengthMinusTwo := len(stream.buf) - 2 // make room for the quotes
if stream.n + toWriteLen > bufLengthMinusTwo {
toWriteLen = bufLengthMinusTwo - stream.n
}
if toWriteLen < 0 {
stream.Flush()
if stream.n + toWriteLen > bufLengthMinusTwo {
toWriteLen = bufLengthMinusTwo - stream.n
}
}
n := stream.n
stream.buf[n] = '"'
n++
// write string, the fast path, without utf8 and escape support
i := 0
for ; i < toWriteLen; i++ {
c := s[i]
if c > 31 && c != '"' && c != '\\' {
stream.buf[n] = c
n++
} else {
break;
}
}
if i == valLen {
stream.buf[n] = '"'
n++
stream.n = n
return
}
stream.n = n
// for the remaining parts, we process them char by char
stream.writeStringSlowPath(s, i, valLen);
stream.writeByte('"')
}
func (stream *Stream) writeStringSlowPath(s string, i int, valLen int) {
for ; i < valLen; i++ {
c := s[i]
switch (c) {
case '"':
stream.writeTwoBytes('\\', '"')
case '\\':
stream.writeTwoBytes('\\', '\\')
case '\b':
stream.writeTwoBytes('\\', 'b')
case '\f':
stream.writeTwoBytes('\\', 'f')
case '\n':
stream.writeTwoBytes('\\', 'n')
case '\r':
stream.writeTwoBytes('\\', 'r')
case '\t':
stream.writeTwoBytes('\\', 't')
default:
stream.writeByte(c);
}
}
}
func (stream *Stream) WriteNil() {
stream.writeFourBytes('n', 'u', 'l', 'l')
}
func (stream *Stream) WriteTrue() {
stream.writeFourBytes('t', 'r', 'u', 'e')
}
func (stream *Stream) WriteFalse() {
stream.writeFiveBytes('f', 'a', 'l', 's', 'e')
}
func (stream *Stream) WriteBool(val bool) {
if val {
stream.WriteTrue()
} else {
stream.WriteFalse()
}
}
func (stream *Stream) WriteObjectStart() {
stream.indention += stream.IndentionStep
stream.writeByte('{')
stream.writeIndention(0)
}
func (stream *Stream) WriteObjectField(field string) {
stream.WriteString(field)
stream.writeByte(':')
}
func (stream *Stream) WriteObjectEnd() {
stream.writeIndention(stream.IndentionStep)
stream.indention -= stream.IndentionStep
stream.writeByte('}')
}
func (stream *Stream) WriteEmptyObject() {
stream.writeByte('{')
stream.writeByte('}')
}
func (stream *Stream) WriteMore() {
stream.writeByte(',')
stream.writeIndention(0)
}
func (stream *Stream) WriteArrayStart() {
stream.indention += stream.IndentionStep
stream.writeByte('[')
stream.writeIndention(0)
}
func (stream *Stream) WriteEmptyArray() {
stream.writeByte('[')
stream.writeByte(']')
}
func (stream *Stream) WriteArrayEnd() {
stream.writeIndention(stream.IndentionStep)
stream.indention -= stream.IndentionStep
stream.writeByte(']')
}
func (stream *Stream) writeIndention(delta int) {
if (stream.indention == 0) {
return
}
stream.writeByte('\n')
toWrite := stream.indention - delta
i := 0
for {
for ; i < toWrite && stream.n < len(stream.buf); i++ {
stream.buf[stream.n] = ' '
stream.n ++
}
if i == toWrite {
break;
} else {
stream.Flush()
}
}
}

92
feature_stream_float.go Normal file
View File

@ -0,0 +1,92 @@
package jsoniter
import (
"strconv"
"unsafe"
)
var POW10 []uint64
func init() {
POW10 = []uint64{1, 10, 100, 1000, 10000, 100000, 1000000}
}
func (stream *Stream) WriteFloat32(val float32) {
stream.WriteRaw(strconv.FormatFloat(float64(val), 'f', -1, 32))
}
func (stream *Stream) WriteFloat32Lossy(val float32) {
if val < 0 {
stream.writeByte('-')
val = -val
}
if val > 0x4ffffff {
stream.WriteRaw(strconv.FormatFloat(float64(val), 'f', -1, 32));
return
}
precision := 6
exp := uint64(1000000) // 6
lval := uint64(float64(val) * float64(exp) + 0.5)
stream.WriteUint64(lval / exp)
fval := lval % exp
if fval == 0 {
return
}
stream.writeByte('.')
if stream.Available() < 10 {
stream.Flush()
}
for p := precision - 1; p > 0 && fval < POW10[p]; p-- {
stream.writeByte('0')
}
stream.WriteUint64(fval)
for stream.buf[stream.n - 1] == '0' {
stream.n--
}
}
func (stream *Stream) WriteFloat64(val float64) {
stream.WriteRaw(strconv.FormatFloat(float64(val), 'f', -1, 64))
}
func (stream *Stream) WriteFloat64Lossy(val float64) {
if val < 0 {
stream.writeByte('-')
val = -val
}
if val > 0x4ffffff {
stream.WriteRaw(strconv.FormatFloat(val, 'f', -1, 64));
return
}
precision := 6
exp := uint64(1000000) // 6
lval := uint64(val * float64(exp) + 0.5)
stream.WriteUint64(lval / exp)
fval := lval % exp
if fval == 0 {
return
}
stream.writeByte('.')
if stream.Available() < 10 {
stream.Flush()
}
for p := precision - 1; p > 0 && fval < POW10[p]; p-- {
stream.writeByte('0')
}
stream.WriteUint64(fval)
for stream.buf[stream.n - 1] == '0' {
stream.n--
}
}
func EnableLossyFloatMarshalling() {
// for better performance
RegisterTypeEncoder("float32", func(ptr unsafe.Pointer, stream *Stream) {
val := *((*float32)(ptr))
stream.WriteFloat32Lossy(val)
})
RegisterTypeEncoder("float64", func(ptr unsafe.Pointer, stream *Stream) {
val := *((*float64)(ptr))
stream.WriteFloat64Lossy(val)
})
}

361
feature_stream_int.go Normal file
View File

@ -0,0 +1,361 @@
package jsoniter
var digits []uint8
var digitTens []uint8
var digitOnes []uint8
var DIGITS []uint32
func init() {
digits = []uint8{
'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b',
'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
}
digitTens = []uint8{
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
'3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
'4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
'5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
'6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
'7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
'8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
'9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
}
digitOnes = []uint8{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
}
DIGITS = make([]uint32, 1000)
for i := uint32(0); i < 1000; i++ {
DIGITS[i] = (((i / 100) + '0') << 16) + ((((i / 10) % 10) + '0') << 8) + i % 10 + '0';
if i < 10 {
DIGITS[i] += 2 << 24
} else if i < 100 {
DIGITS[i] += 1 << 24
}
}
}
func writeFirstBuf(buf []byte, v uint32, n int) int {
start := v >> 24
if start == 0 {
buf[n] = byte(v >> 16)
n++
buf[n] = byte(v >> 8)
n++
} else if start == 1 {
buf[n] = byte(v >> 8)
n++
}
buf[n] = byte(v)
n++
return n
}
func writeBuf(buf []byte, v uint32, n int) {
buf[n] = byte(v >> 16)
buf[n + 1] = byte(v >> 8)
buf[n + 2] = byte(v)
}
func (stream *Stream) WriteUint8(val uint8) {
if stream.Available() < 3 {
stream.Flush()
}
stream.n = writeFirstBuf(stream.buf, DIGITS[val], stream.n)
}
func (stream *Stream) WriteInt8(nval int8) {
if stream.Available() < 4 {
stream.Flush()
}
n := stream.n
var val uint8
if (nval < 0) {
val = uint8(-nval)
stream.buf[n] = '-'
n++
} else {
val = uint8(nval)
}
stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
}
func (stream *Stream) WriteUint16(val uint16) {
if stream.Available() < 5 {
stream.Flush()
}
q1 := val / 1000
if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, DIGITS[val], stream.n)
return
}
r1 := val - q1 * 1000;
n := writeFirstBuf(stream.buf, DIGITS[q1], stream.n)
writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3
return
}
func (stream *Stream) WriteInt16(nval int16) {
if stream.Available() < 6 {
stream.Flush()
}
n := stream.n
var val uint16
if (nval < 0) {
val = uint16(-nval)
stream.buf[n] = '-'
n++
} else {
val = uint16(nval)
}
q1 := val / 1000
if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
return
}
r1 := val - q1 * 1000;
n = writeFirstBuf(stream.buf, DIGITS[q1], n)
writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3
return
}
func (stream *Stream) WriteUint32(val uint32) {
if stream.Available() < 10 {
stream.Flush()
}
n := stream.n
q1 := val / 1000
if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
return
}
r1 := val - q1 * 1000;
q2 := q1 / 1000
if q2 == 0 {
n := writeFirstBuf(stream.buf, DIGITS[q1], n)
writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3
return
}
r2 := q1 - q2 * 1000
q3 := q2 / 1000
if q3 == 0 {
n = writeFirstBuf(stream.buf, DIGITS[q2], n)
} else {
r3 := q2 - q3 * 1000
stream.buf[n] = byte(q3 + '0')
n++
writeBuf(stream.buf, DIGITS[r3], n)
n += 3
}
writeBuf(stream.buf, DIGITS[r2], n)
writeBuf(stream.buf, DIGITS[r1], n + 3)
stream.n = n + 6
}
func (stream *Stream) WriteInt32(nval int32) {
if stream.Available() < 11 {
stream.Flush()
}
n := stream.n
var val uint32
if (nval < 0) {
val = uint32(-nval)
stream.buf[n] = '-'
n++
} else {
val = uint32(nval)
}
q1 := val / 1000
if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
return
}
r1 := val - q1 * 1000;
q2 := q1 / 1000
if q2 == 0 {
n := writeFirstBuf(stream.buf, DIGITS[q1], n)
writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3
return
}
r2 := q1 - q2 * 1000
q3 := q2 / 1000
if q3 == 0 {
n = writeFirstBuf(stream.buf, DIGITS[q2], n)
} else {
r3 := q2 - q3 * 1000
stream.buf[n] = byte(q3 + '0')
n++
writeBuf(stream.buf, DIGITS[r3], n)
n += 3
}
writeBuf(stream.buf, DIGITS[r2], n)
writeBuf(stream.buf, DIGITS[r1], n + 3)
stream.n = n + 6
}
func (stream *Stream) WriteUint64(val uint64) {
if stream.Available() < 20 {
stream.Flush()
}
n := stream.n
q1 := val / 1000
if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
return
}
r1 := val - q1 * 1000;
q2 := q1 / 1000
if q2 == 0 {
n := writeFirstBuf(stream.buf, DIGITS[q1], n)
writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3
return
}
r2 := q1 - q2 * 1000
q3 := q2 / 1000
if q3 == 0 {
n = writeFirstBuf(stream.buf, DIGITS[q2], n)
writeBuf(stream.buf, DIGITS[r2], n)
writeBuf(stream.buf, DIGITS[r1], n + 3)
stream.n = n + 6
return
}
r3 := q2 - q3 * 1000
q4 := q3 / 1000
if q4 == 0 {
n = writeFirstBuf(stream.buf, DIGITS[q3], n)
writeBuf(stream.buf, DIGITS[r3], n)
writeBuf(stream.buf, DIGITS[r2], n + 3)
writeBuf(stream.buf, DIGITS[r1], n + 6)
stream.n = n + 9
return
}
r4 := q3 - q4 * 1000
q5 := q4 / 1000
if q5 == 0 {
n = writeFirstBuf(stream.buf, DIGITS[q4], n)
writeBuf(stream.buf, DIGITS[r4], n)
writeBuf(stream.buf, DIGITS[r3], n + 3)
writeBuf(stream.buf, DIGITS[r2], n + 6)
writeBuf(stream.buf, DIGITS[r1], n + 9)
stream.n = n + 12
return
}
r5 := q4 - q5 * 1000
q6 := q5 / 1000
if q6 == 0 {
n = writeFirstBuf(stream.buf, DIGITS[q5], n)
} else {
n = writeFirstBuf(stream.buf, DIGITS[q6], n)
r6 := q5 - q6 * 1000
writeBuf(stream.buf, DIGITS[r6], n)
n += 3
}
writeBuf(stream.buf, DIGITS[r5], n)
writeBuf(stream.buf, DIGITS[r4], n + 3)
writeBuf(stream.buf, DIGITS[r3], n + 6)
writeBuf(stream.buf, DIGITS[r2], n + 9)
writeBuf(stream.buf, DIGITS[r1], n + 12)
stream.n = n + 15
}
func (stream *Stream) WriteInt64(nval int64) {
if stream.Available() < 20 {
stream.Flush()
}
n := stream.n
var val uint64
if (nval < 0) {
val = uint64(-nval)
stream.buf[n] = '-'
n++
} else {
val = uint64(nval)
}
q1 := val / 1000
if q1 == 0 {
stream.n = writeFirstBuf(stream.buf, DIGITS[val], n)
return
}
r1 := val - q1 * 1000;
q2 := q1 / 1000
if q2 == 0 {
n := writeFirstBuf(stream.buf, DIGITS[q1], n)
writeBuf(stream.buf, DIGITS[r1], n)
stream.n = n + 3
return
}
r2 := q1 - q2 * 1000
q3 := q2 / 1000
if q3 == 0 {
n = writeFirstBuf(stream.buf, DIGITS[q2], n)
writeBuf(stream.buf, DIGITS[r2], n)
writeBuf(stream.buf, DIGITS[r1], n + 3)
stream.n = n + 6
return
}
r3 := q2 - q3 * 1000
q4 := q3 / 1000
if q4 == 0 {
n = writeFirstBuf(stream.buf, DIGITS[q3], n)
writeBuf(stream.buf, DIGITS[r3], n)
writeBuf(stream.buf, DIGITS[r2], n + 3)
writeBuf(stream.buf, DIGITS[r1], n + 6)
stream.n = n + 9
return
}
r4 := q3 - q4 * 1000
q5 := q4 / 1000
if q5 == 0 {
n = writeFirstBuf(stream.buf, DIGITS[q4], n)
writeBuf(stream.buf, DIGITS[r4], n)
writeBuf(stream.buf, DIGITS[r3], n + 3)
writeBuf(stream.buf, DIGITS[r2], n + 6)
writeBuf(stream.buf, DIGITS[r1], n + 9)
stream.n = n + 12
return
}
r5 := q4 - q5 * 1000
q6 := q5 / 1000
if q6 == 0 {
n = writeFirstBuf(stream.buf, DIGITS[q5], n)
} else {
stream.buf[n] = byte(q6 + '0')
n++
r6 := q5 - q6 * 1000
writeBuf(stream.buf, DIGITS[r6], n)
n += 3
}
writeBuf(stream.buf, DIGITS[r5], n)
writeBuf(stream.buf, DIGITS[r4], n + 3)
writeBuf(stream.buf, DIGITS[r3], n + 6)
writeBuf(stream.buf, DIGITS[r2], n + 9)
writeBuf(stream.buf, DIGITS[r1], n + 12)
stream.n = n + 15
}
func (stream *Stream) WriteInt(val int) {
stream.WriteInt64(int64(val))
}
func (stream *Stream) WriteUint(val uint) {
stream.WriteUint64(uint64(val))
}

View File

@ -1,916 +0,0 @@
package jsoniter
import (
"io"
"fmt"
"unicode/utf16"
"strconv"
"unsafe"
"encoding/base64"
)
type ValueType int
const (
Invalid ValueType = iota
String
Number
Null
Bool
Array
Object
)
var digits []byte
var valueTypes []ValueType
func init() {
digits = make([]byte, 256)
for i := 0; i < len(digits); i++ {
digits[i] = 255
}
for i := '0'; i <= '9'; i++ {
digits[i] = byte(i - '0');
}
for i := 'a'; i <= 'f'; i++ {
digits[i] = byte((i - 'a') + 10);
}
for i := 'A'; i <= 'F'; i++ {
digits[i] = byte((i - 'A') + 10);
}
valueTypes = make([]ValueType, 256)
for i := 0; i < len(valueTypes); i++ {
valueTypes[i] = Invalid
}
valueTypes['"'] = String;
valueTypes['-'] = Number;
valueTypes['0'] = Number;
valueTypes['1'] = Number;
valueTypes['2'] = Number;
valueTypes['3'] = Number;
valueTypes['4'] = Number;
valueTypes['5'] = Number;
valueTypes['6'] = Number;
valueTypes['7'] = Number;
valueTypes['8'] = Number;
valueTypes['9'] = Number;
valueTypes['t'] = Bool;
valueTypes['f'] = Bool;
valueTypes['n'] = Null;
valueTypes['['] = Array;
valueTypes['{'] = Object;
}
type Iterator struct {
reader io.Reader
buf []byte
head int
tail int
Error error
}
func Parse(reader io.Reader, bufSize int) *Iterator {
iter := &Iterator{
reader: reader,
buf: make([]byte, bufSize),
head: 0,
tail: 0,
}
iter.skipWhitespaces()
return iter
}
func ParseBytes(input []byte) *Iterator {
iter := &Iterator{
reader: nil,
buf: input,
head: 0,
tail: len(input),
}
iter.skipWhitespaces()
return iter
}
func ParseString(input string) *Iterator {
return ParseBytes([]byte(input))
}
func (iter *Iterator) Reset(reader io.Reader) *Iterator {
iter.reader = reader
iter.head = 0
iter.tail = 0
iter.skipWhitespaces()
return iter
}
func (iter *Iterator) ResetBytes(input []byte) *Iterator {
// only for benchmarking
iter.reader = nil
iter.Error = nil
iter.buf = input
iter.head = 0
iter.tail = len(input)
iter.skipWhitespaces()
return iter
}
func (iter *Iterator) WhatIsNext() ValueType {
valueType := valueTypes[iter.readByte()];
iter.unreadByte();
return valueType;
}
func (iter *Iterator) skipWhitespaces() {
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\t', '\r':
continue
}
iter.head = i
return
}
if !iter.loadMore() {
return
}
}
}
func (iter *Iterator) skipWhitespacesWithoutLoadMore() bool {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\t', '\r':
continue
}
iter.head = i
return false
}
return true
}
func (iter *Iterator) nextToken() byte {
// a variation of skip whitespaces, returning the next non-whitespace token
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\t', 'r':
continue
}
iter.head = i+1
return c
}
if !iter.loadMore() {
return 0
}
}
}
func (iter *Iterator) ReportError(operation string, msg string) {
if iter.Error != nil {
return
}
peekStart := iter.head - 10
if peekStart < 0 {
peekStart = 0
}
iter.Error = fmt.Errorf("%s: %s, parsing %v ...%s... at %s", operation, msg, iter.head,
string(iter.buf[peekStart: iter.head]), string(iter.buf[0:iter.tail]))
}
func (iter *Iterator) CurrentBuffer() string {
peekStart := iter.head - 10
if peekStart < 0 {
peekStart = 0
}
return fmt.Sprintf("parsing %v ...|%s|... at %s", iter.head,
string(iter.buf[peekStart: iter.head]), string(iter.buf[0:iter.tail]))
}
func (iter *Iterator) readByte() (ret byte) {
if iter.head == iter.tail {
if iter.loadMore() {
ret = iter.buf[iter.head]
iter.head++
return ret
} else {
return 0
}
}
ret = iter.buf[iter.head]
iter.head++
return ret
}
func (iter *Iterator) loadMore() bool {
if iter.reader == nil {
iter.Error = io.EOF
return false
}
for {
n, err := iter.reader.Read(iter.buf)
if n == 0 {
if err != nil {
iter.Error = err
return false
} else {
// n == 0, err == nil is not EOF
continue
}
} else {
iter.head = 0
iter.tail = n
return true
}
}
}
func (iter *Iterator) unreadByte() {
if iter.head == 0 {
iter.ReportError("unreadByte", "unread too many bytes")
return
}
iter.head -= 1
return
}
const maxUint64 = (1 << 64 - 1)
const cutoffUint64 = maxUint64 / 10 + 1
const maxUint32 = (1 << 32 - 1)
const cutoffUint32 = maxUint32 / 10 + 1
func (iter *Iterator) ReadUint() (ret uint) {
val := iter.ReadUint64()
converted := uint(val)
if uint64(converted) != val {
iter.ReportError("ReadUint", "int overflow")
return
}
return converted
}
func (iter *Iterator) ReadUint8() (ret uint8) {
val := iter.ReadUint64()
converted := uint8(val)
if uint64(converted) != val {
iter.ReportError("ReadUint8", "int overflow")
return
}
return converted
}
func (iter *Iterator) ReadUint16() (ret uint16) {
val := iter.ReadUint64()
converted := uint16(val)
if uint64(converted) != val {
iter.ReportError("ReadUint16", "int overflow")
return
}
return converted
}
func (iter *Iterator) ReadUint32() (ret uint32) {
val := iter.ReadUint64()
converted := uint32(val)
if uint64(converted) != val {
iter.ReportError("ReadUint32", "int overflow")
return
}
return converted
}
func (iter *Iterator) ReadUint64() (ret uint64) {
c := iter.readByte()
v := digits[c]
if v == 0 {
return 0 // single zero
}
if v == 255 {
iter.ReportError("ReadUint64", "unexpected character")
return
}
for {
if ret >= cutoffUint64 {
iter.ReportError("ReadUint64", "overflow")
return
}
ret = ret * 10 + uint64(v)
c = iter.readByte()
v = digits[c]
if v == 255 {
iter.unreadByte()
break
}
}
return ret
}
func (iter *Iterator) ReadInt() (ret int) {
val := iter.ReadInt64()
converted := int(val)
if int64(converted) != val {
iter.ReportError("ReadInt", "int overflow")
return
}
return converted
}
func (iter *Iterator) ReadInt8() (ret int8) {
val := iter.ReadInt64()
converted := int8(val)
if int64(converted) != val {
iter.ReportError("ReadInt8", "int overflow")
return
}
return converted
}
func (iter *Iterator) ReadInt16() (ret int16) {
val := iter.ReadInt64()
converted := int16(val)
if int64(converted) != val {
iter.ReportError("ReadInt16", "int overflow")
return
}
return converted
}
func (iter *Iterator) ReadInt32() (ret int32) {
val := iter.ReadInt64()
converted := int32(val)
if int64(converted) != val {
iter.ReportError("ReadInt32", "int overflow")
return
}
return converted
}
func (iter *Iterator) ReadInt64() (ret int64) {
c := iter.readByte()
if iter.Error != nil {
return
}
/* optional leading minus */
if c == '-' {
n := iter.ReadUint64()
return -int64(n)
} else {
iter.unreadByte()
n := iter.ReadUint64()
return int64(n)
}
}
func (iter *Iterator) ReadString() (ret string) {
return string(iter.readStringAsBytes())
}
func (iter *Iterator) readStringAsBytes() (ret []byte) {
c := iter.readByte()
if c == 'n' {
iter.skipUntilBreak()
return
}
if c != '"' {
iter.ReportError("ReadString", `expects " or n`)
return
}
end := iter.findStringEndWithoutEscape()
if end != -1 {
// fast path: reuse the underlying buffer
ret = iter.buf[iter.head:end-1]
iter.head = end
return ret
}
str := make([]byte, 0, 8)
for iter.Error == nil {
c = iter.readByte()
if c == '"' {
return str
}
if c == '\\' {
c = iter.readByte()
if iter.Error != nil {
return
}
switch c {
case 'u':
r := iter.readU4()
if iter.Error != nil {
return
}
if utf16.IsSurrogate(r) {
c = iter.readByte()
if iter.Error != nil {
return
}
if c != '\\' {
iter.ReportError("ReadString",
`expects \u after utf16 surrogate, but \ not found`)
return
}
c = iter.readByte()
if iter.Error != nil {
return
}
if c != 'u' {
iter.ReportError("ReadString",
`expects \u after utf16 surrogate, but \u not found`)
return
}
r2 := iter.readU4()
if iter.Error != nil {
return
}
combined := utf16.DecodeRune(r, r2)
str = appendRune(str, combined)
} else {
str = appendRune(str, r)
}
case '"':
str = append(str, '"')
case '\\':
str = append(str, '\\')
case '/':
str = append(str, '/')
case 'b':
str = append(str, '\b')
case 'f':
str = append(str, '\f')
case 'n':
str = append(str, '\n')
case 'r':
str = append(str, '\r')
case 't':
str = append(str, '\t')
default:
iter.ReportError("ReadString",
`invalid escape char after \`)
return
}
} else {
str = append(str, c)
}
}
return
}
func (iter *Iterator) readU4() (ret rune) {
for i := 0; i < 4; i++ {
c := iter.readByte()
if iter.Error != nil {
return
}
if (c >= '0' && c <= '9') {
if ret >= cutoffUint32 {
iter.ReportError("readU4", "overflow")
return
}
ret = ret * 16 + rune(c - '0')
} else if ((c >= 'a' && c <= 'f') ) {
if ret >= cutoffUint32 {
iter.ReportError("readU4", "overflow")
return
}
ret = ret * 16 + rune(c - 'a' + 10)
} else {
iter.ReportError("readU4", "expects 0~9 or a~f")
return
}
}
return ret
}
const (
t1 = 0x00 // 0000 0000
tx = 0x80 // 1000 0000
t2 = 0xC0 // 1100 0000
t3 = 0xE0 // 1110 0000
t4 = 0xF0 // 1111 0000
t5 = 0xF8 // 1111 1000
maskx = 0x3F // 0011 1111
mask2 = 0x1F // 0001 1111
mask3 = 0x0F // 0000 1111
mask4 = 0x07 // 0000 0111
rune1Max = 1 << 7 - 1
rune2Max = 1 << 11 - 1
rune3Max = 1 << 16 - 1
surrogateMin = 0xD800
surrogateMax = 0xDFFF
MaxRune = '\U0010FFFF' // Maximum valid Unicode code point.
RuneError = '\uFFFD' // the "error" Rune or "Unicode replacement character"
)
func appendRune(p []byte, r rune) []byte {
// Negative values are erroneous. Making it unsigned addresses the problem.
switch i := uint32(r); {
case i <= rune1Max:
p = append(p, byte(r))
return p
case i <= rune2Max:
p = append(p, t2 | byte(r >> 6))
p = append(p, tx | byte(r) & maskx)
return p
case i > MaxRune, surrogateMin <= i && i <= surrogateMax:
r = RuneError
fallthrough
case i <= rune3Max:
p = append(p, t3 | byte(r >> 12))
p = append(p, tx | byte(r >> 6) & maskx)
p = append(p, tx | byte(r) & maskx)
return p
default:
p = append(p, t4 | byte(r >> 18))
p = append(p, tx | byte(r >> 12) & maskx)
p = append(p, tx | byte(r >> 6) & maskx)
p = append(p, tx | byte(r) & maskx)
return p
}
}
func (iter *Iterator) ReadArray() (ret bool) {
c := iter.nextToken()
if iter.Error != nil {
return
}
switch c {
case 'n': {
iter.skipUntilBreak()
return false // null
}
case '[': {
c = iter.nextToken()
if iter.Error != nil {
return
}
if c == ']' {
return false
} else {
iter.unreadByte()
return true
}
}
case ']': return false
case ',':
iter.skipWhitespaces()
return true
default:
iter.ReportError("ReadArray", "expect [ or , or ] or n")
return
}
}
func (iter *Iterator) ReadObject() (ret string) {
c := iter.nextToken()
if iter.Error != nil {
return
}
switch c {
case 'n': {
iter.skipUntilBreak()
if iter.Error != nil {
return
}
return "" // null
}
case '{': {
c = iter.nextToken()
if iter.Error != nil {
return
}
switch c {
case '}':
return "" // end of object
case '"':
iter.unreadByte()
return iter.readObjectField()
default:
iter.ReportError("ReadObject", `expect " after {`)
return
}
}
case ',':
iter.skipWhitespaces()
return iter.readObjectField()
case '}':
return "" // end of object
default:
iter.ReportError("ReadObject", `expect { or , or } or n`)
return
}
}
func (iter *Iterator) readObjectField() (ret string) {
str := iter.readStringAsBytes()
if iter.skipWhitespacesWithoutLoadMore() {
if ret == "" {
ret = string(str);
}
if !iter.loadMore() {
return
}
}
if iter.buf[iter.head] != ':' {
iter.ReportError("ReadObject", "expect : after object field")
return
}
iter.head++
if iter.skipWhitespacesWithoutLoadMore() {
if ret == "" {
ret = string(str);
}
if !iter.loadMore() {
return
}
}
if ret == "" {
return *(*string)(unsafe.Pointer(&str))
}
return ret
}
func (iter *Iterator) ReadFloat32() (ret float32) {
strBuf := [8]byte{}
str := strBuf[0:0]
hasMore := true
for(hasMore) {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case '-', '+', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
str = append(str, c)
continue
default:
hasMore = false
break
}
}
if hasMore {
if !iter.loadMore() {
break
}
}
}
if iter.Error != nil && iter.Error != io.EOF {
return
}
val, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&str)), 32)
if err != nil {
iter.Error = err
return
}
return float32(val)
}
func (iter *Iterator) ReadFloat64() (ret float64) {
strBuf := [8]byte{}
str := strBuf[0:0]
hasMore := true
for(hasMore) {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case '-', '+', '.', 'e', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
str = append(str, c)
continue
default:
hasMore = false
break
}
}
if hasMore {
if !iter.loadMore() {
break
}
}
}
if iter.Error != nil && iter.Error != io.EOF {
return
}
val, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&str)), 64)
if err != nil {
iter.Error = err
return
}
return val
}
func (iter *Iterator) ReadBool() (ret bool) {
c := iter.readByte()
if iter.Error != nil {
return
}
switch c {
case 't':
iter.skipUntilBreak()
return true
case 'f':
iter.skipUntilBreak()
return false
default:
iter.ReportError("ReadBool", "expect t or f")
return
}
}
func (iter *Iterator) ReadBase64() (ret []byte) {
src := iter.readStringAsBytes()
if iter.Error != nil {
return
}
b64 := base64.StdEncoding
ret = make([]byte, b64.DecodedLen(len(src)))
n, err := b64.Decode(ret, src)
if err != nil {
iter.Error = err
return
}
return ret[:n]
}
func (iter *Iterator) ReadNull() (ret bool) {
c := iter.readByte()
if c == 'n' {
iter.skipUntilBreak()
return true
}
iter.unreadByte()
return false
}
func (iter *Iterator) Skip() {
c := iter.readByte()
switch c {
case '"':
iter.skipString()
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 't', 'f', 'n':
iter.skipUntilBreak()
case '[':
iter.skipArray()
case '{':
iter.skipObject()
default:
iter.ReportError("Skip", fmt.Sprintf("do not know how to skip: %v", c))
return
}
}
func (iter *Iterator) skipString() {
for {
end, escaped := iter.findStringEnd()
if end == -1 {
if !iter.loadMore() {
return
}
if escaped {
iter.head = 1 // skip the first char as last char read is \
}
} else {
iter.head = end
return
}
}
}
// adapted from: https://github.com/buger/jsonparser/blob/master/parser.go
// Tries to find the end of string
// Support if string contains escaped quote symbols.
func (iter *Iterator) findStringEnd() (int, bool) {
escaped := false
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
if c == '"' {
if !escaped {
return i + 1, false
} else {
j := i - 1
for {
if j < iter.head || iter.buf[j] != '\\' {
// even number of backslashes
// either end of buffer, or " found
return i + 1, true
}
j--
if j < iter.head || iter.buf[j] != '\\' {
// odd number of backslashes
// it is \" or \\\"
break
}
j--
}
}
} else if c == '\\' {
escaped = true
}
}
j := iter.tail - 1
for {
if j < iter.head || iter.buf[j] != '\\' {
// even number of backslashes
// either end of buffer, or " found
return -1, false // do not end with \
}
j--
if j < iter.head || iter.buf[j] != '\\' {
// odd number of backslashes
// it is \" or \\\"
break
}
j--
}
return -1, true // end with \
}
func (iter *Iterator) findStringEndWithoutEscape() int {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
if c == '"' {
return i + 1
} else if c == '\\' {
return -1
}
}
return -1
}
func (iter *Iterator) skipArray() {
level := 1
for {
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '[': // If open symbol, increase level
level++
case ']': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
return
}
}
}
if (!iter.loadMore()) {
return
}
}
}
func (iter *Iterator) skipObject() {
level := 1
for {
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
case '"': // If inside string, skip it
iter.head = i + 1
iter.skipString()
i = iter.head - 1 // it will be i++ soon
case '{': // If open symbol, increase level
level++
case '}': // If close symbol, increase level
level--
// If we have returned to the original level, we're done
if level == 0 {
iter.head = i + 1
return
}
}
}
if (!iter.loadMore()) {
return
}
}
}
func (iter *Iterator) skipUntilBreak() {
// true, false, null, number
for {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case ' ', '\n', '\r', '\t', ',', '}', ']':
iter.head = i
return
}
}
if (!iter.loadMore()) {
return
}
}
}

View File

@ -1,14 +0,0 @@
package jsoniter
import "io"
// adapt to json/encoding api
func Unmarshal(data []byte, v interface{}) error {
iter := ParseBytes(data)
iter.Read(v)
if iter.Error == io.EOF {
return nil
}
return iter.Error
}

46
jsoniter_adapter_test.go Normal file
View File

@ -0,0 +1,46 @@
package jsoniter
import (
"testing"
"github.com/json-iterator/go/require"
"encoding/json"
"bytes"
"io/ioutil"
)
func Test_new_decoder(t *testing.T) {
should := require.New(t)
decoder1 := json.NewDecoder(bytes.NewBufferString(`[1][2]`))
decoder2 := NewDecoder(bytes.NewBufferString(`[1][2]`))
arr1 := []int{}
should.Nil(decoder1.Decode(&arr1))
should.Equal([]int{1}, arr1)
arr2 := []int{}
should.True(decoder1.More())
buffered, _ := ioutil.ReadAll(decoder1.Buffered())
should.Equal("[2]", string(buffered))
should.Nil(decoder2.Decode(&arr2))
should.Equal([]int{1}, arr2)
should.True(decoder2.More())
buffered, _ = ioutil.ReadAll(decoder2.Buffered())
should.Equal("[2]", string(buffered))
should.Nil(decoder1.Decode(&arr1))
should.Equal([]int{2}, arr1)
should.False(decoder1.More())
should.Nil(decoder2.Decode(&arr2))
should.Equal([]int{2}, arr2)
should.False(decoder2.More())
}
func Test_new_encoder(t *testing.T) {
should := require.New(t)
buf1 := &bytes.Buffer{}
encoder1 := json.NewEncoder(buf1)
encoder1.Encode([]int{1})
should.Equal("[1]\n", buf1.String())
buf2 := &bytes.Buffer{}
encoder2 := NewEncoder(buf2)
encoder2.Encode([]int{1})
should.Equal("[1]", buf2.String())
}

View File

@ -1,39 +0,0 @@
package jsoniter
import (
"testing"
"fmt"
)
func Test_read_string_as_any(t *testing.T) {
iter := ParseString(`[1, {"hello": "world"}, 2]`)
any := iter.ReadAny()
if any.ToString(1, "hello") != "world" {
t.FailNow()
}
}
func Test_read_float64_as_any(t *testing.T) {
iter := ParseString(`1.23`)
any := iter.ReadAny()
if any.ToFloat32() != 1.23 {
t.FailNow()
}
}
func Test_read_int_as_any(t *testing.T) {
iter := ParseString(`123`)
any := iter.ReadAny()
if any.ToFloat32() != 123 {
t.FailNow()
}
}
func Test_read_any_from_nested(t *testing.T) {
iter := ParseString(`{"numbers": ["1", "2", ["3", "4"]]}`)
val := iter.ReadAny()
if val.ToInt("numbers", 2, 0) != 3 {
fmt.Println(val.Error)
t.FailNow()
}
}

View File

@ -1,59 +1,152 @@
package jsoniter package jsoniter
import ( import (
"testing"
"encoding/json" "encoding/json"
"testing"
"github.com/json-iterator/go/require"
"bytes"
"io"
) )
func Test_empty_array(t *testing.T) { func Test_empty_array(t *testing.T) {
should := require.New(t)
iter := ParseString(`[]`) iter := ParseString(`[]`)
cont := iter.ReadArray() cont := iter.ReadArray()
if cont != false { should.False(cont)
t.FailNow() iter = ParseString(`[]`)
} iter.ReadArrayCB(func(iter *Iterator) bool {
should.FailNow("should not call")
return true
})
} }
func Test_one_element(t *testing.T) { func Test_one_element(t *testing.T) {
should := require.New(t)
iter := ParseString(`[1]`) iter := ParseString(`[1]`)
cont := iter.ReadArray() should.True(iter.ReadArray())
if cont != true { should.Equal(1, iter.ReadInt())
t.FailNow() should.False(iter.ReadArray())
} iter = ParseString(`[1]`)
if iter.ReadInt64() != 1 { iter.ReadArrayCB(func(iter *Iterator) bool {
t.FailNow() should.Equal(1, iter.ReadInt())
} return true
cont = iter.ReadArray() })
if cont != false {
t.FailNow()
}
} }
func Test_two_elements(t *testing.T) { func Test_two_elements(t *testing.T) {
should := require.New(t)
iter := ParseString(`[1,2]`) iter := ParseString(`[1,2]`)
cont := iter.ReadArray() should.True(iter.ReadArray())
if cont != true { should.Equal(int64(1), iter.ReadInt64())
t.FailNow() should.True(iter.ReadArray())
should.Equal(int64(2), iter.ReadInt64())
should.False(iter.ReadArray())
iter = ParseString(`[1,2]`)
should.Equal([]interface{}{float64(1), float64(2)}, iter.Read())
}
func Test_read_empty_array_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[]")
should.Nil(err)
should.Equal(0, any.Size())
}
func Test_read_one_element_array_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[1]")
should.Nil(err)
should.Equal(1, any.Size())
}
func Test_read_two_element_array_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[1,2]")
should.Nil(err)
should.Equal(1, any.Get(0).ToInt())
should.Equal(2, any.Size())
should.True(any.ToBool())
should.Equal(1, any.ToInt())
}
func Test_read_array_with_any_iterator(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[1,2]")
should.Nil(err)
var element Any
var elements []int
for next, hasNext := any.IterateArray(); hasNext; {
element, hasNext = next()
elements = append(elements, element.ToInt())
} }
if iter.ReadInt64() != 1 { should.Equal([]int{1, 2}, elements)
t.FailNow() }
}
cont = iter.ReadArray() func Test_wrap_array(t *testing.T) {
if cont != true { should := require.New(t)
t.FailNow() any := Wrap([]int{1,2,3})
} should.Equal("[1,2,3]", any.ToString())
if iter.ReadInt64() != 2 { var element Any
t.FailNow() var elements []int
} for next, hasNext := any.IterateArray(); hasNext; {
cont = iter.ReadArray() element, hasNext = next()
if cont != false { elements = append(elements, element.ToInt())
t.FailNow()
} }
should.Equal([]int{1, 2, 3}, elements)
any = Wrap([]int{1,2,3})
should.Equal(3, any.Size())
any = Wrap([]int{1,2,3})
should.Equal(2, any.Get(1).ToInt())
}
func Test_array_lazy_any_get(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[1,[2,3],4]")
should.Nil(err)
should.Equal(3, any.Get(1,1).ToInt())
should.Equal("[1,[2,3],4]", any.ToString())
}
func Test_array_lazy_any_get_all(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[[1],[2],[3,4]]")
should.Nil(err)
should.Equal("[1,2,3]", any.Get('*',0).ToString())
}
func Test_array_wrapper_any_get_all(t *testing.T) {
should := require.New(t)
any := wrapArray([][]int{
[]int{1, 2},
[]int{3, 4},
[]int{5, 6},
})
should.Equal("[1,3,5]", any.Get('*',0).ToString())
}
func Test_array_lazy_any_get_invalid(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[]")
should.Nil(err)
should.Equal(Invalid, any.Get(1,1).ValueType())
should.NotNil(any.Get(1,1).LastError())
should.Equal(Invalid, any.Get("1").ValueType())
should.NotNil(any.Get("1").LastError())
}
func Test_array_lazy_any_set(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("[1,[2,3],4]")
should.Nil(err)
any.GetArray()[0] = WrapInt64(2)
str, err := MarshalToString(any)
should.Nil(err)
should.Equal("[2,[2,3],4]", str)
} }
func Test_invalid_array(t *testing.T) { func Test_invalid_array(t *testing.T) {
iter := ParseString(`[`) _, err := UnmarshalAnyFromString("[")
iter.ReadArray() if err == nil || err == io.EOF {
if iter.Error == nil {
t.FailNow() t.FailNow()
} }
} }
@ -117,6 +210,60 @@ func Test_whitespace_before_comma(t *testing.T) {
} }
} }
func Test_write_array(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.IndentionStep = 2
stream.WriteArrayStart()
stream.WriteInt(1)
stream.WriteMore()
stream.WriteInt(2)
stream.WriteArrayEnd()
stream.Flush()
should.Nil(stream.Error)
should.Equal("[\n 1,\n 2\n]", buf.String())
}
func Test_write_val_array(t *testing.T) {
should := require.New(t)
val := []int{1, 2, 3}
str, err := MarshalToString(val)
should.Nil(err)
should.Equal("[1,2,3]", str)
}
func Test_write_val_empty_array(t *testing.T) {
should := require.New(t)
val := []int{}
str, err := MarshalToString(val)
should.Nil(err)
should.Equal("[]", str)
}
func Test_write_array_of_interface_in_struct(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field []interface{}
Field2 string
}
val := TestObject{[]interface{}{1, 2}, ""}
str, err := MarshalToString(val)
should.Nil(err)
should.Contains(str, `"Field":[1,2]`)
should.Contains(str, `"Field2":""`)
}
func Test_json_RawMessage(t *testing.T) {
should := require.New(t)
var data json.RawMessage
should.Nil(Unmarshal([]byte(`[1,2,3]`), &data))
should.Equal(`[1,2,3]`, string(data))
str, err := MarshalToString(data)
should.Nil(err)
should.Equal(`[1,2,3]`, str)
}
func Benchmark_jsoniter_array(b *testing.B) { func Benchmark_jsoniter_array(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
input := []byte(`[1,2,3,4,5,6,7,8,9]`) input := []byte(`[1,2,3,4,5,6,7,8,9]`)

View File

@ -1,8 +1,8 @@
package jsoniter package jsoniter
import ( import (
"testing"
"bytes" "bytes"
"testing"
) )
func Test_read_base64(t *testing.T) { func Test_read_base64(t *testing.T) {
@ -12,7 +12,6 @@ func Test_read_base64(t *testing.T) {
} }
} }
func Test_bad_case(t *testing.T) { func Test_bad_case(t *testing.T) {
// field := *(*string)(unsafe.Pointer(&str)) // field := *(*string)(unsafe.Pointer(&str))
// caused this issue // caused this issue

View File

@ -1,17 +1,50 @@
package jsoniter package jsoniter
import "testing" import (
"testing"
"bytes"
"github.com/json-iterator/go/require"
)
func Test_true(t *testing.T) { func Test_true(t *testing.T) {
should := require.New(t)
iter := ParseString(`true`) iter := ParseString(`true`)
if iter.ReadBool() != true { should.True(iter.ReadBool())
t.FailNow() iter = ParseString(`true`)
} should.Equal(true, iter.Read())
} }
func Test_false(t *testing.T) { func Test_false(t *testing.T) {
should := require.New(t)
iter := ParseString(`false`) iter := ParseString(`false`)
if iter.ReadBool() != false { should.False(iter.ReadBool())
t.FailNow() }
}
func Test_read_bool_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("true")
should.Nil(err)
should.True(any.ToBool())
}
func Test_write_true_false(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteTrue()
stream.WriteFalse()
stream.Flush()
should.Nil(stream.Error)
should.Equal("truefalse", buf.String())
}
func Test_write_val_bool(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(true)
stream.Flush()
should.Nil(stream.Error)
should.Equal("true", buf.String())
} }

View File

@ -1,11 +1,13 @@
package jsoniter package jsoniter
import ( import (
"reflect"
"strconv"
"testing" "testing"
"time" "time"
"unsafe" "unsafe"
"strconv" "github.com/json-iterator/go/require"
"reflect" "encoding/json"
) )
func Test_customize_type_decoder(t *testing.T) { func Test_customize_type_decoder(t *testing.T) {
@ -17,7 +19,7 @@ func Test_customize_type_decoder(t *testing.T) {
} }
*((*time.Time)(ptr)) = t *((*time.Time)(ptr)) = t
}) })
defer ClearDecoders() defer CleanDecoders()
val := time.Time{} val := time.Time{}
err := Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val) err := Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val)
if err != nil { if err != nil {
@ -29,6 +31,41 @@ func Test_customize_type_decoder(t *testing.T) {
} }
} }
func Test_customize_type_encoder(t *testing.T) {
should := require.New(t)
RegisterTypeEncoder("time.Time", func(ptr unsafe.Pointer, stream *Stream) {
t := *((*time.Time)(ptr))
stream.WriteString(t.UTC().Format("2006-01-02 15:04:05"))
})
defer CleanEncoders()
val := time.Unix(0, 0)
str, err := MarshalToString(val)
should.Nil(err)
should.Equal(`"1970-01-01 00:00:00"`, str)
}
func Test_customize_byte_array_encoder(t *testing.T) {
should := require.New(t)
RegisterTypeEncoder("[]uint8", func(ptr unsafe.Pointer, stream *Stream) {
t := *((*[]byte)(ptr))
stream.WriteString(string(t))
})
defer CleanEncoders()
val := []byte("abc")
str, err := MarshalToString(val)
should.Nil(err)
should.Equal(`"abc"`, str)
}
func Test_customize_float_marshal(t *testing.T) {
should := require.New(t)
EnableLossyFloatMarshalling()
defer CleanEncoders()
str, err := MarshalToString(float32(1.23456789))
should.Nil(err)
should.Equal("1.234568", str)
}
type Tom struct { type Tom struct {
field1 string field1 string
} }
@ -37,7 +74,7 @@ func Test_customize_field_decoder(t *testing.T) {
RegisterFieldDecoder("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *Iterator) { RegisterFieldDecoder("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *Iterator) {
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt()) *((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
}) })
defer ClearDecoders() defer CleanDecoders()
tom := Tom{} tom := Tom{}
err := Unmarshal([]byte(`{"field1": 100}`), &tom) err := Unmarshal([]byte(`{"field1": 100}`), &tom)
if err != nil { if err != nil {
@ -45,21 +82,134 @@ func Test_customize_field_decoder(t *testing.T) {
} }
} }
func Test_customize_field_decoder_factory(t *testing.T) { type TestObject1 struct {
RegisterFieldCustomizer(func(type_ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc) { field1 string
if (type_.String() == "jsoniter.Tom" && field.Name == "field1") { }
return []string{"field-1"}, func(ptr unsafe.Pointer, iter *Iterator) {
func Test_customize_field_by_extension(t *testing.T) {
should := require.New(t)
RegisterExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, EncoderFunc, DecoderFunc) {
if type_.String() == "jsoniter.TestObject1" && field.Name == "field1" {
encode := func(ptr unsafe.Pointer, stream *Stream) {
str := *((*string)(ptr))
val, _ := strconv.Atoi(str)
stream.WriteInt(val)
}
decode := func(ptr unsafe.Pointer, iter *Iterator) {
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt()) *((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
} }
return []string{"field-1"}, encode, decode
} }
return nil, nil return nil, nil, nil
}) })
tom := Tom{} obj := TestObject1{}
err := Unmarshal([]byte(`{"field-1": 100}`), &tom) err := UnmarshalFromString(`{"field-1": 100}`, &obj)
if err != nil { should.Nil(err)
t.Fatal(err) should.Equal("100", obj.field1)
} str, err := MarshalToString(obj)
if tom.field1 != "100" { should.Nil(err)
t.Fatal(tom.field1) should.Equal(`{"field-1":100}`, str)
} }
func Test_unexported_fields(t *testing.T) {
EnableUnexportedStructFieldsSupport()
should := require.New(t)
type TestObject struct {
field1 string
field2 string `json:"field-2"`
}
obj := TestObject{}
obj.field1 = "hello"
should.Nil(UnmarshalFromString(`{}`, &obj))
should.Equal("hello", obj.field1)
should.Nil(UnmarshalFromString(`{"field1": "world", "field-2": "abc"}`, &obj))
should.Equal("world", obj.field1)
should.Equal("abc", obj.field2)
str, err := MarshalToString(obj)
should.Nil(err)
should.Contains(str, `"field-2":"abc"`)
}
type ObjectImplementedMarshaler int
func (obj *ObjectImplementedMarshaler) MarshalJSON() ([]byte, error) {
return []byte(`"hello"`), nil
}
func Test_marshaler(t *testing.T) {
type TestObject struct {
Field *ObjectImplementedMarshaler
}
should := require.New(t)
val := ObjectImplementedMarshaler(100)
obj := TestObject{&val}
bytes, err := json.Marshal(obj)
should.Nil(err)
should.Equal(`{"Field":"hello"}`, string(bytes))
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Field":"hello"}`, str)
}
func Test_marshaler_and_encoder(t *testing.T) {
type TestObject struct {
Field *ObjectImplementedMarshaler
}
should := require.New(t)
RegisterTypeEncoder("jsoniter.ObjectImplementedMarshaler", func(ptr unsafe.Pointer, stream *Stream) {
stream.WriteString("hello from encoder")
})
val := ObjectImplementedMarshaler(100)
obj := TestObject{&val}
bytes, err := json.Marshal(obj)
should.Nil(err)
should.Equal(`{"Field":"hello"}`, string(bytes))
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Field":"hello from encoder"}`, str)
}
type ObjectImplementedUnmarshaler int
func (obj *ObjectImplementedUnmarshaler) UnmarshalJSON([]byte) error {
*obj = 100
return nil
}
func Test_unmarshaler(t *testing.T) {
type TestObject struct {
Field *ObjectImplementedUnmarshaler
Field2 string
}
should := require.New(t)
obj := TestObject{}
val := ObjectImplementedUnmarshaler(0)
obj.Field = &val
err := json.Unmarshal([]byte(`{"Field":"hello"}`), &obj)
should.Nil(err)
should.Equal(100, int(*obj.Field))
err = Unmarshal([]byte(`{"Field":"hello"}`), &obj)
should.Nil(err)
should.Equal(100, int(*obj.Field))
}
func Test_unmarshaler_and_decoder(t *testing.T) {
type TestObject struct {
Field *ObjectImplementedUnmarshaler
Field2 string
}
should := require.New(t)
RegisterTypeDecoder("jsoniter.ObjectImplementedUnmarshaler", func(ptr unsafe.Pointer, iter *Iterator) {
*(*ObjectImplementedUnmarshaler)(ptr) = 10
iter.Skip()
})
obj := TestObject{}
val := ObjectImplementedUnmarshaler(0)
obj.Field = &val
err := json.Unmarshal([]byte(`{"Field":"hello"}`), &obj)
should.Nil(err)
should.Equal(100, int(*obj.Field))
err = Unmarshal([]byte(`{"Field":"hello"}`), &obj)
should.Nil(err)
should.Equal(10, int(*obj.Field))
} }

View File

@ -1,21 +1,17 @@
package jsoniter package jsoniter
import ( import (
"testing"
"fmt" "fmt"
"testing"
"github.com/json-iterator/go/require"
) )
func Test_bind_api_demo(t *testing.T) { func Test_bind_api_demo(t *testing.T) {
iter := ParseString(`[0,1,2,3]`) should := require.New(t)
val := []int{} val := []int{}
iter.Read(&val) err := UnmarshalFromString(`[0,1,2,3] `, &val)
fmt.Println(val[3]) should.Nil(err)
} should.Equal([]int{0, 1, 2, 3}, val)
func Test_any_api_demo(t *testing.T) {
iter := ParseString(`[0,1,2,3]`)
val := iter.ReadAny()
fmt.Println(val.Get(3))
} }
func Test_iterator_api_demo(t *testing.T) { func Test_iterator_api_demo(t *testing.T) {
@ -26,31 +22,3 @@ func Test_iterator_api_demo(t *testing.T) {
} }
fmt.Println(total) fmt.Println(total)
} }
type ABC struct {
a Any
}
func Test_deep_nested_any_api(t *testing.T) {
iter := ParseString(`{"a": {"b": {"c": "d"}}}`)
abc := &ABC{}
iter.Read(&abc)
fmt.Println(abc.a.Get("b", "c"))
}
type User struct {
userId int
name string
tags []string
}
func Test_iterator_and_bind_api(t *testing.T) {
iter := ParseString(`[123, {"name": "taowen", "tags": ["crazy", "hacker"]}]`)
user := User{}
iter.ReadArray()
user.userId = iter.ReadInt()
iter.ReadArray()
iter.Read(&user)
iter.ReadArray() // array end
fmt.Println(user)
}

View File

@ -1,8 +1,9 @@
package jsoniter package jsoniter
import ( import (
"testing"
"io" "io"
"testing"
"github.com/json-iterator/go/require"
) )
func Test_string_end(t *testing.T) { func Test_string_end(t *testing.T) {
@ -89,52 +90,41 @@ func (reader *StagedReader) Read(p []byte) (n int, err error) {
} }
func Test_skip_string(t *testing.T) { func Test_skip_string(t *testing.T) {
should := require.New(t)
iter := ParseString(`"abc`) iter := ParseString(`"abc`)
iter.skipString() iter.skipString()
if iter.head != 1 { should.Equal(1, iter.head)
t.Fatal(iter.head)
}
iter = ParseString(`\""abc`) iter = ParseString(`\""abc`)
iter.skipString() iter.skipString()
if iter.head != 3 { should.Equal(3, iter.head)
t.Fatal(iter.head)
}
reader := &StagedReader{ reader := &StagedReader{
r1: `abc`, r1: `abc`,
r2: `"`, r2: `"`,
} }
iter = Parse(reader, 4096) iter = Parse(reader, 4096)
iter.skipString() iter.skipString()
if iter.head != 1 { should.Equal(1, iter.head)
t.Fatal(iter.head)
}
reader = &StagedReader{ reader = &StagedReader{
r1: `abc`, r1: `abc`,
r2: `1"`, r2: `1"`,
} }
iter = Parse(reader, 4096) iter = Parse(reader, 4096)
iter.skipString() iter.skipString()
if iter.head != 2 { should.Equal(2, iter.head)
t.Fatal(iter.head)
}
reader = &StagedReader{ reader = &StagedReader{
r1: `abc\`, r1: `abc\`,
r2: `"`, r2: `"`,
} }
iter = Parse(reader, 4096) iter = Parse(reader, 4096)
iter.skipString() iter.skipString()
if iter.Error != io.EOF { should.NotNil(iter.Error)
t.Fatal(iter.Error)
}
reader = &StagedReader{ reader = &StagedReader{
r1: `abc\`, r1: `abc\`,
r2: `""`, r2: `""`,
} }
iter = Parse(reader, 4096) iter = Parse(reader, 4096)
iter.skipString() iter.skipString()
if iter.head != 2 { should.Equal(2, iter.head)
t.Fatal(iter.head)
}
} }
func Test_skip_object(t *testing.T) { func Test_skip_object(t *testing.T) {

View File

@ -1,40 +1,169 @@
package jsoniter package jsoniter
import ( import (
"testing"
"encoding/json" "encoding/json"
"fmt" "fmt"
"testing"
"github.com/json-iterator/go/require"
"bytes"
"strconv"
) )
func Test_float64_0(t *testing.T) { func Test_read_big_float(t *testing.T) {
iter := ParseString(`0`) should := require.New(t)
val := iter.ReadFloat64() iter := ParseString(`12.3`)
if val != 0 { val := iter.ReadBigFloat()
t.Fatal(val) val64, _ := val.Float64()
should.Equal(12.3, val64)
}
func Test_read_big_int(t *testing.T) {
should := require.New(t)
iter := ParseString(`92233720368547758079223372036854775807`)
val := iter.ReadBigInt()
should.NotNil(val)
should.Equal(`92233720368547758079223372036854775807`, val.String())
}
func Test_read_float(t *testing.T) {
inputs := []string{`1.1`, `1000`, `9223372036854775807`, `12.3`, `-12.3`, `720368.54775807`, `720368.547758075`}
for _, input := range inputs {
// non-streaming
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t)
iter := ParseString(input + ",")
expected, err := strconv.ParseFloat(input, 32)
should.Nil(err)
should.Equal(float32(expected), iter.ReadFloat32())
})
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t)
iter := ParseString(input + ",")
expected, err := strconv.ParseFloat(input, 64)
should.Nil(err)
should.Equal(expected, iter.ReadFloat64())
})
// streaming
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t)
iter := Parse(bytes.NewBufferString(input + ","), 2)
expected, err := strconv.ParseFloat(input, 32)
should.Nil(err)
should.Equal(float32(expected), iter.ReadFloat32())
})
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t)
iter := Parse(bytes.NewBufferString(input + ","), 2)
expected, err := strconv.ParseFloat(input, 64)
should.Nil(err)
should.Equal(expected, iter.ReadFloat64())
})
} }
} }
func Test_float64_1_dot_1(t *testing.T) { func Test_read_float_as_interface(t *testing.T) {
iter := ParseString(`1.1`) should := require.New(t)
val := iter.ReadFloat64() iter := ParseString(`12.3`)
if val != 1.1 { should.Equal(float64(12.3), iter.Read())
t.Fatal(val)
}
} }
func Test_float32_1_dot_1_comma(t *testing.T) { func Test_read_float_as_any(t *testing.T) {
iter := ParseString(`1.1,`) should := require.New(t)
val := iter.ReadFloat32() any, err := UnmarshalAnyFromString("12.3")
if val != 1.1 { should.Nil(err)
fmt.Println(iter.Error) should.Equal(float64(12.3), any.ToFloat64())
t.Fatal(val) should.Equal("12.3", any.ToString())
should.True(any.ToBool())
}
func Test_wrap_float(t *testing.T) {
should := require.New(t)
str, err := MarshalToString(WrapFloat64(12.3))
should.Nil(err)
should.Equal("12.3", str)
}
func Test_write_float32(t *testing.T) {
vals := []float32{0, 1, -1, 99, 0xff, 0xfff, 0xffff, 0xfffff, 0xffffff, 0x4ffffff, 0xfffffff,
-0x4ffffff, -0xfffffff, 1.2345, 1.23456, 1.234567, 1.001}
for _, val := range vals {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteFloat32Lossy(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatFloat(float64(val), 'f', -1, 32), buf.String())
})
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatFloat(float64(val), 'f', -1, 32), buf.String())
})
} }
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 10)
stream.WriteRaw("abcdefg")
stream.WriteFloat32Lossy(1.123456)
stream.Flush()
should.Nil(stream.Error)
should.Equal("abcdefg1.123456", buf.String())
}
func Test_write_float64(t *testing.T) {
vals := []float64{0, 1, -1, 99, 0xff, 0xfff, 0xffff, 0xfffff, 0xffffff, 0x4ffffff, 0xfffffff,
-0x4ffffff, -0xfffffff, 1.2345, 1.23456, 1.234567, 1.001}
for _, val := range vals {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteFloat64Lossy(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatFloat(val, 'f', -1, 64), buf.String())
})
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatFloat(val, 'f', -1, 64), buf.String())
})
}
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 10)
stream.WriteRaw("abcdefg")
stream.WriteFloat64Lossy(1.123456)
stream.Flush()
should.Nil(stream.Error)
should.Equal("abcdefg1.123456", buf.String())
}
func Test_read_float64_cursor(t *testing.T) {
should := require.New(t)
iter := ParseString("[1.23456789\n,2,3]")
should.True(iter.ReadArray())
should.Equal(1.23456789, iter.Read())
should.True(iter.ReadArray())
should.Equal(float64(2), iter.Read())
} }
func Benchmark_jsoniter_float(b *testing.B) { func Benchmark_jsoniter_float(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
input := []byte(`1.1123,`)
iter := NewIterator()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter := ParseString(`1.1111111111`) iter.ResetBytes(input)
iter.ReadFloat64() iter.ReadFloat64()
} }
} }

View File

@ -1,76 +1,456 @@
package jsoniter package jsoniter
import ( import (
"testing"
"bytes" "bytes"
"encoding/json" "encoding/json"
"testing"
"github.com/json-iterator/go/require"
"fmt"
"strconv"
"io/ioutil"
"io"
) )
func Test_uint64_0(t *testing.T) { func Test_read_uint64_invalid(t *testing.T) {
iter := Parse(bytes.NewBufferString("0"), 4096) should := require.New(t)
val := iter.ReadUint64() iter := ParseString(",")
if iter.Error != nil {
t.Fatal(iter.Error)
}
if val != 0 {
t.Fatal(val)
}
}
func Test_uint64_1(t *testing.T) {
iter := Parse(bytes.NewBufferString("1"), 4096)
val := iter.ReadUint64()
if val != 1 {
t.Fatal(val)
}
}
func Test_uint64_100(t *testing.T) {
iter := Parse(bytes.NewBufferString("100"), 4096)
val := iter.ReadUint64()
if val != 100 {
t.Fatal(val)
}
}
func Test_uint64_100_comma(t *testing.T) {
iter := Parse(bytes.NewBufferString("100,"), 4096)
val := iter.ReadUint64()
if iter.Error != nil {
t.Fatal(iter.Error)
}
if val != 100 {
t.Fatal(val)
}
}
func Test_uint64_invalid(t *testing.T) {
iter := Parse(bytes.NewBufferString(","), 4096)
iter.ReadUint64() iter.ReadUint64()
if iter.Error == nil { should.NotNil(iter.Error)
t.FailNow() }
func Test_read_int8(t *testing.T) {
inputs := []string{`127`, `-128`}
for _, input := range inputs {
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t)
iter := ParseString(input)
expected, err := strconv.ParseInt(input, 10, 8)
should.Nil(err)
should.Equal(int8(expected), iter.ReadInt8())
})
} }
} }
func Test_int64_100(t *testing.T) { func Test_read_int16(t *testing.T) {
iter := Parse(bytes.NewBufferString("100"), 4096) inputs := []string{`32767`, `-32768`}
val := iter.ReadInt64() for _, input := range inputs {
if val != 100 { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
t.Fatal(val) should := require.New(t)
iter := ParseString(input)
expected, err := strconv.ParseInt(input, 10, 16)
should.Nil(err)
should.Equal(int16(expected), iter.ReadInt16())
})
} }
} }
func Test_int64_minus_100(t *testing.T) { func Test_read_int32(t *testing.T) {
iter := Parse(bytes.NewBufferString("-100"), 4096) inputs := []string{`1`, `12`, `123`, `1234`, `12345`, `123456`, `2147483647`, `-2147483648`}
val := iter.ReadInt64() for _, input := range inputs {
if val != -100 { t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
t.Fatal(val) should := require.New(t)
iter := ParseString(input)
expected, err := strconv.ParseInt(input, 10, 32)
should.Nil(err)
should.Equal(int32(expected), iter.ReadInt32())
})
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t)
iter := Parse(bytes.NewBufferString(input), 2)
expected, err := strconv.ParseInt(input, 10, 32)
should.Nil(err)
should.Equal(int32(expected), iter.ReadInt32())
})
}
}
func Test_read_int32_array(t *testing.T) {
should := require.New(t)
input := `[123,456,789]`
val := make([]int32, 0)
UnmarshalFromString(input, &val)
should.Equal(3, len(val))
}
func Test_read_int64_array(t *testing.T) {
should := require.New(t)
input := `[123,456,789]`
val := make([]int64, 0)
UnmarshalFromString(input, &val)
should.Equal(3, len(val))
}
func Test_read_int32_overflow(t *testing.T) {
should := require.New(t)
input := "123456789123456789,"
iter := ParseString(input)
iter.ReadInt32()
should.NotNil(iter.Error)
}
func Test_read_int64(t *testing.T) {
inputs := []string{`1`, `12`, `123`, `1234`, `12345`, `123456`, `9223372036854775807`, `-9223372036854775808`}
for _, input := range inputs {
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t)
iter := ParseString(input)
expected, err := strconv.ParseInt(input, 10, 64)
should.Nil(err)
should.Equal(expected, iter.ReadInt64())
})
t.Run(fmt.Sprintf("%v", input), func(t *testing.T) {
should := require.New(t)
iter := Parse(bytes.NewBufferString(input), 2)
expected, err := strconv.ParseInt(input, 10, 64)
should.Nil(err)
should.Equal(expected, iter.ReadInt64())
})
}
}
func Test_read_int64_overflow(t *testing.T) {
should := require.New(t)
input := "123456789123456789123456789123456789,"
iter := ParseString(input)
iter.ReadInt64()
should.NotNil(iter.Error)
}
func Test_read_int64_as_any(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("1234")
should.Nil(err)
should.Equal(1234, any.ToInt())
should.Equal(io.EOF, any.LastError())
should.Equal("1234", any.ToString())
should.True(any.ToBool())
}
func Test_int_lazy_any_get(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString("1234")
should.Nil(err)
should.Equal(Invalid, any.Get(1, "2").ValueType())
}
func Test_wrap_int(t *testing.T) {
should := require.New(t)
str, err := MarshalToString(WrapInt64(100))
should.Nil(err)
should.Equal("100", str)
}
func Test_write_uint8(t *testing.T) {
vals := []uint8{0, 1, 11, 111, 255}
for _, val := range vals {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteUint8(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
})
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
})
}
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 3)
stream.WriteRaw("a")
stream.WriteUint8(100) // should clear buffer
stream.Flush()
should.Nil(stream.Error)
should.Equal("a100", buf.String())
}
func Test_write_int8(t *testing.T) {
vals := []int8{0, 1, -1, 99, 0x7f, -0x80}
for _, val := range vals {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteInt8(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatInt(int64(val), 10), buf.String())
})
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatInt(int64(val), 10), buf.String())
})
}
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4)
stream.WriteRaw("a")
stream.WriteInt8(-100) // should clear buffer
stream.Flush()
should.Nil(stream.Error)
should.Equal("a-100", buf.String())
}
func Test_write_uint16(t *testing.T) {
vals := []uint16{0, 1, 11, 111, 255, 0xfff, 0xffff}
for _, val := range vals {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteUint16(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
})
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
})
}
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 5)
stream.WriteRaw("a")
stream.WriteUint16(10000) // should clear buffer
stream.Flush()
should.Nil(stream.Error)
should.Equal("a10000", buf.String())
}
func Test_write_int16(t *testing.T) {
vals := []int16{0, 1, 11, 111, 255, 0xfff, 0x7fff, -0x8000}
for _, val := range vals {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteInt16(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatInt(int64(val), 10), buf.String())
})
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatInt(int64(val), 10), buf.String())
})
}
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 6)
stream.WriteRaw("a")
stream.WriteInt16(-10000) // should clear buffer
stream.Flush()
should.Nil(stream.Error)
should.Equal("a-10000", buf.String())
}
func Test_write_uint32(t *testing.T) {
vals := []uint32{0, 1, 11, 111, 255, 999999, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0xffffffff}
for _, val := range vals {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteUint32(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
})
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
})
}
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 10)
stream.WriteRaw("a")
stream.WriteUint32(0xffffffff) // should clear buffer
stream.Flush()
should.Nil(stream.Error)
should.Equal("a4294967295", buf.String())
}
func Test_write_int32(t *testing.T) {
vals := []int32{0, 1, 11, 111, 255, 999999, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0x7fffffff, -0x80000000}
for _, val := range vals {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteInt32(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatInt(int64(val), 10), buf.String())
})
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatInt(int64(val), 10), buf.String())
})
}
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 11)
stream.WriteRaw("a")
stream.WriteInt32(-0x7fffffff) // should clear buffer
stream.Flush()
should.Nil(stream.Error)
should.Equal("a-2147483647", buf.String())
}
func Test_write_uint64(t *testing.T) {
vals := []uint64{0, 1, 11, 111, 255, 999999, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0xffffffff,
0xfffffffff, 0xffffffffff, 0xfffffffffff, 0xffffffffffff, 0xfffffffffffff, 0xffffffffffffff,
0xfffffffffffffff, 0xffffffffffffffff}
for _, val := range vals {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteUint64(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
})
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatUint(uint64(val), 10), buf.String())
})
}
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 10)
stream.WriteRaw("a")
stream.WriteUint64(0xffffffff) // should clear buffer
stream.Flush()
should.Nil(stream.Error)
should.Equal("a4294967295", buf.String())
}
func Test_write_int64(t *testing.T) {
vals := []int64{0, 1, 11, 111, 255, 999999, 0xfff, 0xffff, 0xfffff, 0xffffff, 0xfffffff, 0xffffffff,
0xfffffffff, 0xffffffffff, 0xfffffffffff, 0xffffffffffff, 0xfffffffffffff, 0xffffffffffffff,
0xfffffffffffffff, 0x7fffffffffffffff, -0x8000000000000000}
for _, val := range vals {
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteInt64(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatInt(val, 10), buf.String())
})
t.Run(fmt.Sprintf("%v", val), func(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(val)
stream.Flush()
should.Nil(stream.Error)
should.Equal(strconv.FormatInt(val, 10), buf.String())
})
}
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 10)
stream.WriteRaw("a")
stream.WriteInt64(0xffffffff) // should clear buffer
stream.Flush()
should.Nil(stream.Error)
should.Equal("a4294967295", buf.String())
}
func Test_write_val_int(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteVal(1001)
stream.Flush()
should.Nil(stream.Error)
should.Equal("1001", buf.String())
}
func Test_write_val_int_ptr(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
val := 1001
stream.WriteVal(&val)
stream.Flush()
should.Nil(stream.Error)
should.Equal("1001", buf.String())
}
func Test_json_number(t *testing.T) {
should := require.New(t)
var arr []json.Number
err := Unmarshal([]byte(`[1]`), &arr)
should.Nil(err)
should.Equal(json.Number("1"), arr[0])
str, err := MarshalToString(arr)
should.Nil(err)
should.Equal(`[1]`, str)
}
func Benchmark_jsoniter_encode_int(b *testing.B) {
stream := NewStream(ioutil.Discard, 64)
for n := 0; n < b.N; n++ {
stream.n = 0
stream.WriteUint64(0xffffffff)
}
}
func Benchmark_itoa(b *testing.B) {
for n := 0; n < b.N; n++ {
strconv.FormatInt(0xffffffff, 10)
} }
} }
func Benchmark_jsoniter_int(b *testing.B) { func Benchmark_jsoniter_int(b *testing.B) {
iter := NewIterator()
input := []byte(`100`)
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter := ParseString(`-100`) iter.ResetBytes(input)
iter.ReadInt64() iter.ReadInt64()
} }
} }

140
jsoniter_interface_test.go Normal file
View File

@ -0,0 +1,140 @@
package jsoniter
import (
"testing"
"github.com/json-iterator/go/require"
"unsafe"
)
func Test_write_array_of_interface(t *testing.T) {
should := require.New(t)
array := []interface{}{"hello"}
str, err := MarshalToString(array)
should.Nil(err)
should.Equal(`["hello"]`, str)
}
func Test_write_map_of_interface(t *testing.T) {
should := require.New(t)
val := map[string]interface{}{"hello":"world"}
str, err := MarshalToString(val)
should.Nil(err)
should.Equal(`{"hello":"world"}`, str)
}
func Test_write_map_of_interface_in_struct(t *testing.T) {
type TestObject struct {
Field map[string]interface{}
}
should := require.New(t)
val := TestObject{map[string]interface{}{"hello":"world"}}
str, err := MarshalToString(val)
should.Nil(err)
should.Equal(`{"Field":{"hello":"world"}}`, str)
}
func Test_write_map_of_interface_in_struct_with_two_fields(t *testing.T) {
type TestObject struct {
Field map[string]interface{}
Field2 string
}
should := require.New(t)
val := TestObject{map[string]interface{}{"hello":"world"}, ""}
str, err := MarshalToString(val)
should.Nil(err)
should.Contains(str, `"Field":{"hello":"world"}`)
}
type MyInterface interface {
Hello() string
}
type MyString string
func (ms MyString) Hello() string {
return string(ms)
}
func Test_write_map_of_custom_interface(t *testing.T) {
should := require.New(t)
myStr := MyString("world")
should.Equal("world", myStr.Hello())
val := map[string]MyInterface{"hello":myStr}
str, err := MarshalToString(val)
should.Nil(err)
should.Equal(`{"hello":"world"}`, str)
}
func Test_write_interface(t *testing.T) {
should := require.New(t)
var val interface{}
val = "hello"
str, err := MarshalToString(val)
should.Nil(err)
should.Equal(`"hello"`, str)
}
func Test_read_interface(t *testing.T) {
should := require.New(t)
var val interface{}
err := UnmarshalFromString(`"hello"`, &val)
should.Nil(err)
should.Equal("hello", val)
}
func Test_read_custom_interface(t *testing.T) {
should := require.New(t)
var val MyInterface
RegisterTypeDecoder("jsoniter.MyInterface", func(ptr unsafe.Pointer, iter *Iterator) {
*((*MyInterface)(ptr)) = MyString(iter.ReadString())
})
err := UnmarshalFromString(`"hello"`, &val)
should.Nil(err)
should.Equal("hello", val.Hello())
}
func Test_decode_object_contain_empty_interface(t *testing.T) {
type TestObject struct {
Field interface{}
}
should := require.New(t)
obj := TestObject{}
obj.Field = 1024
should.Nil(UnmarshalFromString(`{"Field": "hello"}`, &obj))
should.Equal("hello", obj.Field)
}
func Test_decode_object_contain_non_empty_interface(t *testing.T) {
type TestObject struct {
Field MyInterface
}
should := require.New(t)
obj := TestObject{}
obj.Field = MyString("abc")
should.Nil(UnmarshalFromString(`{"Field": "hello"}`, &obj))
should.Equal(MyString("hello"), obj.Field)
}
func Test_encode_object_contain_empty_interface(t *testing.T) {
type TestObject struct {
Field interface{}
}
should := require.New(t)
obj := TestObject{}
obj.Field = 1024
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Field":1024}`, str)
}
func Test_encode_object_contain_non_empty_interface(t *testing.T) {
type TestObject struct {
Field MyInterface
}
should := require.New(t)
obj := TestObject{}
obj.Field = MyString("hello")
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Field":"hello"}`, str)
}

View File

@ -1,9 +1,9 @@
package jsoniter package jsoniter
import ( import (
"testing"
"bytes" "bytes"
"io" "io"
"testing"
) )
func Test_read_by_one(t *testing.T) { func Test_read_by_one(t *testing.T) {

View File

@ -1,28 +1,27 @@
package jsoniter package jsoniter
import ( import (
"testing"
"os"
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"os"
"testing"
) )
func Test_large_file(t *testing.T) { //func Test_large_file(t *testing.T) {
file, err := os.Open("/tmp/large-file.json") // file, err := os.Open("/tmp/large-file.json")
if err != nil { // if err != nil {
t.Fatal(err) // t.Fatal(err)
} // }
iter := Parse(file, 4096) // iter := Parse(file, 4096)
count := 0 // count := 0
for iter.ReadArray() { // for iter.ReadArray() {
iter.Skip() // iter.Skip()
count++ // count++
} // }
if count != 11351 { // if count != 11351 {
t.Fatal(count) // t.Fatal(count)
} // }
} //}
func Benchmark_jsoniter_large_file(b *testing.B) { func Benchmark_jsoniter_large_file(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()

View File

@ -2,37 +2,68 @@ package jsoniter
import ( import (
"testing" "testing"
"reflect" "github.com/json-iterator/go/require"
"fmt"
) )
func Test_read_map(t *testing.T) { func Test_read_map(t *testing.T) {
should := require.New(t)
iter := ParseString(`{"hello": "world"}`) iter := ParseString(`{"hello": "world"}`)
m := map[string]string{"1": "2"} m := map[string]string{"1": "2"}
iter.Read(&m) iter.ReadVal(&m)
copy(iter.buf, []byte{0,0,0,0,0,0}) copy(iter.buf, []byte{0, 0, 0, 0, 0, 0})
if !reflect.DeepEqual(map[string]string{"1": "2", "hello": "world"}, m) { should.Equal(map[string]string{"1": "2", "hello": "world"}, m)
fmt.Println(iter.Error)
t.Fatal(m)
}
} }
func Test_read_map_of_interface(t *testing.T) { func Test_read_map_of_interface(t *testing.T) {
should := require.New(t)
iter := ParseString(`{"hello": "world"}`) iter := ParseString(`{"hello": "world"}`)
m := map[string]interface{}{"1": "2"} m := map[string]interface{}{"1": "2"}
iter.Read(&m) iter.ReadVal(&m)
if !reflect.DeepEqual(map[string]interface{}{"1": "2", "hello": "world"}, m) { should.Equal(map[string]interface{}{"1": "2", "hello": "world"}, m)
fmt.Println(iter.Error) iter = ParseString(`{"hello": "world"}`)
t.Fatal(m) should.Equal(map[string]interface{}{"hello": "world"}, iter.Read())
}
} }
func Test_read_map_of_any(t *testing.T) { func Test_wrap_map(t *testing.T) {
iter := ParseString(`{"hello": "world"}`) should := require.New(t)
m := map[string]Any{"1": *MakeAny("2")} any := Wrap(map[string]string{"Field1": "hello"})
iter.Read(&m) should.Equal("hello", any.Get("Field1").ToString())
if !reflect.DeepEqual(map[string]Any{"1": *MakeAny("2"), "hello": *MakeAny("world")}, m) { any = Wrap(map[string]string{"Field1": "hello"})
fmt.Println(iter.Error) should.Equal(1, any.Size())
t.Fatal(m) any = Wrap(map[string]string{"Field1": "hello"})
vals := map[string]string{}
var k string
var v Any
for next, hasNext := any.IterateObject(); hasNext; {
k, v, hasNext = next()
if v.ValueType() == String {
vals[k] = v.ToString()
}
} }
should.Equal(map[string]string{"Field1":"hello"}, vals)
}
func Test_map_wrapper_any_get_all(t *testing.T) {
should := require.New(t)
any := Wrap(map[string][]int{"Field1": []int{1, 2}})
should.Equal(`{"Field1":1}`, any.Get('*', 0).ToString())
}
func Test_write_val_map(t *testing.T) {
should := require.New(t)
val := map[string]string{"1": "2"}
str, err := MarshalToString(val)
should.Nil(err)
should.Equal(`{"1":"2"}`, str)
}
func Test_slice_of_map(t *testing.T) {
should := require.New(t)
val := []map[string]string{{"1": "2"}}
str, err := MarshalToString(val)
should.Nil(err)
should.Equal(`[{"1":"2"}]`, str)
val = []map[string]string{}
should.Nil(UnmarshalFromString(str, &val))
should.Equal("2", val[0]["1"])
} }

View File

@ -1,9 +1,9 @@
package jsoniter package jsoniter
import ( import (
"testing"
"reflect"
"encoding/json" "encoding/json"
"reflect"
"testing"
) )
type Level1 struct { type Level1 struct {
@ -28,14 +28,14 @@ func Test_nested(t *testing.T) {
case "world": case "world":
l2.World = iter.ReadString() l2.World = iter.ReadString()
default: default:
iter.ReportError("bind l2", "unexpected field: " + l2Field) iter.reportError("bind l2", "unexpected field: "+l2Field)
} }
} }
l2Array = append(l2Array, l2) l2Array = append(l2Array, l2)
} }
l1.Hello = l2Array l1.Hello = l2Array
default: default:
iter.ReportError("bind l1", "unexpected field: " + l1Field) iter.reportError("bind l1", "unexpected field: "+l1Field)
} }
} }
if !reflect.DeepEqual(l1, Level1{ if !reflect.DeepEqual(l1, Level1{

View File

@ -2,16 +2,44 @@ package jsoniter
import ( import (
"testing" "testing"
"github.com/json-iterator/go/require"
"bytes"
) )
func Test_null(t *testing.T) { func Test_read_null(t *testing.T) {
should := require.New(t)
iter := ParseString(`null`) iter := ParseString(`null`)
if iter.ReadNull() != true { should.True(iter.ReadNil())
t.FailNow() iter = ParseString(`null`)
} should.Nil(iter.Read())
iter = ParseString(`null`)
any, err := UnmarshalAnyFromString(`null`)
should.Nil(err)
should.Equal(0, any.ToInt())
should.Equal(float64(0), any.ToFloat64())
should.Equal("", any.ToString())
should.False(any.ToBool())
} }
func Test_null_object(t *testing.T) { func Test_write_null(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.WriteNil()
stream.Flush()
should.Nil(stream.Error)
should.Equal("null", buf.String())
}
func Test_encode_null(t *testing.T) {
should := require.New(t)
str, err := MarshalToString(nil)
should.Nil(err)
should.Equal("null", str)
}
func Test_decode_null_object(t *testing.T) {
should := require.New(t)
iter := ParseString(`[null,"a"]`) iter := ParseString(`[null,"a"]`)
iter.ReadArray() iter.ReadArray()
if iter.ReadObject() != "" { if iter.ReadObject() != "" {
@ -21,9 +49,15 @@ func Test_null_object(t *testing.T) {
if iter.ReadString() != "a" { if iter.ReadString() != "a" {
t.FailNow() t.FailNow()
} }
type TestObject struct {
Field string
}
objs := []TestObject{}
should.Nil(UnmarshalFromString("[null]", &objs))
should.Len(objs, 1)
} }
func Test_null_array(t *testing.T) { func Test_decode_null_array(t *testing.T) {
iter := ParseString(`[null,"a"]`) iter := ParseString(`[null,"a"]`)
iter.ReadArray() iter.ReadArray()
if iter.ReadArray() != false { if iter.ReadArray() != false {
@ -35,19 +69,16 @@ func Test_null_array(t *testing.T) {
} }
} }
func Test_null_string(t *testing.T) { func Test_decode_null_string(t *testing.T) {
should := require.New(t)
iter := ParseString(`[null,"a"]`) iter := ParseString(`[null,"a"]`)
iter.ReadArray() should.True(iter.ReadArray())
if iter.ReadString() != "" { should.Equal("", iter.ReadString())
t.FailNow() should.True(iter.ReadArray())
} should.Equal("a", iter.ReadString())
iter.ReadArray()
if iter.ReadString() != "a" {
t.FailNow()
}
} }
func Test_null_skip(t *testing.T) { func Test_decode_null_skip(t *testing.T) {
iter := ParseString(`[null,"a"]`) iter := ParseString(`[null,"a"]`)
iter.ReadArray() iter.ReadArray()
iter.Skip() iter.Skip()

View File

@ -1,58 +1,53 @@
package jsoniter package jsoniter
import ( import (
"testing"
"encoding/json" "encoding/json"
"fmt" "testing"
"github.com/json-iterator/go/require"
"bytes"
) )
func Test_empty_object(t *testing.T) { func Test_empty_object(t *testing.T) {
should := require.New(t)
iter := ParseString(`{}`) iter := ParseString(`{}`)
field := iter.ReadObject() field := iter.ReadObject()
if field != "" { should.Equal("", field)
t.Fatal(field) iter = ParseString(`{}`)
} iter.ReadObjectCB(func(iter *Iterator, field string) bool {
should.FailNow("should not call")
return true
})
} }
func Test_one_field(t *testing.T) { func Test_one_field(t *testing.T) {
should := require.New(t)
iter := ParseString(`{"a": "b"}`) iter := ParseString(`{"a": "b"}`)
field := iter.ReadObject() field := iter.ReadObject()
if field != "a" { should.Equal("a", field)
fmt.Println(iter.Error)
t.Fatal(field)
}
value := iter.ReadString() value := iter.ReadString()
if value != "b" { should.Equal("b", value)
t.Fatal(field)
}
field = iter.ReadObject() field = iter.ReadObject()
if field != "" { should.Equal("", field)
t.Fatal(field) iter = ParseString(`{"a": "b"}`)
} should.True(iter.ReadObjectCB(func(iter *Iterator, field string) bool {
should.Equal("a", field)
return true
}))
} }
func Test_two_field(t *testing.T) { func Test_two_field(t *testing.T) {
should := require.New(t)
iter := ParseString(`{ "a": "b" , "c": "d" }`) iter := ParseString(`{ "a": "b" , "c": "d" }`)
field := iter.ReadObject() field := iter.ReadObject()
if field != "a" { should.Equal("a", field)
t.Fatal(field)
}
value := iter.ReadString() value := iter.ReadString()
if value != "b" { should.Equal("b", value)
t.Fatal(field)
}
field = iter.ReadObject() field = iter.ReadObject()
if field != "c" { should.Equal("c", field)
t.Fatal(field)
}
value = iter.ReadString() value = iter.ReadString()
if value != "d" { should.Equal("d", value)
t.Fatal(field)
}
field = iter.ReadObject() field = iter.ReadObject()
if field != "" { should.Equal("", field)
t.Fatal(field)
}
iter = ParseString(`{"field1": "1", "field2": 2}`) iter = ParseString(`{"field1": "1", "field2": 2}`)
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
switch field { switch field {
@ -61,17 +56,179 @@ func Test_two_field(t *testing.T) {
case "field2": case "field2":
iter.ReadInt64() iter.ReadInt64()
default: default:
iter.ReportError("bind object", "unexpected field") iter.reportError("bind object", "unexpected field")
} }
} }
} }
type TestObj struct { func Test_read_object_as_any(t *testing.T) {
Field1 string should := require.New(t)
Field2 uint64 any, err := UnmarshalAnyFromString(`{"a":"b","c":"d"}`)
should.Nil(err)
should.Equal(`{"a":"b","c":"d"}`, any.ToString())
// partial parse
should.Equal("b", any.Get("a").ToString())
should.Equal("d", any.Get("c").ToString())
should.Equal(2, len(any.Keys()))
any, err = UnmarshalAnyFromString(`{"a":"b","c":"d"}`)
// full parse
should.Equal(2, len(any.Keys()))
should.Equal(2, any.Size())
should.True(any.ToBool())
should.Equal(1, any.ToInt())
}
func Test_object_any_lazy_iterator(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{"a":"b","c":"d"}`)
should.Nil(err)
// iterator parse
vals := map[string]string{}
var k string
var v Any
next, hasNext := any.IterateObject()
should.True(hasNext)
k, v, hasNext = next()
should.True(hasNext)
vals[k] = v.ToString()
// trigger full parse
should.Equal(2, len(any.Keys()))
k, v, hasNext = next()
should.False(hasNext)
vals[k] = v.ToString()
should.Equal(map[string]string{"a":"b", "c":"d"}, vals)
vals = map[string]string{}
for next, hasNext := any.IterateObject(); hasNext; {
k, v, hasNext = next()
if v.ValueType() == String {
vals[k] = v.ToString()
}
}
should.Equal(map[string]string{"a":"b", "c":"d"}, vals)
}
func Test_object_any_with_two_lazy_iterators(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{"a":"b","c":"d","e":"f"}`)
should.Nil(err)
var k string
var v Any
next1, hasNext1 := any.IterateObject()
next2, hasNext2 := any.IterateObject()
should.True(hasNext1)
k, v, hasNext1 = next1()
should.True(hasNext1)
should.Equal("a", k)
should.Equal("b", v.ToString())
should.True(hasNext2)
k, v, hasNext2 = next2()
should.True(hasNext2)
should.Equal("a", k)
should.Equal("b", v.ToString())
k, v, hasNext1 = next1()
should.True(hasNext1)
should.Equal("c", k)
should.Equal("d", v.ToString())
k, v, hasNext2 = next2()
should.True(hasNext2)
should.Equal("c", k)
should.Equal("d", v.ToString())
}
func Test_object_lazy_any_get(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{"a":{"b":{"c":"d"}}}`)
should.Nil(err)
should.Equal("d", any.Get("a", "b", "c").ToString())
}
func Test_object_lazy_any_get_all(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{"a":[0],"b":[1]}`)
should.Nil(err)
should.Contains(any.Get('*', 0).ToString(), `"a":0`)
}
func Test_object_lazy_any_get_invalid(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{}`)
should.Nil(err)
should.Equal(Invalid, any.Get("a", "b", "c").ValueType())
should.Equal(Invalid, any.Get(1).ValueType())
}
func Test_object_lazy_any_set(t *testing.T) {
should := require.New(t)
any, err := UnmarshalAnyFromString(`{"a":{"b":{"c":"d"}}}`)
should.Nil(err)
any.GetObject()["a"] = WrapInt64(1)
str, err := MarshalToString(any)
should.Nil(err)
should.Equal(`{"a":1}`, str)
}
func Test_wrap_object(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 string
field2 string
}
any := Wrap(TestObject{"hello", "world"})
should.Equal("hello", any.Get("Field1").ToString())
any = Wrap(TestObject{"hello", "world"})
should.Equal(2, any.Size())
any = Wrap(TestObject{"hello", "world"})
vals := map[string]string{}
var k string
var v Any
for next, hasNext := any.IterateObject(); hasNext; {
k, v, hasNext = next()
if v.ValueType() == String {
vals[k] = v.ToString()
}
}
should.Equal(map[string]string{"Field1":"hello"}, vals)
}
func Test_object_wrapper_any_get_all(t *testing.T) {
should := require.New(t)
type TestObject struct {
Field1 []int
Field2 []int
}
any := Wrap(TestObject{[]int{1, 2}, []int{3, 4}})
should.Contains(any.Get('*', 0).ToString(), `"Field2":3`)
}
func Test_write_object(t *testing.T) {
should := require.New(t)
buf := &bytes.Buffer{}
stream := NewStream(buf, 4096)
stream.IndentionStep = 2
stream.WriteObjectStart()
stream.WriteObjectField("hello")
stream.WriteInt(1)
stream.WriteMore()
stream.WriteObjectField("world")
stream.WriteInt(2)
stream.WriteObjectEnd()
stream.Flush()
should.Nil(stream.Error)
should.Equal("{\n \"hello\":1,\n \"world\":2\n}", buf.String())
} }
func Benchmark_jsoniter_object(b *testing.B) { func Benchmark_jsoniter_object(b *testing.B) {
type TestObj struct {
Field1 string
Field2 uint64
}
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter := ParseString(`{"field1": "1", "field2": 2}`) iter := ParseString(`{"field1": "1", "field2": 2}`)
obj := TestObj{} obj := TestObj{}
@ -82,13 +239,17 @@ func Benchmark_jsoniter_object(b *testing.B) {
case "field2": case "field2":
obj.Field2 = iter.ReadUint64() obj.Field2 = iter.ReadUint64()
default: default:
iter.ReportError("bind object", "unexpected field") iter.reportError("bind object", "unexpected field")
} }
} }
} }
} }
func Benchmark_json_object(b *testing.B) { func Benchmark_json_object(b *testing.B) {
type TestObj struct {
Field1 string
Field2 uint64
}
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
result := TestObj{} result := TestObj{}
json.Unmarshal([]byte(`{"field1": "1", "field2": 2}`), &result) json.Unmarshal([]byte(`{"field1": "1", "field2": 2}`), &result)

46
jsoniter_optional_test.go Normal file
View File

@ -0,0 +1,46 @@
package jsoniter
import (
"testing"
"github.com/json-iterator/go/require"
)
func Test_encode_optional_int_pointer(t *testing.T) {
should := require.New(t)
var ptr *int
str, err := MarshalToString(ptr)
should.Nil(err)
should.Equal("null", str)
val := 100
ptr = &val
str, err = MarshalToString(ptr)
should.Nil(err)
should.Equal("100", str)
}
func Test_decode_struct_with_optional_field(t *testing.T) {
should := require.New(t)
type TestObject struct {
field1 *string
field2 *string
}
obj := TestObject{}
UnmarshalFromString(`{"field1": null, "field2": "world"}`, &obj)
should.Nil(obj.field1)
should.Equal("world", *obj.field2)
}
func Test_encode_struct_with_optional_field(t *testing.T) {
should := require.New(t)
type TestObject struct {
field1 *string
field2 *string
}
obj := TestObject{}
world := "world"
obj.field2 = &world
str, err := MarshalToString(obj)
should.Nil(err)
should.Contains(str, `"field1":null`)
should.Contains(str, `"field2":"world"`)
}

View File

@ -1,819 +0,0 @@
package jsoniter
import (
"reflect"
"errors"
"fmt"
"unsafe"
"sync/atomic"
"strings"
"io"
"strconv"
)
type Decoder interface {
decode(ptr unsafe.Pointer, iter *Iterator)
}
type stringDecoder struct {
}
func (decoder *stringDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*string)(ptr)) = iter.ReadString()
}
type intDecoder struct {
}
func (decoder *intDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*int)(ptr)) = iter.ReadInt()
}
type int8Decoder struct {
}
func (decoder *int8Decoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*int8)(ptr)) = iter.ReadInt8()
}
type int16Decoder struct {
}
func (decoder *int16Decoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*int16)(ptr)) = iter.ReadInt16()
}
type int32Decoder struct {
}
func (decoder *int32Decoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*int32)(ptr)) = iter.ReadInt32()
}
type int64Decoder struct {
}
func (decoder *int64Decoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*int64)(ptr)) = iter.ReadInt64()
}
type uintDecoder struct {
}
func (decoder *uintDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*uint)(ptr)) = iter.ReadUint()
}
type uint8Decoder struct {
}
func (decoder *uint8Decoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*uint8)(ptr)) = iter.ReadUint8()
}
type uint16Decoder struct {
}
func (decoder *uint16Decoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*uint16)(ptr)) = iter.ReadUint16()
}
type uint32Decoder struct {
}
func (decoder *uint32Decoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*uint32)(ptr)) = iter.ReadUint32()
}
type uint64Decoder struct {
}
func (decoder *uint64Decoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*uint64)(ptr)) = iter.ReadUint64()
}
type float32Decoder struct {
}
func (decoder *float32Decoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*float32)(ptr)) = iter.ReadFloat32()
}
type float64Decoder struct {
}
func (decoder *float64Decoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*float64)(ptr)) = iter.ReadFloat64()
}
type boolDecoder struct {
}
func (decoder *boolDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*bool)(ptr)) = iter.ReadBool()
}
type interfaceDecoder struct {
}
func (decoder *interfaceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*interface{})(ptr)) = iter.ReadAny().Get()
}
type anyDecoder struct {
}
func (decoder *anyDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*Any)(ptr)) = *iter.ReadAny()
}
type stringNumberDecoder struct {
elemDecoder Decoder
}
func (decoder *stringNumberDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
c := iter.readByte()
if c != '"' {
iter.ReportError("stringNumberDecoder", `expect "`)
return
}
decoder.elemDecoder.decode(ptr, iter)
if iter.Error != nil {
return
}
c = iter.readByte()
if c != '"' {
iter.ReportError("stringNumberDecoder", `expect "`)
return
}
}
type optionalDecoder struct {
valueType reflect.Type
valueDecoder Decoder
}
func (decoder *optionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNull() {
*((*unsafe.Pointer)(ptr)) = nil
} else {
value := reflect.New(decoder.valueType)
decoder.valueDecoder.decode(unsafe.Pointer(value.Pointer()), iter)
*((*uintptr)(ptr)) = value.Pointer()
}
}
type generalStructDecoder struct {
type_ reflect.Type
fields map[string]*structFieldDecoder
}
func (decoder *generalStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
fieldDecoder := decoder.fields[field]
if fieldDecoder == nil {
iter.Skip()
} else {
fieldDecoder.decode(ptr, iter)
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
}
}
type skipDecoder struct {
type_ reflect.Type
}
func (decoder *skipDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
iter.Skip()
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
}
}
type oneFieldStructDecoder struct {
type_ reflect.Type
fieldName string
fieldDecoder *structFieldDecoder
}
func (decoder *oneFieldStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
if field == decoder.fieldName {
decoder.fieldDecoder.decode(ptr, iter)
} else {
iter.Skip()
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
}
}
type twoFieldsStructDecoder struct {
type_ reflect.Type
fieldName1 string
fieldDecoder1 *structFieldDecoder
fieldName2 string
fieldDecoder2 *structFieldDecoder
}
func (decoder *twoFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
switch field {
case decoder.fieldName1:
decoder.fieldDecoder1.decode(ptr, iter)
case decoder.fieldName2:
decoder.fieldDecoder2.decode(ptr, iter)
default:
iter.Skip()
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
}
}
type threeFieldsStructDecoder struct {
type_ reflect.Type
fieldName1 string
fieldDecoder1 *structFieldDecoder
fieldName2 string
fieldDecoder2 *structFieldDecoder
fieldName3 string
fieldDecoder3 *structFieldDecoder
}
func (decoder *threeFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
switch field {
case decoder.fieldName1:
decoder.fieldDecoder1.decode(ptr, iter)
case decoder.fieldName2:
decoder.fieldDecoder2.decode(ptr, iter)
case decoder.fieldName3:
decoder.fieldDecoder3.decode(ptr, iter)
default:
iter.Skip()
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
}
}
type fourFieldsStructDecoder struct {
type_ reflect.Type
fieldName1 string
fieldDecoder1 *structFieldDecoder
fieldName2 string
fieldDecoder2 *structFieldDecoder
fieldName3 string
fieldDecoder3 *structFieldDecoder
fieldName4 string
fieldDecoder4 *structFieldDecoder
}
func (decoder *fourFieldsStructDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
switch field {
case decoder.fieldName1:
decoder.fieldDecoder1.decode(ptr, iter)
case decoder.fieldName2:
decoder.fieldDecoder2.decode(ptr, iter)
case decoder.fieldName3:
decoder.fieldDecoder3.decode(ptr, iter)
case decoder.fieldName4:
decoder.fieldDecoder4.decode(ptr, iter)
default:
iter.Skip()
}
}
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
}
}
type structFieldDecoder struct {
field *reflect.StructField
fieldDecoder Decoder
}
func (decoder *structFieldDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
fieldPtr := uintptr(ptr) + decoder.field.Offset
decoder.fieldDecoder.decode(unsafe.Pointer(fieldPtr), iter)
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%s: %s", decoder.field.Name, iter.Error.Error())
}
}
type mapDecoder struct {
mapType reflect.Type
elemType reflect.Type
elemDecoder Decoder
mapInterface emptyInterface
}
func (decoder *mapDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
// dark magic to cast unsafe.Pointer back to interface{} using reflect.Type
mapInterface := decoder.mapInterface
mapInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
realVal := reflect.ValueOf(*realInterface).Elem()
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
elem := reflect.New(decoder.elemType)
decoder.elemDecoder.decode(unsafe.Pointer(elem.Pointer()), iter)
realVal.SetMapIndex(reflect.ValueOf(string([]byte(field))), elem.Elem())
}
}
type sliceDecoder struct {
sliceType reflect.Type
elemType reflect.Type
elemDecoder Decoder
}
// sliceHeader is a safe version of SliceHeader used within this package.
type sliceHeader struct {
Data unsafe.Pointer
Len int
Cap int
}
func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.doDecode(ptr, iter)
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
}
}
func (decoder *sliceDecoder) doDecode(ptr unsafe.Pointer, iter *Iterator) {
slice := (*sliceHeader)(ptr)
reuseSlice(slice, decoder.sliceType, 4)
if !iter.ReadArray() {
return
}
offset := uintptr(0)
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
if !iter.ReadArray() {
slice.Len = 1
return
}
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
if !iter.ReadArray() {
slice.Len = 2
return
}
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
if !iter.ReadArray() {
slice.Len = 3
return
}
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
slice.Len = 4
for iter.ReadArray() {
growOne(slice, decoder.sliceType, decoder.elemType)
offset += decoder.elemType.Size()
decoder.elemDecoder.decode(unsafe.Pointer(uintptr(slice.Data) + offset), iter)
}
}
// grow grows the slice s so that it can hold extra more values, allocating
// more capacity if needed. It also returns the old and new slice lengths.
func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Type) {
newLen := slice.Len + 1
if newLen <= slice.Cap {
slice.Len = newLen
return
}
newCap := slice.Cap
if newCap == 0 {
newCap = 1
} else {
for newCap < newLen {
if slice.Len < 1024 {
newCap += newCap
} else {
newCap += newCap / 4
}
}
}
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, newLen, newCap).Pointer())
originalBytesCount := uintptr(slice.Len) * elementType.Size()
srcPtr := (*[1 << 30]byte)(slice.Data)
dstPtr := (*[1 << 30]byte)(dst)
for i := uintptr(0); i < originalBytesCount; i++ {
dstPtr[i] = srcPtr[i]
}
slice.Len = newLen
slice.Cap = newCap
slice.Data = dst
}
func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
if expectedCap <= slice.Cap {
return
}
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, 0, expectedCap).Pointer())
slice.Cap = expectedCap
slice.Data = dst
}
var DECODERS unsafe.Pointer
func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
retry := true
for retry {
ptr := atomic.LoadPointer(&DECODERS)
cache := *(*map[reflect.Type]Decoder)(ptr)
copy := map[reflect.Type]Decoder{}
for k, v := range cache {
copy[k] = v
}
copy[cacheKey] = decoder
retry = !atomic.CompareAndSwapPointer(&DECODERS, ptr, unsafe.Pointer(&copy))
}
}
func getDecoderFromCache(cacheKey reflect.Type) Decoder {
ptr := atomic.LoadPointer(&DECODERS)
cache := *(*map[reflect.Type]Decoder)(ptr)
return cache[cacheKey]
}
var typeDecoders map[string]Decoder
var fieldDecoders map[string]Decoder
var fieldCustomizers []FieldCustomizerFunc
func init() {
typeDecoders = map[string]Decoder{}
fieldDecoders = map[string]Decoder{}
fieldCustomizers = []FieldCustomizerFunc{}
atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
}
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
type FieldCustomizerFunc func(type_ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc)
type funcDecoder struct {
func_ DecoderFunc
}
func (decoder *funcDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
decoder.func_(ptr, iter)
}
func RegisterTypeDecoder(type_ string, func_ DecoderFunc) {
typeDecoders[type_] = &funcDecoder{func_}
}
func RegisterFieldDecoder(type_ string, field string, func_ DecoderFunc) {
fieldDecoders[fmt.Sprintf("%s/%s", type_, field)] = &funcDecoder{func_}
}
func RegisterFieldCustomizer(func_ FieldCustomizerFunc) {
fieldCustomizers = append(fieldCustomizers, func_)
}
func ClearDecoders() {
typeDecoders = map[string]Decoder{}
fieldDecoders = map[string]Decoder{}
}
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *struct{}
word unsafe.Pointer
}
func (iter *Iterator) ReadAny() (ret *Any) {
valueType := iter.WhatIsNext()
switch valueType {
case String:
return MakeAny(iter.ReadString())
case Number:
return iter.readNumber()
case Null:
return MakeAny(nil)
case Bool:
return MakeAny(iter.ReadBool())
case Array:
val := []interface{}{}
for (iter.ReadArray()) {
element := iter.ReadAny()
if iter.Error != nil {
return
}
val = append(val, element.val)
}
return MakeAny(val)
case Object:
val := map[string]interface{}{}
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
element := iter.ReadAny()
if iter.Error != nil {
return
}
val[string([]byte(field))] = element.val
}
return MakeAny(val)
default:
iter.ReportError("ReadAny", fmt.Sprintf("unexpected value type: %v", valueType))
return MakeAny(nil)
}
}
func (iter *Iterator) readNumber() (ret *Any) {
strBuf := [8]byte{}
str := strBuf[0:0]
hasMore := true
foundFloat := false
foundNegative := false
for(hasMore) {
for i := iter.head; i < iter.tail; i++ {
c := iter.buf[i]
switch c {
case '-':
foundNegative = true
str = append(str, c)
continue
case '+', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
str = append(str, c)
continue
case '.', 'e', 'E':
foundFloat = true
str = append(str, c)
continue
default:
hasMore = false
break
}
}
if hasMore {
if !iter.loadMore() {
break
}
}
}
if iter.Error != nil && iter.Error != io.EOF {
return
}
number := *(*string)(unsafe.Pointer(&str))
if foundFloat {
val, err := strconv.ParseFloat(number, 64)
if err != nil {
iter.Error = err
return
}
return MakeAny(val)
}
if foundNegative {
val, err := strconv.ParseInt(number, 10, 64)
if err != nil {
iter.Error = err
return
}
return MakeAny(val)
}
val, err := strconv.ParseUint(number, 10, 64)
if err != nil {
iter.Error = err
return
}
return MakeAny(val)
}
func (iter *Iterator) Read(obj interface{}) {
type_ := reflect.TypeOf(obj)
cacheKey := type_.Elem()
cachedDecoder := getDecoderFromCache(cacheKey)
if cachedDecoder == nil {
decoder, err := decoderOfType(type_)
if err != nil {
iter.Error = err
return
}
cachedDecoder = decoder
addDecoderToCache(cacheKey, decoder)
}
e := (*emptyInterface)(unsafe.Pointer(&obj))
cachedDecoder.decode(e.word, iter)
}
type prefix string
func (p prefix) addTo(decoder Decoder, err error) (Decoder, error) {
if err != nil {
return nil, fmt.Errorf("%s: %s", p, err.Error())
}
return decoder, err
}
func decoderOfType(type_ reflect.Type) (Decoder, error) {
switch type_.Kind() {
case reflect.Ptr:
return prefix("ptr").addTo(decoderOfPtr(type_.Elem()))
default:
return nil, errors.New("expect ptr")
}
}
func decoderOfPtr(type_ reflect.Type) (Decoder, error) {
typeName := type_.String()
if typeName == "jsoniter.Any" {
return &anyDecoder{}, nil
}
typeDecoder := typeDecoders[typeName]
if typeDecoder != nil {
return typeDecoder, nil
}
switch type_.Kind() {
case reflect.String:
return &stringDecoder{}, nil
case reflect.Int:
return &intDecoder{}, nil
case reflect.Int8:
return &int8Decoder{}, nil
case reflect.Int16:
return &int16Decoder{}, nil
case reflect.Int32:
return &int32Decoder{}, nil
case reflect.Int64:
return &int64Decoder{}, nil
case reflect.Uint:
return &uintDecoder{}, nil
case reflect.Uint8:
return &uint8Decoder{}, nil
case reflect.Uint16:
return &uint16Decoder{}, nil
case reflect.Uint32:
return &uint32Decoder{}, nil
case reflect.Uint64:
return &uint64Decoder{}, nil
case reflect.Float32:
return &float32Decoder{}, nil
case reflect.Float64:
return &float64Decoder{}, nil
case reflect.Bool:
return &boolDecoder{}, nil
case reflect.Interface:
return &interfaceDecoder{}, nil
case reflect.Struct:
return decoderOfStruct(type_)
case reflect.Slice:
return prefix("[slice]").addTo(decoderOfSlice(type_))
case reflect.Map:
return prefix("[map]").addTo(decoderOfMap(type_))
case reflect.Ptr:
return prefix("[optional]").addTo(decoderOfOptional(type_.Elem()))
default:
return nil, fmt.Errorf("unsupported type: %v", type_)
}
}
func decoderOfOptional(type_ reflect.Type) (Decoder, error) {
decoder, err := decoderOfPtr(type_)
if err != nil {
return nil, err
}
return &optionalDecoder{type_, decoder}, nil
}
func decoderOfStruct(type_ reflect.Type) (Decoder, error) {
fields := map[string]*structFieldDecoder{}
for i := 0; i < type_.NumField(); i++ {
field := type_.Field(i)
fieldDecoderKey := fmt.Sprintf("%s/%s", type_.String(), field.Name)
var fieldNames []string
for _, customizer := range fieldCustomizers {
alternativeFieldNames, func_ := customizer(type_, &field)
if alternativeFieldNames != nil {
fieldNames = alternativeFieldNames
}
if func_ != nil {
fieldDecoders[fieldDecoderKey] = &funcDecoder{func_}
}
}
decoder := fieldDecoders[fieldDecoderKey]
tagParts := strings.Split(field.Tag.Get("json"), ",")
if fieldNames == nil {
switch tagParts[0] {
case "":
fieldNames = []string{field.Name}
case "-":
fieldNames = []string{}
}
}
if decoder == nil {
var err error
decoder, err = decoderOfPtr(field.Type)
if err != nil {
return prefix(fmt.Sprintf("{%s}", field.Name)).addTo(decoder, err)
}
}
if len(tagParts) > 1 && tagParts[1] == "string" {
decoder = &stringNumberDecoder{decoder}
}
for _, fieldName := range fieldNames {
fields[fieldName] = &structFieldDecoder{&field, decoder}
}
}
switch len(fields) {
case 0:
return &skipDecoder{type_}, nil
case 1:
for fieldName, fieldDecoder := range fields {
return &oneFieldStructDecoder{type_, fieldName, fieldDecoder}, nil
}
case 2:
var fieldName1 string
var fieldName2 string
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
if fieldName1 == "" {
fieldName1 = fieldName
fieldDecoder1 = fieldDecoder
} else {
fieldName2 = fieldName
fieldDecoder2 = fieldDecoder
}
}
return &twoFieldsStructDecoder{type_, fieldName1, fieldDecoder1, fieldName2, fieldDecoder2}, nil
case 3:
var fieldName1 string
var fieldName2 string
var fieldName3 string
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
var fieldDecoder3 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
if fieldName1 == "" {
fieldName1 = fieldName
fieldDecoder1 = fieldDecoder
} else if fieldName2 == "" {
fieldName2 = fieldName
fieldDecoder2 = fieldDecoder
} else {
fieldName3 = fieldName
fieldDecoder3 = fieldDecoder
}
}
return &threeFieldsStructDecoder{type_,
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
case 4:
var fieldName1 string
var fieldName2 string
var fieldName3 string
var fieldName4 string
var fieldDecoder1 *structFieldDecoder
var fieldDecoder2 *structFieldDecoder
var fieldDecoder3 *structFieldDecoder
var fieldDecoder4 *structFieldDecoder
for fieldName, fieldDecoder := range fields {
if fieldName1 == "" {
fieldName1 = fieldName
fieldDecoder1 = fieldDecoder
} else if fieldName2 == "" {
fieldName2 = fieldName
fieldDecoder2 = fieldDecoder
} else if fieldName3 == "" {
fieldName3 = fieldName
fieldDecoder3 = fieldDecoder
} else {
fieldName4 = fieldName
fieldDecoder4 = fieldDecoder
}
}
return &fourFieldsStructDecoder{type_,
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
fieldName4, fieldDecoder4}, nil
}
return &generalStructDecoder{type_, fields}, nil
}
func decoderOfSlice(type_ reflect.Type) (Decoder, error) {
decoder, err := decoderOfPtr(type_.Elem())
if err != nil {
return nil, err
}
return &sliceDecoder{type_, type_.Elem(), decoder}, nil
}
func decoderOfMap(type_ reflect.Type) (Decoder, error) {
decoder, err := decoderOfPtr(type_.Elem())
if err != nil {
return nil, err
}
mapInterface := reflect.New(type_).Interface()
return &mapDecoder{type_, type_.Elem(), decoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
}

View File

@ -0,0 +1,154 @@
package jsoniter
import (
"testing"
"fmt"
)
func Test_reflect_str(t *testing.T) {
iter := ParseString(`"hello"`)
str := ""
iter.ReadVal(&str)
if str != "hello" {
fmt.Println(iter.Error)
t.Fatal(str)
}
}
func Test_reflect_ptr_str(t *testing.T) {
iter := ParseString(`"hello"`)
var str *string
iter.ReadVal(&str)
if *str != "hello" {
t.Fatal(str)
}
}
func Test_reflect_int(t *testing.T) {
iter := ParseString(`123`)
val := int(0)
iter.ReadVal(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_int8(t *testing.T) {
iter := ParseString(`123`)
val := int8(0)
iter.ReadVal(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_int16(t *testing.T) {
iter := ParseString(`123`)
val := int16(0)
iter.ReadVal(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_int32(t *testing.T) {
iter := ParseString(`123`)
val := int32(0)
iter.ReadVal(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_int64(t *testing.T) {
iter := ParseString(`123`)
val := int64(0)
iter.ReadVal(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_uint(t *testing.T) {
iter := ParseString(`123`)
val := uint(0)
iter.ReadVal(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_uint8(t *testing.T) {
iter := ParseString(`123`)
val := uint8(0)
iter.ReadVal(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_uint16(t *testing.T) {
iter := ParseString(`123`)
val := uint16(0)
iter.ReadVal(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_uint32(t *testing.T) {
iter := ParseString(`123`)
val := uint32(0)
iter.ReadVal(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_uint64(t *testing.T) {
iter := ParseString(`123`)
val := uint64(0)
iter.ReadVal(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_byte(t *testing.T) {
iter := ParseString(`123`)
val := byte(0)
iter.ReadVal(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_float32(t *testing.T) {
iter := ParseString(`1.23`)
val := float32(0)
iter.ReadVal(&val)
if val != 1.23 {
fmt.Println(iter.Error)
t.Fatal(val)
}
}
func Test_reflect_float64(t *testing.T) {
iter := ParseString(`1.23`)
val := float64(0)
iter.ReadVal(&val)
if val != 1.23 {
fmt.Println(iter.Error)
t.Fatal(val)
}
}
func Test_reflect_bool(t *testing.T) {
iter := ParseString(`true`)
val := false
iter.ReadVal(&val)
if val != true {
fmt.Println(iter.Error)
t.Fatal(val)
}
}

View File

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

View File

@ -1,262 +1,35 @@
package jsoniter package jsoniter
import ( import (
"testing"
"fmt"
"encoding/json" "encoding/json"
"fmt"
"testing"
"unsafe" "unsafe"
"github.com/json-iterator/go/require"
) )
func Test_reflect_str(t *testing.T) { func Test_decode_slice(t *testing.T) {
iter := ParseString(`"hello"`) should := require.New(t)
str := ""
iter.Read(&str)
if str != "hello" {
fmt.Println(iter.Error)
t.Fatal(str)
}
}
func Test_reflect_ptr_str(t *testing.T) {
iter := ParseString(`"hello"`)
var str *string
iter.Read(&str)
if *str != "hello" {
t.Fatal(str)
}
}
func Test_reflect_int(t *testing.T) {
iter := ParseString(`123`)
val := int(0)
iter.Read(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_int8(t *testing.T) {
iter := ParseString(`123`)
val := int8(0)
iter.Read(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_int16(t *testing.T) {
iter := ParseString(`123`)
val := int16(0)
iter.Read(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_int32(t *testing.T) {
iter := ParseString(`123`)
val := int32(0)
iter.Read(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_int64(t *testing.T) {
iter := ParseString(`123`)
val := int64(0)
iter.Read(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_uint(t *testing.T) {
iter := ParseString(`123`)
val := uint(0)
iter.Read(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_uint8(t *testing.T) {
iter := ParseString(`123`)
val := uint8(0)
iter.Read(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_uint16(t *testing.T) {
iter := ParseString(`123`)
val := uint16(0)
iter.Read(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_uint32(t *testing.T) {
iter := ParseString(`123`)
val := uint32(0)
iter.Read(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_uint64(t *testing.T) {
iter := ParseString(`123`)
val := uint64(0)
iter.Read(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_byte(t *testing.T) {
iter := ParseString(`123`)
val := byte(0)
iter.Read(&val)
if val != 123 {
t.Fatal(val)
}
}
func Test_reflect_float32(t *testing.T) {
iter := ParseString(`1.23`)
val := float32(0)
iter.Read(&val)
if val != 1.23 {
fmt.Println(iter.Error)
t.Fatal(val)
}
}
func Test_reflect_float64(t *testing.T) {
iter := ParseString(`1.23`)
val := float64(0)
iter.Read(&val)
if val != 1.23 {
fmt.Println(iter.Error)
t.Fatal(val)
}
}
func Test_reflect_bool(t *testing.T) {
iter := ParseString(`true`)
val := false
iter.Read(&val)
if val != true {
fmt.Println(iter.Error)
t.Fatal(val)
}
}
type StructOfString struct {
field1 string
field2 string
}
func Test_reflect_struct_string(t *testing.T) {
iter := ParseString(`{"field1": "hello", "field2": "world"}`)
struct_ := StructOfString{}
iter.Read(&struct_)
if struct_.field1 != "hello" {
fmt.Println(iter.Error)
t.Fatal(struct_.field1)
}
if struct_.field2 != "world" {
fmt.Println(iter.Error)
t.Fatal(struct_.field1)
}
}
type StructOfStringPtr struct {
field1 *string
field2 *string
}
func Test_reflect_struct_string_ptr(t *testing.T) {
iter := ParseString(`{"field1": null, "field2": "world"}`)
struct_ := StructOfStringPtr{}
iter.Read(&struct_)
if struct_.field1 != nil {
fmt.Println(iter.Error)
t.Fatal(struct_.field1)
}
if *struct_.field2 != "world" {
fmt.Println(iter.Error)
t.Fatal(struct_.field2)
}
}
type StructOfTag struct {
field1 string `json:"field-1"`
field2 string `json:"-"`
field3 int `json:",string"`
}
func Test_reflect_struct_tag_field(t *testing.T) {
iter := ParseString(`{"field-1": "hello", "field2": "", "field3": "100"}`)
struct_ := StructOfTag{field2: "world"}
iter.Read(&struct_)
if struct_.field1 != "hello" {
fmt.Println(iter.Error)
t.Fatal(struct_.field1)
}
if struct_.field2 != "world" {
fmt.Println(iter.Error)
t.Fatal(struct_.field2)
}
if struct_.field3 != 100 {
fmt.Println(iter.Error)
t.Fatal(struct_.field3)
}
}
func Test_reflect_slice(t *testing.T) {
iter := ParseString(`["hello", "world"]`)
slice := make([]string, 0, 5) slice := make([]string, 0, 5)
iter.Read(&slice) UnmarshalFromString(`["hello", "world"]`, &slice)
if len(slice) != 2 { should.Equal([]string{"hello", "world"}, slice)
fmt.Println(iter.Error)
t.Fatal(len(slice))
}
if slice[0] != "hello" {
fmt.Println(iter.Error)
t.Fatal(slice[0])
}
if slice[1] != "world" {
fmt.Println(iter.Error)
t.Fatal(slice[1])
}
} }
func Test_reflect_large_slice(t *testing.T) { func Test_decode_large_slice(t *testing.T) {
iter := ParseString(`[1,2,3,4,5,6,7,8,9]`) should := require.New(t)
slice := make([]int, 0, 1) slice := make([]int, 0, 1)
iter.Read(&slice) UnmarshalFromString(`[1,2,3,4,5,6,7,8,9]`, &slice)
if len(slice) != 9 { should.Equal([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}, slice)
fmt.Println(iter.Error)
t.Fatal(len(slice))
}
if slice[0] != 1 {
fmt.Println(iter.Error)
t.Fatal(slice[0])
}
if slice[8] != 9 {
fmt.Println(iter.Error)
t.Fatal(slice[1])
}
} }
func Test_reflect_nested(t *testing.T) { func Test_decode_nested(t *testing.T) {
type StructOfString struct {
field1 string
field2 string
}
iter := ParseString(`[{"field1": "hello"}, null, {"field2": "world"}]`) iter := ParseString(`[{"field1": "hello"}, null, {"field2": "world"}]`)
slice := []*StructOfString{} slice := []*StructOfString{}
iter.Read(&slice) iter.ReadVal(&slice)
if len(slice) != 3 { if len(slice) != 3 {
fmt.Println(iter.Error) fmt.Println(iter.Error)
t.Fatal(len(slice)) t.Fatal(len(slice))
@ -271,39 +44,40 @@ func Test_reflect_nested(t *testing.T) {
} }
if slice[2].field2 != "world" { if slice[2].field2 != "world" {
fmt.Println(iter.Error) fmt.Println(iter.Error)
t.Fatal(slice[1]) t.Fatal(slice[2])
} }
} }
func Test_reflect_base64(t *testing.T) { func Test_decode_base64(t *testing.T) {
iter := ParseString(`"YWJj"`) iter := ParseString(`"YWJj"`)
val := []byte{} val := []byte{}
RegisterTypeDecoder("[]uint8", func(ptr unsafe.Pointer, iter *Iterator) { RegisterTypeDecoder("[]uint8", func(ptr unsafe.Pointer, iter *Iterator) {
*((*[]byte)(ptr)) = iter.ReadBase64() *((*[]byte)(ptr)) = iter.ReadBase64()
}) })
defer ClearDecoders() defer CleanDecoders()
iter.Read(&val) iter.ReadVal(&val)
if "abc" != string(val) { if "abc" != string(val) {
t.Fatal(string(val)) t.Fatal(string(val))
} }
} }
type StructOfTagOne struct { type StructOfTagOne struct {
field1 string `json:"field1"` Field1 string `json:"field1"`
field2 string `json:"field2"` Field2 string `json:"field2"`
field3 int `json:"field3,string"` Field3 int `json:"field3,string"`
field4 int `json:"field4,string"` Field4 int `json:"field4,string"`
} }
func Benchmark_jsoniter_reflect(b *testing.B) { func Benchmark_jsoniter_reflect(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
iter := NewIterator()
Struct := &StructOfTagOne{}
//var Struct *StructOfTagOne
input := []byte(`{"field3": "100", "field4": "100"}`)
//input := []byte(`null`)
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter := ParseString(`{"field3": "100"}`) iter.ResetBytes(input)
struct_ := StructOfTagOne{} iter.ReadVal(&Struct)
iter.Read(&struct_)
//iter := ParseString(`[1,2,3]`)
//var array []int
//iter.Read(&array)
} }
} }
@ -315,9 +89,9 @@ func Benchmark_jsoniter_direct(b *testing.B) {
//for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { //for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
// switch field { // switch field {
// case "field1": // case "field1":
// struct_.field1 = iter.ReadString() // struct_.Field1 = iter.ReadString()
// case "field2": // case "field2":
// struct_.field2 = iter.ReadString() // struct_.Field2 = iter.ReadString()
// default: // default:
// iter.Skip() // iter.Skip()
// } // }
@ -333,8 +107,8 @@ func Benchmark_jsoniter_direct(b *testing.B) {
func Benchmark_json_reflect(b *testing.B) { func Benchmark_json_reflect(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
struct_ := StructOfTagOne{} Struct := StructOfTagOne{}
json.Unmarshal([]byte(`{"field3": "100"}`), &struct_) json.Unmarshal([]byte(`{"field3": "100"}`), &Struct)
//array := make([]string, 0, 2) //array := make([]string, 0, 2)
//json.Unmarshal([]byte(`["hello", "world"]`), &array) //json.Unmarshal([]byte(`["hello", "world"]`), &array)
} }

View File

@ -1,11 +1,10 @@
package jsoniter package jsoniter
import ( import (
"testing"
"encoding/json" "encoding/json"
"testing"
) )
func Test_skip_number(t *testing.T) { func Test_skip_number(t *testing.T) {
iter := ParseString(`[-0.12, "b"]`) iter := ParseString(`[-0.12, "b"]`)
iter.ReadArray() iter.ReadArray()

View File

@ -1,87 +1,108 @@
package jsoniter package jsoniter
import ( import (
"testing"
"bytes" "bytes"
"encoding/json" "encoding/json"
"testing"
"github.com/json-iterator/go/require"
"fmt"
) )
func Test_string_empty(t *testing.T) { func Test_read_normal_string(t *testing.T) {
iter := Parse(bytes.NewBufferString(`""`), 4096) cases := map[string]string{
val := iter.ReadString() `"0123456789012345678901234567890123456789"`: `0123456789012345678901234567890123456789`,
if iter.Error != nil { `""`: ``,
t.Fatal(iter.Error) `"hello"`: `hello`,
} }
if val != "" { for input, output := range cases {
t.Fatal(val) t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t)
iter := ParseString(input)
should.Equal(output, iter.ReadString())
})
t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t)
iter := Parse(bytes.NewBufferString(input), 2)
should.Equal(output, iter.ReadString())
})
t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t)
iter := ParseString(input)
should.Equal(output, string(iter.ReadStringAsSlice()))
})
t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t)
iter := Parse(bytes.NewBufferString(input), 2)
should.Equal(output, string(iter.ReadStringAsSlice()))
})
} }
} }
func Test_string_hello(t *testing.T) { func Test_read_exotic_string(t *testing.T) {
iter := Parse(bytes.NewBufferString(`"hello"`), 4096) cases := map[string]string{
val := iter.ReadString() `"hel\"lo"`: `hel"lo`,
if iter.Error != nil { `"hel\nlo"`: "hel\nlo",
t.Fatal(iter.Error) `"\u4e2d\u6587"`: "中文",
`"\ud83d\udc4a"`: "\xf0\x9f\x91\x8a", // surrogate
} }
if val != "hello" { for input, output := range cases {
t.Fatal(val) t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t)
iter := ParseString(input)
should.Equal(output, iter.ReadString())
})
t.Run(fmt.Sprintf("%v:%v", input, output), func(t *testing.T) {
should := require.New(t)
iter := Parse(bytes.NewBufferString(input), 2)
should.Equal(output, iter.ReadString())
})
} }
} }
func Test_string_escape_quote(t *testing.T) { func Test_read_string_as_interface(t *testing.T) {
iter := Parse(bytes.NewBufferString(`"hel\"lo"`), 4096) should := require.New(t)
val := iter.ReadString() iter := ParseString(`"hello"`)
if iter.Error != nil { should.Equal("hello", iter.Read())
t.Fatal(iter.Error)
}
if val != `hel"lo` {
t.Fatal(val)
}
} }
func Test_string_escape_newline(t *testing.T) { func Test_read_string_as_any(t *testing.T) {
iter := Parse(bytes.NewBufferString(`"hel\nlo"`), 4096) should := require.New(t)
val := iter.ReadString() any, err := UnmarshalAnyFromString(`"hello"`)
if iter.Error != nil { should.Nil(err)
t.Fatal(iter.Error) should.Equal("hello", any.ToString())
} should.True(any.ToBool())
if val != "hel\nlo" { any, err = UnmarshalAnyFromString(`" "`)
t.Fatal(val) should.False(any.ToBool())
} any, err = UnmarshalAnyFromString(`"false"`)
should.False(any.ToBool())
any, err = UnmarshalAnyFromString(`"123"`)
should.Equal(123, any.ToInt())
} }
func Test_string_escape_unicode(t *testing.T) { func Test_wrap_string(t *testing.T) {
iter := Parse(bytes.NewBufferString(`"\u4e2d\u6587"`), 4096) should := require.New(t)
val := iter.ReadString() any := WrapString("123")
if iter.Error != nil { should.Equal(123, any.ToInt())
t.Fatal(iter.Error)
}
if val != "中文" {
t.Fatal(val)
}
} }
func Test_string_escape_unicode_with_surrogate(t *testing.T) { func Test_write_string(t *testing.T) {
iter := Parse(bytes.NewBufferString(`"\ud83d\udc4a"`), 4096) should := require.New(t)
val := iter.ReadString() str, err := MarshalToString("hello")
if iter.Error != nil { should.Equal(`"hello"`, str)
t.Fatal(iter.Error) should.Nil(err)
} str, err = MarshalToString(`hel"lo`)
if val != "\xf0\x9f\x91\x8a" { should.Equal(`"hel\"lo"`, str)
t.Fatal(val) should.Nil(err)
}
} }
func Test_string_as_bytes(t *testing.T) { func Test_write_val_string(t *testing.T) {
iter := Parse(bytes.NewBufferString(`"hello""world"`), 4096) should := require.New(t)
val := string(iter.readStringAsBytes()) buf := &bytes.Buffer{}
if val != "hello" { stream := NewStream(buf, 4096)
t.Fatal(val) stream.WriteVal("hello")
} stream.Flush()
val = string(iter.readStringAsBytes()) should.Nil(stream.Error)
if val != "world" { should.Equal(`"hello"`, buf.String())
t.Fatal(val)
}
} }
func Benchmark_jsoniter_unicode(b *testing.B) { func Benchmark_jsoniter_unicode(b *testing.B) {
@ -92,10 +113,11 @@ func Benchmark_jsoniter_unicode(b *testing.B) {
} }
func Benchmark_jsoniter_ascii(b *testing.B) { func Benchmark_jsoniter_ascii(b *testing.B) {
iter := ParseString(`"hello, world!"`) iter := NewIterator()
input := []byte(`"hello, world! hello, world!"`)
b.ResetTimer() b.ResetTimer()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter.ResetBytes(iter.buf) iter.ResetBytes(input)
iter.ReadString() iter.ReadString()
} }
} }
@ -105,7 +127,7 @@ func Benchmark_jsoniter_string_as_bytes(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {
iter.ResetBytes(iter.buf) iter.ResetBytes(iter.buf)
iter.readStringAsBytes() iter.ReadStringAsSlice()
} }
} }

View File

@ -0,0 +1,16 @@
package require
// Assertions provides assertion methods around the
// TestingT interface.
type Assertions struct {
t TestingT
}
// New makes a new Assertions object for the specified TestingT.
func New(t TestingT) *Assertions {
return &Assertions{
t: t,
}
}
//go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl

364
require/require.go Normal file
View File

@ -0,0 +1,364 @@
/*
* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
* THIS FILE MUST NOT BE EDITED BY HAND
*/
package require
import (
"github.com/json-iterator/go/assert"
"time"
)
// Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
if !assert.Condition(t, comp, msgAndArgs...) {
t.FailNow()
}
}
// Contains asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
//
// assert.Contains(t, "Hello World", "World", "But 'Hello World' does contain 'World'")
// assert.Contains(t, ["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
// assert.Contains(t, {"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'")
//
// Returns whether the assertion was successful (true) or not (false).
func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
if !assert.Contains(t, s, contains, msgAndArgs...) {
t.FailNow()
}
}
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// assert.Empty(t, obj)
//
// Returns whether the assertion was successful (true) or not (false).
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if !assert.Empty(t, object, msgAndArgs...) {
t.FailNow()
}
}
// Equal asserts that two objects are equal.
//
// assert.Equal(t, 123, 123, "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if !assert.Equal(t, expected, actual, msgAndArgs...) {
t.FailNow()
}
}
// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// assert.EqualError(t, err, expectedErrorString, "An error was expected")
//
// Returns whether the assertion was successful (true) or not (false).
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
if !assert.EqualError(t, theError, errString, msgAndArgs...) {
t.FailNow()
}
}
// EqualValues asserts that two objects are equal or convertable to the same types
// and equal.
//
// assert.EqualValues(t, uint32(123), int32(123), "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if !assert.EqualValues(t, expected, actual, msgAndArgs...) {
t.FailNow()
}
}
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if assert.Error(t, err, "An error was expected") {
// assert.Equal(t, err, expectedError)
// }
//
// Returns whether the assertion was successful (true) or not (false).
func Error(t TestingT, err error, msgAndArgs ...interface{}) {
if !assert.Error(t, err, msgAndArgs...) {
t.FailNow()
}
}
// Exactly asserts that two objects are equal is value and type.
//
// assert.Exactly(t, int32(123), int64(123), "123 and 123 should NOT be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if !assert.Exactly(t, expected, actual, msgAndArgs...) {
t.FailNow()
}
}
// Fail reports a failure through
func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
if !assert.Fail(t, failureMessage, msgAndArgs...) {
t.FailNow()
}
}
// FailNow fails test
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
if !assert.FailNow(t, failureMessage, msgAndArgs...) {
t.FailNow()
}
}
// False asserts that the specified value is false.
//
// assert.False(t, myBool, "myBool should be false")
//
// Returns whether the assertion was successful (true) or not (false).
func False(t TestingT, value bool, msgAndArgs ...interface{}) {
if !assert.False(t, value, msgAndArgs...) {
t.FailNow()
}
}
// Implements asserts that an object is implemented by the specified interface.
//
// assert.Implements(t, (*MyInterface)(nil), new(MyObject), "MyObject")
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
if !assert.Implements(t, interfaceObject, object, msgAndArgs...) {
t.FailNow()
}
}
// InDelta asserts that the two numerals are within delta of each other.
//
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
//
// Returns whether the assertion was successful (true) or not (false).
func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if !assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
t.FailNow()
}
}
// InDeltaSlice is the same as InDelta, except it compares two slices.
func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if !assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) {
t.FailNow()
}
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
if !assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
t.FailNow()
}
}
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
if !assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) {
t.FailNow()
}
}
// IsType asserts that the specified objects are of the same type.
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
if !assert.IsType(t, expectedType, object, msgAndArgs...) {
t.FailNow()
}
}
// JSONEq asserts that two JSON strings are equivalent.
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
if !assert.JSONEq(t, expected, actual, msgAndArgs...) {
t.FailNow()
}
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
// assert.Len(t, mySlice, 3, "The size of slice is not 3")
//
// Returns whether the assertion was successful (true) or not (false).
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) {
if !assert.Len(t, object, length, msgAndArgs...) {
t.FailNow()
}
}
// Nil asserts that the specified object is nil.
//
// assert.Nil(t, err, "err should be nothing")
//
// Returns whether the assertion was successful (true) or not (false).
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if !assert.Nil(t, object, msgAndArgs...) {
t.FailNow()
}
}
// NoError asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if assert.NoError(t, err) {
// assert.Equal(t, actualObj, expectedObj)
// }
//
// Returns whether the assertion was successful (true) or not (false).
func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
if !assert.NoError(t, err, msgAndArgs...) {
t.FailNow()
}
}
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element.
//
// assert.NotContains(t, "Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
// assert.NotContains(t, ["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'")
// assert.NotContains(t, {"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'")
//
// Returns whether the assertion was successful (true) or not (false).
func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
if !assert.NotContains(t, s, contains, msgAndArgs...) {
t.FailNow()
}
}
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// if assert.NotEmpty(t, obj) {
// assert.Equal(t, "two", obj[1])
// }
//
// Returns whether the assertion was successful (true) or not (false).
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if !assert.NotEmpty(t, object, msgAndArgs...) {
t.FailNow()
}
}
// NotEqual asserts that the specified values are NOT equal.
//
// assert.NotEqual(t, obj1, obj2, "two objects shouldn't be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if !assert.NotEqual(t, expected, actual, msgAndArgs...) {
t.FailNow()
}
}
// NotNil asserts that the specified object is not nil.
//
// assert.NotNil(t, err, "err should be something")
//
// Returns whether the assertion was successful (true) or not (false).
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if !assert.NotNil(t, object, msgAndArgs...) {
t.FailNow()
}
}
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// assert.NotPanics(t, func(){
// RemainCalm()
// }, "Calling RemainCalm() should NOT panic")
//
// Returns whether the assertion was successful (true) or not (false).
func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if !assert.NotPanics(t, f, msgAndArgs...) {
t.FailNow()
}
}
// NotRegexp asserts that a specified regexp does not match a string.
//
// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
// assert.NotRegexp(t, "^start", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
if !assert.NotRegexp(t, rx, str, msgAndArgs...) {
t.FailNow()
}
}
// NotZero asserts that i is not the zero value for its type and returns the truth.
func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
if !assert.NotZero(t, i, msgAndArgs...) {
t.FailNow()
}
}
// Panics asserts that the code inside the specified PanicTestFunc panics.
//
// assert.Panics(t, func(){
// GoCrazy()
// }, "Calling GoCrazy() should panic")
//
// Returns whether the assertion was successful (true) or not (false).
func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if !assert.Panics(t, f, msgAndArgs...) {
t.FailNow()
}
}
// Regexp asserts that a specified regexp matches a string.
//
// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
// assert.Regexp(t, "start...$", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
if !assert.Regexp(t, rx, str, msgAndArgs...) {
t.FailNow()
}
}
// True asserts that the specified value is true.
//
// assert.True(t, myBool, "myBool should be true")
//
// Returns whether the assertion was successful (true) or not (false).
func True(t TestingT, value bool, msgAndArgs ...interface{}) {
if !assert.True(t, value, msgAndArgs...) {
t.FailNow()
}
}
// WithinDuration asserts that the two times are within duration delta of each other.
//
// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
//
// Returns whether the assertion was successful (true) or not (false).
func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
if !assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
t.FailNow()
}
}
// Zero asserts that i is the zero value for its type and returns the truth.
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
if !assert.Zero(t, i, msgAndArgs...) {
t.FailNow()
}
}

298
require/require_forward.go Normal file
View File

@ -0,0 +1,298 @@
/*
* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
* THIS FILE MUST NOT BE EDITED BY HAND
*/
package require
import (
"github.com/json-iterator/go/assert"
"time"
)
// Condition uses a Comparison to assert a complex condition.
func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
Condition(a.t, comp, msgAndArgs...)
}
// Contains asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
//
// a.Contains("Hello World", "World", "But 'Hello World' does contain 'World'")
// a.Contains(["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'")
// a.Contains({"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
Contains(a.t, s, contains, msgAndArgs...)
}
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// a.Empty(obj)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
Empty(a.t, object, msgAndArgs...)
}
// Equal asserts that two objects are equal.
//
// a.Equal(123, 123, "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
Equal(a.t, expected, actual, msgAndArgs...)
}
// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// a.EqualError(err, expectedErrorString, "An error was expected")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
EqualError(a.t, theError, errString, msgAndArgs...)
}
// EqualValues asserts that two objects are equal or convertable to the same types
// and equal.
//
// a.EqualValues(uint32(123), int32(123), "123 and 123 should be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
EqualValues(a.t, expected, actual, msgAndArgs...)
}
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// if a.Error(err, "An error was expected") {
// assert.Equal(t, err, expectedError)
// }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
Error(a.t, err, msgAndArgs...)
}
// Exactly asserts that two objects are equal is value and type.
//
// a.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
Exactly(a.t, expected, actual, msgAndArgs...)
}
// Fail reports a failure through
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
Fail(a.t, failureMessage, msgAndArgs...)
}
// FailNow fails test
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) {
FailNow(a.t, failureMessage, msgAndArgs...)
}
// False asserts that the specified value is false.
//
// a.False(myBool, "myBool should be false")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
False(a.t, value, msgAndArgs...)
}
// Implements asserts that an object is implemented by the specified interface.
//
// a.Implements((*MyInterface)(nil), new(MyObject), "MyObject")
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
Implements(a.t, interfaceObject, object, msgAndArgs...)
}
// InDelta asserts that the two numerals are within delta of each other.
//
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
InDelta(a.t, expected, actual, delta, msgAndArgs...)
}
// InDeltaSlice is the same as InDelta, except it compares two slices.
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
}
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
}
// IsType asserts that the specified objects are of the same type.
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
IsType(a.t, expectedType, object, msgAndArgs...)
}
// JSONEq asserts that two JSON strings are equivalent.
//
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
JSONEq(a.t, expected, actual, msgAndArgs...)
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
// a.Len(mySlice, 3, "The size of slice is not 3")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
Len(a.t, object, length, msgAndArgs...)
}
// Nil asserts that the specified object is nil.
//
// a.Nil(err, "err should be nothing")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
Nil(a.t, object, msgAndArgs...)
}
// NoError asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if a.NoError(err) {
// assert.Equal(t, actualObj, expectedObj)
// }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
NoError(a.t, err, msgAndArgs...)
}
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element.
//
// a.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'")
// a.NotContains(["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'")
// a.NotContains({"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
NotContains(a.t, s, contains, msgAndArgs...)
}
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
// a slice or a channel with len == 0.
//
// if a.NotEmpty(obj) {
// assert.Equal(t, "two", obj[1])
// }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
NotEmpty(a.t, object, msgAndArgs...)
}
// NotEqual asserts that the specified values are NOT equal.
//
// a.NotEqual(obj1, obj2, "two objects shouldn't be equal")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
NotEqual(a.t, expected, actual, msgAndArgs...)
}
// NotNil asserts that the specified object is not nil.
//
// a.NotNil(err, "err should be something")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
NotNil(a.t, object, msgAndArgs...)
}
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// a.NotPanics(func(){
// RemainCalm()
// }, "Calling RemainCalm() should NOT panic")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
NotPanics(a.t, f, msgAndArgs...)
}
// NotRegexp asserts that a specified regexp does not match a string.
//
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
// a.NotRegexp("^start", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
NotRegexp(a.t, rx, str, msgAndArgs...)
}
// NotZero asserts that i is not the zero value for its type and returns the truth.
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
NotZero(a.t, i, msgAndArgs...)
}
// Panics asserts that the code inside the specified PanicTestFunc panics.
//
// a.Panics(func(){
// GoCrazy()
// }, "Calling GoCrazy() should panic")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
Panics(a.t, f, msgAndArgs...)
}
// Regexp asserts that a specified regexp matches a string.
//
// a.Regexp(regexp.MustCompile("start"), "it's starting")
// a.Regexp("start...$", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
Regexp(a.t, rx, str, msgAndArgs...)
}
// True asserts that the specified value is true.
//
// a.True(myBool, "myBool should be true")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
True(a.t, value, msgAndArgs...)
}
// WithinDuration asserts that the two times are within duration delta of each other.
//
// a.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
}
// Zero asserts that i is the zero value for its type and returns the truth.
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
Zero(a.t, i, msgAndArgs...)
}

9
require/requirements.go Normal file
View File

@ -0,0 +1,9 @@
package require
// TestingT is an interface wrapper around *testing.T
type TestingT interface {
Errorf(format string, args ...interface{})
FailNow()
}
//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl