Pārlūkot izejas kodu

implement any api

Tao Wen 9 gadi atpakaļ
vecāks
revīzija
aa42ac95c0
6 mainītis faili ar 508 papildinājumiem un 7 dzēšanām
  1. 323 0
      any.go
  2. 63 0
      any_test.go
  3. 32 4
      jsoniter.go
  4. 27 0
      jsoniter_any_test.go
  5. 60 0
      jsoniter_reflect.go
  6. 3 3
      jsoniter_string_test.go

+ 323 - 0
any.go

@@ -0,0 +1,323 @@
+package jsoniter
+
+import (
+	"fmt"
+	"reflect"
+)
+
+type Any struct {
+	Val   interface{}
+	Error error
+}
+
+func (any *Any) GetObject(keys ...interface{}) interface{} {
+	ret, err := getPath(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return "";
+	}
+	return ret
+}
+
+func (any *Any) GetString(keys ...interface{}) string {
+	ret, err := getPath(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return "";
+	}
+	typedRet, ok := ret.(string)
+	if !ok {
+		any.Error = fmt.Errorf("%v is not string", ret);
+		return "";
+	}
+	return typedRet
+}
+
+func (any *Any) GetUint8(keys ...interface{}) uint8 {
+	ret, err := getPathAsInt64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return uint8(ret)
+}
+
+func (any *Any) GetInt8(keys ...interface{}) int8 {
+	ret, err := getPathAsInt64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return int8(ret)
+}
+
+func (any *Any) GetUint16(keys ...interface{}) uint16 {
+	ret, err := getPathAsInt64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return uint16(ret)
+}
+
+func (any *Any) GetInt16(keys ...interface{}) int16 {
+	ret, err := getPathAsInt64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return int16(ret)
+}
+
+func (any *Any) GetUint32(keys ...interface{}) uint32 {
+	ret, err := getPathAsInt64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return uint32(ret)
+}
+
+func (any *Any) GetInt32(keys ...interface{}) int32 {
+	ret, err := getPathAsInt64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return int32(ret)
+}
+
+func (any *Any) GetUint64(keys ...interface{}) uint64 {
+	ret, err := getPathAsUint64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return uint64(ret)
+}
+
+func (any *Any) GetInt64(keys ...interface{}) int64 {
+	ret, err := getPathAsInt64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return int64(ret)
+}
+
+func (any *Any) GetInt(keys ...interface{}) int {
+	ret, err := getPathAsInt64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return int(ret)
+}
+
+func (any *Any) GetUint(keys ...interface{}) uint {
+	ret, err := getPathAsInt64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return uint(ret)
+}
+
+func (any *Any) GetFloat32(keys ...interface{}) float32 {
+	ret, err := getPathAsFloat64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return float32(ret)
+}
+
+func (any *Any) GetFloat64(keys ...interface{}) float64 {
+	ret, err := getPathAsFloat64(any.Val, keys...)
+	if err != nil {
+		any.Error = err
+		return 0;
+	}
+	return ret
+}
+
+func (any *Any) GetBool(keys ...interface{}) bool {
+	ret, err := getPath(any.Val, keys...)
+	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...)
+	if err != nil {
+		any.Error = err
+		return false;
+	}
+	return reflect.ValueOf(ret).IsNil()
+}
+
+func getPathAsInt64(val interface{}, keys ...interface{}) (int64, error) {
+	ret, err := getPath(val, keys...)
+	if err != nil {
+		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;
+	default:
+		return 0, fmt.Errorf("%v is not number", ret)
+	}
+}
+
+func getPathAsUint64(val interface{}, keys ...interface{}) (uint64, error) {
+	ret, err := getPath(val, keys...)
+	if err != nil {
+		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;
+	default:
+		return 0, fmt.Errorf("%v is not number", ret)
+	}
+}
+
+func getPathAsFloat64(val interface{}, keys ...interface{}) (float64, error) {
+	ret, err := getPath(val, keys...)
+	if err != nil {
+		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;
+	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
+}

+ 63 - 0
any_test.go

@@ -0,0 +1,63 @@
+package jsoniter
+
+import (
+	"testing"
+	"fmt"
+)
+
+func Test_get_from_map(t *testing.T) {
+	any := Any{Val: map[string]interface{}{
+		"hello": "world",
+	}}
+	if any.GetString("hello") != "world" {
+		t.FailNow()
+	}
+}
+
+func Test_get_from_array(t *testing.T) {
+	any := Any{Val: []interface{}{
+		"hello", "world",
+	}}
+	if any.GetString(1) != "world" {
+		t.FailNow()
+	}
+}
+
+func Test_get_int(t *testing.T) {
+	any := Any{Val: []interface{}{
+		1, 2, 3,
+	}}
+	if any.GetInt(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.GetBool(1) != true {
+		t.FailNow()
+	}
+}
+
+func Test_nested_read(t *testing.T) {
+	any := Any{Val: []interface{}{
+		true, map[string]interface{}{
+			"hello": "world",
+		}, false,
+	}}
+	if any.GetString(1, "hello") != "world" {
+		fmt.Println(any.Error)
+		t.FailNow()
+	}
+}

+ 32 - 4
jsoniter.go

@@ -365,11 +365,11 @@ func (iter *Iterator) ReadInt64() (ret int64) {
 }
 
 func (iter *Iterator) ReadString() (ret string) {
-	return string(iter.ReadStringAsBytes())
+	return string(iter.readStringAsBytes())
 }
 
 
-func (iter *Iterator) ReadStringAsBytes() (ret []byte) {
+func (iter *Iterator) readStringAsBytes() (ret []byte) {
 	c := iter.readByte()
 	if c == 'n' {
 		iter.skipUntilBreak()
@@ -609,7 +609,7 @@ func (iter *Iterator) ReadObject() (ret string) {
 }
 
 func (iter *Iterator) readObjectField() (ret string) {
-	str := iter.ReadStringAsBytes()
+	str := iter.readStringAsBytes()
 	if iter.skipWhitespacesWithoutLoadMore() {
 		if ret == "" {
 			ret = string(str);
@@ -670,6 +670,34 @@ 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]
@@ -722,7 +750,7 @@ func (iter *Iterator) ReadBool() (ret bool) {
 }
 
 func (iter *Iterator) ReadBase64() (ret []byte) {
-	src := iter.ReadStringAsBytes()
+	src := iter.readStringAsBytes()
 	if iter.Error != nil {
 		return
 	}

+ 27 - 0
jsoniter_any_test.go

@@ -0,0 +1,27 @@
+package jsoniter
+
+import "testing"
+
+func Test_read_string_as_any(t *testing.T) {
+	iter := ParseString(`[1, {"hello": "world"}, 2]`)
+	any := iter.ReadAny()
+	if any.GetString(1, "hello") != "world" {
+		t.FailNow()
+	}
+}
+
+func Test_read_float64_as_any(t *testing.T) {
+	iter := ParseString(`1.23`)
+	any := iter.ReadAny()
+	if any.GetFloat32() != 1.23 {
+		t.FailNow()
+	}
+}
+
+func Test_read_int_as_any(t *testing.T) {
+	iter := ParseString(`123`)
+	any := iter.ReadAny()
+	if any.GetFloat32() != 123 {
+		t.FailNow()
+	}
+}

+ 60 - 0
jsoniter_reflect.go

@@ -8,6 +8,7 @@ import (
 	"sync/atomic"
 	"strings"
 	"io"
+	"strconv"
 )
 
 type Decoder interface {
@@ -449,6 +450,65 @@ type emptyInterface struct {
 	word unsafe.Pointer
 }
 
+func (iter *Iterator) ReadAny() (ret *Any) {
+	valueType := iter.WhatIsNext()
+	switch valueType {
+	case String:
+		return &Any{iter.ReadString(), nil}
+	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}
+	case Null:
+		return &Any{nil, nil}
+	case Boolean:
+		return &Any{iter.ReadBool(), nil}
+	case Array:
+		val := []interface{}{}
+		for (iter.ReadArray()) {
+			element := iter.ReadAny()
+			if iter.Error != nil {
+				return
+			}
+			val = append(val, element.Val)
+		}
+		return &Any{val, nil}
+	case Object:
+		val := map[string]interface{}{}
+		for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
+			element := iter.ReadAny()
+			if iter.Error != nil {
+				return
+			}
+			val[field] = element.Val
+		}
+		return &Any{val, nil}
+	default:
+		iter.ReportError("ReadAny", fmt.Sprintf("unexpected value type: %v", valueType))
+		return nil
+	}
+}
+
 func (iter *Iterator) Read(obj interface{}) {
 	type_ := reflect.TypeOf(obj)
 	cacheKey := type_.String()

+ 3 - 3
jsoniter_string_test.go

@@ -74,11 +74,11 @@ func Test_string_escape_unicode_with_surrogate(t *testing.T) {
 
 func Test_string_as_bytes(t *testing.T) {
 	iter := Parse(bytes.NewBufferString(`"hello""world"`), 4096)
-	val := string(iter.ReadStringAsBytes())
+	val := string(iter.readStringAsBytes())
 	if val != "hello" {
 		t.Fatal(val)
 	}
-	val = string(iter.ReadStringAsBytes())
+	val = string(iter.readStringAsBytes())
 	if val != "world" {
 		t.Fatal(val)
 	}
@@ -105,7 +105,7 @@ func Benchmark_jsoniter_string_as_bytes(b *testing.B) {
 	b.ResetTimer()
 	for n := 0; n < b.N; n++ {
 		iter.ResetBytes(iter.buf)
-		iter.ReadStringAsBytes()
+		iter.readStringAsBytes()
 	}
 }