From 3e47c79b7e72d460c78b01181ffd93d0a29ac87c Mon Sep 17 00:00:00 2001 From: Tao Wen Date: Sun, 11 Dec 2016 15:53:35 +0800 Subject: [PATCH] fix any --- any.go | 70 ++++++++++++++++++++++--------- jsoniter.go | 28 ------------- jsoniter_any_test.go | 14 ++++++- jsoniter_demo_test.go | 56 +++++++++++++++++++++++++ jsoniter_map_test.go | 4 +- jsoniter_reflect.go | 98 ++++++++++++++++++++++++++++++------------- 6 files changed, 190 insertions(+), 80 deletions(-) create mode 100644 jsoniter_demo_test.go diff --git a/any.go b/any.go index f6557a2..fcda7f6 100644 --- a/any.go +++ b/any.go @@ -9,14 +9,16 @@ import ( type Any struct { val interface{} Error error + LastAccessed interface{} } -func any(val interface{}) Any { - return Any{val, nil} +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 ""; @@ -26,6 +28,7 @@ func (any *Any) Get(keys ...interface{}) interface{} { func (any *Any) GetValueType(keys ...interface{}) ValueType { ret, err := getPath(any.val, keys...) + any.LastAccessed = ret if err != nil { any.Error = err return Invalid; @@ -71,6 +74,7 @@ func (any *Any) GetValueType(keys ...interface{}) ValueType { func (any *Any) ToString(keys ...interface{}) string { ret, err := getPath(any.val, keys...) + any.LastAccessed = ret if err != nil { any.Error = err return ""; @@ -108,7 +112,7 @@ func (any *Any) ToString(keys ...interface{}) string { } func (any *Any) ToUint8(keys ...interface{}) uint8 { - ret, err := getPathAsInt64(any.val, keys...) + ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0; @@ -117,7 +121,7 @@ func (any *Any) ToUint8(keys ...interface{}) uint8 { } func (any *Any) ToInt8(keys ...interface{}) int8 { - ret, err := getPathAsInt64(any.val, keys...) + ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0; @@ -126,7 +130,7 @@ func (any *Any) ToInt8(keys ...interface{}) int8 { } func (any *Any) ToUint16(keys ...interface{}) uint16 { - ret, err := getPathAsInt64(any.val, keys...) + ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0; @@ -135,7 +139,7 @@ func (any *Any) ToUint16(keys ...interface{}) uint16 { } func (any *Any) ToInt16(keys ...interface{}) int16 { - ret, err := getPathAsInt64(any.val, keys...) + ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0; @@ -144,7 +148,7 @@ func (any *Any) ToInt16(keys ...interface{}) int16 { } func (any *Any) ToUint32(keys ...interface{}) uint32 { - ret, err := getPathAsInt64(any.val, keys...) + ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0; @@ -153,7 +157,7 @@ func (any *Any) ToUint32(keys ...interface{}) uint32 { } func (any *Any) ToInt32(keys ...interface{}) int32 { - ret, err := getPathAsInt64(any.val, keys...) + ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0; @@ -162,7 +166,7 @@ func (any *Any) ToInt32(keys ...interface{}) int32 { } func (any *Any) ToUint64(keys ...interface{}) uint64 { - ret, err := getPathAsUint64(any.val, keys...) + ret, err := getPathAsUint64(any, keys...) if err != nil { any.Error = err return 0; @@ -171,7 +175,7 @@ func (any *Any) ToUint64(keys ...interface{}) uint64 { } func (any *Any) ToInt64(keys ...interface{}) int64 { - ret, err := getPathAsInt64(any.val, keys...) + ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0; @@ -180,7 +184,7 @@ func (any *Any) ToInt64(keys ...interface{}) int64 { } func (any *Any) ToInt(keys ...interface{}) int { - ret, err := getPathAsInt64(any.val, keys...) + ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0; @@ -189,7 +193,7 @@ func (any *Any) ToInt(keys ...interface{}) int { } func (any *Any) ToUint(keys ...interface{}) uint { - ret, err := getPathAsInt64(any.val, keys...) + ret, err := getPathAsInt64(any, keys...) if err != nil { any.Error = err return 0; @@ -198,7 +202,7 @@ func (any *Any) ToUint(keys ...interface{}) uint { } func (any *Any) ToFloat32(keys ...interface{}) float32 { - ret, err := getPathAsFloat64(any.val, keys...) + ret, err := getPathAsFloat64(any, keys...) if err != nil { any.Error = err return 0; @@ -207,7 +211,7 @@ func (any *Any) ToFloat32(keys ...interface{}) float32 { } func (any *Any) ToFloat64(keys ...interface{}) float64 { - ret, err := getPathAsFloat64(any.val, keys...) + ret, err := getPathAsFloat64(any, keys...) if err != nil { any.Error = err return 0; @@ -217,6 +221,7 @@ func (any *Any) ToFloat64(keys ...interface{}) float64 { func (any *Any) ToBool(keys ...interface{}) bool { ret, err := getPath(any.val, keys...) + any.LastAccessed = ret if err != nil { any.Error = err return false; @@ -231,6 +236,7 @@ func (any *Any) ToBool(keys ...interface{}) bool { func (any *Any) IsNull(keys ...interface{}) bool { ret, err := getPath(any.val, keys...) + any.LastAccessed = ret if err != nil { any.Error = err return false; @@ -238,9 +244,11 @@ func (any *Any) IsNull(keys ...interface{}) bool { return reflect.ValueOf(ret).IsNil() } -func getPathAsInt64(val interface{}, keys ...interface{}) (int64, error) { - ret, err := getPath(val, keys...) +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) { @@ -268,14 +276,22 @@ func getPathAsInt64(val interface{}, keys ...interface{}) (int64, error) { 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(val interface{}, keys ...interface{}) (uint64, error) { - ret, err := getPath(val, keys...) +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) { @@ -303,14 +319,22 @@ func getPathAsUint64(val interface{}, keys ...interface{}) (uint64, error) { 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(val interface{}, keys ...interface{}) (float64, error) { - ret, err := getPath(val, keys...) +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) { @@ -338,6 +362,12 @@ func getPathAsFloat64(val interface{}, keys ...interface{}) (float64, error) { 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) } diff --git a/jsoniter.go b/jsoniter.go index c72860c..6b37856 100644 --- a/jsoniter.go +++ b/jsoniter.go @@ -670,34 +670,6 @@ func (iter *Iterator) ReadFloat32() (ret float32) { return float32(val) } -func (iter *Iterator) ReadNumber() (ret string) { - 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 - } - return string(str) -} - func (iter *Iterator) ReadFloat64() (ret float64) { strBuf := [8]byte{} str := strBuf[0:0] diff --git a/jsoniter_any_test.go b/jsoniter_any_test.go index 4651980..e2fbc51 100644 --- a/jsoniter_any_test.go +++ b/jsoniter_any_test.go @@ -1,6 +1,9 @@ package jsoniter -import "testing" +import ( + "testing" + "fmt" +) func Test_read_string_as_any(t *testing.T) { iter := ParseString(`[1, {"hello": "world"}, 2]`) @@ -25,3 +28,12 @@ func Test_read_int_as_any(t *testing.T) { 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() + } +} diff --git a/jsoniter_demo_test.go b/jsoniter_demo_test.go new file mode 100644 index 0000000..e631240 --- /dev/null +++ b/jsoniter_demo_test.go @@ -0,0 +1,56 @@ +package jsoniter + +import ( + "testing" + "fmt" +) + +func Test_bind_api_demo(t *testing.T) { + iter := ParseString(`[0,1,2,3]`) + val := []int{} + iter.Read(&val) + fmt.Println(val[3]) +} + +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) { + iter := ParseString(`[0,1,2,3]`) + total := 0 + for iter.ReadArray() { + total += iter.ReadInt() + } + 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) +} diff --git a/jsoniter_map_test.go b/jsoniter_map_test.go index 90ac6fa..d69f073 100644 --- a/jsoniter_map_test.go +++ b/jsoniter_map_test.go @@ -28,9 +28,9 @@ func Test_read_map_of_interface(t *testing.T) { func Test_read_map_of_any(t *testing.T) { iter := ParseString(`{"hello": "world"}`) - m := map[string]Any{"1": any("2")} + m := map[string]Any{"1": *MakeAny("2")} iter.Read(&m) - if !reflect.DeepEqual(map[string]Any{"1": any("2"), "hello": any("world")}, m) { + if !reflect.DeepEqual(map[string]Any{"1": *MakeAny("2"), "hello": *MakeAny("world")}, m) { fmt.Println(iter.Error) t.Fatal(m) } diff --git a/jsoniter_reflect.go b/jsoniter_reflect.go index e0f3ead..946dd8b 100644 --- a/jsoniter_reflect.go +++ b/jsoniter_reflect.go @@ -490,35 +490,13 @@ func (iter *Iterator) ReadAny() (ret *Any) { valueType := iter.WhatIsNext() switch valueType { case String: - return &Any{iter.ReadString(), nil} + return MakeAny(iter.ReadString()) case Number: - number := iter.ReadNumber() - if strings.Contains(number, ".") { - val, err := strconv.ParseFloat(number, 64) - if err != nil { - iter.Error = err - return - } - return &Any{val, nil} - } - if strings.HasPrefix(number, "-") { - val, err := strconv.ParseUint(number, 10, 64) - if err != nil { - iter.Error = err - return - } - return &Any{val, nil} - } - val, err := strconv.ParseInt(number, 10, 64) - if err != nil { - iter.Error = err - return - } - return &Any{val, nil} + return iter.readNumber() case Null: - return &Any{nil, nil} + return MakeAny(nil) case Bool: - return &Any{iter.ReadBool(), nil} + return MakeAny(iter.ReadBool()) case Array: val := []interface{}{} for (iter.ReadArray()) { @@ -528,7 +506,7 @@ func (iter *Iterator) ReadAny() (ret *Any) { } val = append(val, element.val) } - return &Any{val, nil} + return MakeAny(val) case Object: val := map[string]interface{}{} for field := iter.ReadObject(); field != ""; field = iter.ReadObject() { @@ -538,13 +516,75 @@ func (iter *Iterator) ReadAny() (ret *Any) { } val[field] = element.val } - return &Any{val, nil} + return MakeAny(val) default: iter.ReportError("ReadAny", fmt.Sprintf("unexpected value type: %v", valueType)) - return nil + 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()