Procházet zdrojové kódy

make any easier to work with

Tao Wen před 9 roky
rodič
revize
2895fe2215
6 změnil soubory, kde provedl 188 přidání a 64 odebrání
  1. 111 37
      any.go
  2. 20 11
      any_test.go
  3. 3 3
      jsoniter.go
  4. 3 3
      jsoniter_any_test.go
  5. 20 0
      jsoniter_map_test.go
  6. 31 10
      jsoniter_reflect.go

+ 111 - 37
any.go

@@ -3,15 +3,20 @@ package jsoniter
 import (
 	"fmt"
 	"reflect"
+	"strconv"
 )
 
 type Any struct {
-	Val   interface{}
+	val   interface{}
 	Error error
 }
 
-func (any *Any) GetObject(keys ...interface{}) interface{} {
-	ret, err := getPath(any.Val, keys...)
+func any(val interface{}) Any {
+	return Any{val, nil}
+}
+
+func (any *Any) Get(keys ...interface{}) interface{} {
+	ret, err := getPath(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return "";
@@ -19,22 +24,91 @@ func (any *Any) GetObject(keys ...interface{}) interface{} {
 	return ret
 }
 
-func (any *Any) GetString(keys ...interface{}) string {
-	ret, err := getPath(any.Val, keys...)
+func (any *Any) GetValueType(keys ...interface{}) ValueType {
+	ret, err := getPath(any.val, keys...)
 	if err != nil {
 		any.Error = err
-		return "";
+		return Invalid;
 	}
-	typedRet, ok := ret.(string)
-	if !ok {
-		any.Error = fmt.Errorf("%v is not string", ret);
+
+	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...)
+	if err != nil {
+		any.Error = err
 		return "";
 	}
-	return typedRet
+	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) GetUint8(keys ...interface{}) uint8 {
-	ret, err := getPathAsInt64(any.Val, keys...)
+func (any *Any) ToUint8(keys ...interface{}) uint8 {
+	ret, err := getPathAsInt64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -42,8 +116,8 @@ func (any *Any) GetUint8(keys ...interface{}) uint8 {
 	return uint8(ret)
 }
 
-func (any *Any) GetInt8(keys ...interface{}) int8 {
-	ret, err := getPathAsInt64(any.Val, keys...)
+func (any *Any) ToInt8(keys ...interface{}) int8 {
+	ret, err := getPathAsInt64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -51,8 +125,8 @@ func (any *Any) GetInt8(keys ...interface{}) int8 {
 	return int8(ret)
 }
 
-func (any *Any) GetUint16(keys ...interface{}) uint16 {
-	ret, err := getPathAsInt64(any.Val, keys...)
+func (any *Any) ToUint16(keys ...interface{}) uint16 {
+	ret, err := getPathAsInt64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -60,8 +134,8 @@ func (any *Any) GetUint16(keys ...interface{}) uint16 {
 	return uint16(ret)
 }
 
-func (any *Any) GetInt16(keys ...interface{}) int16 {
-	ret, err := getPathAsInt64(any.Val, keys...)
+func (any *Any) ToInt16(keys ...interface{}) int16 {
+	ret, err := getPathAsInt64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -69,8 +143,8 @@ func (any *Any) GetInt16(keys ...interface{}) int16 {
 	return int16(ret)
 }
 
-func (any *Any) GetUint32(keys ...interface{}) uint32 {
-	ret, err := getPathAsInt64(any.Val, keys...)
+func (any *Any) ToUint32(keys ...interface{}) uint32 {
+	ret, err := getPathAsInt64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -78,8 +152,8 @@ func (any *Any) GetUint32(keys ...interface{}) uint32 {
 	return uint32(ret)
 }
 
-func (any *Any) GetInt32(keys ...interface{}) int32 {
-	ret, err := getPathAsInt64(any.Val, keys...)
+func (any *Any) ToInt32(keys ...interface{}) int32 {
+	ret, err := getPathAsInt64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -87,8 +161,8 @@ func (any *Any) GetInt32(keys ...interface{}) int32 {
 	return int32(ret)
 }
 
-func (any *Any) GetUint64(keys ...interface{}) uint64 {
-	ret, err := getPathAsUint64(any.Val, keys...)
+func (any *Any) ToUint64(keys ...interface{}) uint64 {
+	ret, err := getPathAsUint64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -96,8 +170,8 @@ func (any *Any) GetUint64(keys ...interface{}) uint64 {
 	return uint64(ret)
 }
 
-func (any *Any) GetInt64(keys ...interface{}) int64 {
-	ret, err := getPathAsInt64(any.Val, keys...)
+func (any *Any) ToInt64(keys ...interface{}) int64 {
+	ret, err := getPathAsInt64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -105,8 +179,8 @@ func (any *Any) GetInt64(keys ...interface{}) int64 {
 	return int64(ret)
 }
 
-func (any *Any) GetInt(keys ...interface{}) int {
-	ret, err := getPathAsInt64(any.Val, keys...)
+func (any *Any) ToInt(keys ...interface{}) int {
+	ret, err := getPathAsInt64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -114,8 +188,8 @@ func (any *Any) GetInt(keys ...interface{}) int {
 	return int(ret)
 }
 
-func (any *Any) GetUint(keys ...interface{}) uint {
-	ret, err := getPathAsInt64(any.Val, keys...)
+func (any *Any) ToUint(keys ...interface{}) uint {
+	ret, err := getPathAsInt64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -123,8 +197,8 @@ func (any *Any) GetUint(keys ...interface{}) uint {
 	return uint(ret)
 }
 
-func (any *Any) GetFloat32(keys ...interface{}) float32 {
-	ret, err := getPathAsFloat64(any.Val, keys...)
+func (any *Any) ToFloat32(keys ...interface{}) float32 {
+	ret, err := getPathAsFloat64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -132,8 +206,8 @@ func (any *Any) GetFloat32(keys ...interface{}) float32 {
 	return float32(ret)
 }
 
-func (any *Any) GetFloat64(keys ...interface{}) float64 {
-	ret, err := getPathAsFloat64(any.Val, keys...)
+func (any *Any) ToFloat64(keys ...interface{}) float64 {
+	ret, err := getPathAsFloat64(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return 0;
@@ -141,8 +215,8 @@ func (any *Any) GetFloat64(keys ...interface{}) float64 {
 	return ret
 }
 
-func (any *Any) GetBool(keys ...interface{}) bool {
-	ret, err := getPath(any.Val, keys...)
+func (any *Any) ToBool(keys ...interface{}) bool {
+	ret, err := getPath(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return false;
@@ -156,7 +230,7 @@ func (any *Any) GetBool(keys ...interface{}) bool {
 }
 
 func (any *Any) IsNull(keys ...interface{}) bool {
-	ret, err := getPath(any.Val, keys...)
+	ret, err := getPath(any.val, keys...)
 	if err != nil {
 		any.Error = err
 		return false;

+ 20 - 11
any_test.go

@@ -6,34 +6,34 @@ import (
 )
 
 func Test_get_from_map(t *testing.T) {
-	any := Any{Val: map[string]interface{}{
+	any := Any{val: map[string]interface{}{
 		"hello": "world",
 	}}
-	if any.GetString("hello") != "world" {
+	if any.ToString("hello") != "world" {
 		t.FailNow()
 	}
 }
 
 func Test_get_from_array(t *testing.T) {
-	any := Any{Val: []interface{}{
+	any := Any{val: []interface{}{
 		"hello", "world",
 	}}
-	if any.GetString(1) != "world" {
+	if any.ToString(1) != "world" {
 		t.FailNow()
 	}
 }
 
 func Test_get_int(t *testing.T) {
-	any := Any{Val: []interface{}{
+	any := Any{val: []interface{}{
 		1, 2, 3,
 	}}
-	if any.GetInt(1) != 2 {
+	if any.ToInt(1) != 2 {
 		t.FailNow()
 	}
 }
 
 func Test_is_null(t *testing.T) {
-	any := Any{Val: []interface{}{
+	any := Any{val: []interface{}{
 		1, 2, 3,
 	}}
 	if any.IsNull() != false {
@@ -42,22 +42,31 @@ func Test_is_null(t *testing.T) {
 }
 
 func Test_get_bool(t *testing.T) {
-	any := Any{Val: []interface{}{
+	any := Any{val: []interface{}{
 		true, true, false,
 	}}
-	if any.GetBool(1) != true {
+	if any.ToBool(1) != true {
 		t.FailNow()
 	}
 }
 
 func Test_nested_read(t *testing.T) {
-	any := Any{Val: []interface{}{
+	any := Any{val: []interface{}{
 		true, map[string]interface{}{
 			"hello": "world",
 		}, false,
 	}}
-	if any.GetString(1, "hello") != "world" {
+	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()
+	}
+}

+ 3 - 3
jsoniter.go

@@ -16,7 +16,7 @@ const (
 	String
 	Number
 	Null
-	Boolean
+	Bool
 	Array
 	Object
 )
@@ -54,8 +54,8 @@ func init() {
 	valueTypes['7'] = Number;
 	valueTypes['8'] = Number;
 	valueTypes['9'] = Number;
-	valueTypes['t'] = Boolean;
-	valueTypes['f'] = Boolean;
+	valueTypes['t'] = Bool;
+	valueTypes['f'] = Bool;
 	valueTypes['n'] = Null;
 	valueTypes['['] = Array;
 	valueTypes['{'] = Object;

+ 3 - 3
jsoniter_any_test.go

@@ -5,7 +5,7 @@ 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" {
+	if any.ToString(1, "hello") != "world" {
 		t.FailNow()
 	}
 }
@@ -13,7 +13,7 @@ func Test_read_string_as_any(t *testing.T) {
 func Test_read_float64_as_any(t *testing.T) {
 	iter := ParseString(`1.23`)
 	any := iter.ReadAny()
-	if any.GetFloat32() != 1.23 {
+	if any.ToFloat32() != 1.23 {
 		t.FailNow()
 	}
 }
@@ -21,7 +21,7 @@ func Test_read_float64_as_any(t *testing.T) {
 func Test_read_int_as_any(t *testing.T) {
 	iter := ParseString(`123`)
 	any := iter.ReadAny()
-	if any.GetFloat32() != 123 {
+	if any.ToFloat32() != 123 {
 		t.FailNow()
 	}
 }

+ 20 - 0
jsoniter_map_test.go

@@ -15,3 +15,23 @@ func Test_read_map(t *testing.T) {
 		t.Fatal(m)
 	}
 }
+
+func Test_read_map_of_interface(t *testing.T) {
+	iter := ParseString(`{"hello": "world"}`)
+	m := map[string]interface{}{"1": "2"}
+	iter.Read(&m)
+	if !reflect.DeepEqual(map[string]interface{}{"1": "2", "hello": "world"}, m) {
+		fmt.Println(iter.Error)
+		t.Fatal(m)
+	}
+}
+
+func Test_read_map_of_any(t *testing.T) {
+	iter := ParseString(`{"hello": "world"}`)
+	m := map[string]Any{"1": any("2")}
+	iter.Read(&m)
+	if !reflect.DeepEqual(map[string]Any{"1": any("2"), "hello": any("world")}, m) {
+		fmt.Println(iter.Error)
+		t.Fatal(m)
+	}
+}

+ 31 - 10
jsoniter_reflect.go

@@ -113,6 +113,21 @@ 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
 }
@@ -413,12 +428,12 @@ func reuseSlice(slice *sliceHeader, sliceType reflect.Type, expectedCap int) {
 
 var DECODERS unsafe.Pointer
 
-func addDecoderToCache(cacheKey string, decoder Decoder) {
+func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
 	retry := true
 	for retry {
 		ptr := atomic.LoadPointer(&DECODERS)
-		cache := *(*map[string]Decoder)(ptr)
-		copy := map[string]Decoder{}
+		cache := *(*map[reflect.Type]Decoder)(ptr)
+		copy := map[reflect.Type]Decoder{}
 		for k, v := range cache {
 			copy[k] = v
 		}
@@ -427,9 +442,9 @@ func addDecoderToCache(cacheKey string, decoder Decoder) {
 	}
 }
 
-func getDecoderFromCache(cacheKey string) Decoder {
+func getDecoderFromCache(cacheKey reflect.Type) Decoder {
 	ptr := atomic.LoadPointer(&DECODERS)
-	cache := *(*map[string]Decoder)(ptr)
+	cache := *(*map[reflect.Type]Decoder)(ptr)
 	return cache[cacheKey]
 }
 
@@ -502,7 +517,7 @@ func (iter *Iterator) ReadAny() (ret *Any) {
 		return &Any{val, nil}
 	case Null:
 		return &Any{nil, nil}
-	case Boolean:
+	case Bool:
 		return &Any{iter.ReadBool(), nil}
 	case Array:
 		val := []interface{}{}
@@ -511,7 +526,7 @@ func (iter *Iterator) ReadAny() (ret *Any) {
 			if iter.Error != nil {
 				return
 			}
-			val = append(val, element.Val)
+			val = append(val, element.val)
 		}
 		return &Any{val, nil}
 	case Object:
@@ -521,7 +536,7 @@ func (iter *Iterator) ReadAny() (ret *Any) {
 			if iter.Error != nil {
 				return
 			}
-			val[field] = element.Val
+			val[field] = element.val
 		}
 		return &Any{val, nil}
 	default:
@@ -532,7 +547,7 @@ func (iter *Iterator) ReadAny() (ret *Any) {
 
 func (iter *Iterator) Read(obj interface{}) {
 	type_ := reflect.TypeOf(obj)
-	cacheKey := type_.String()
+	cacheKey := type_.Elem()
 	cachedDecoder := getDecoderFromCache(cacheKey)
 	if cachedDecoder == nil {
 		decoder, err := decoderOfType(type_)
@@ -566,7 +581,11 @@ func decoderOfType(type_ reflect.Type) (Decoder, error) {
 }
 
 func decoderOfPtr(type_ reflect.Type) (Decoder, error) {
-	typeDecoder := typeDecoders[type_.String()]
+	typeName := type_.String()
+	if typeName == "jsoniter.Any" {
+		return &anyDecoder{}, nil
+	}
+	typeDecoder := typeDecoders[typeName]
 	if typeDecoder != nil {
 		return typeDecoder, nil
 	}
@@ -599,6 +618,8 @@ func decoderOfPtr(type_ reflect.Type) (Decoder, error) {
 		return &float64Decoder{}, nil
 	case reflect.Bool:
 		return &boolDecoder{}, nil
+	case reflect.Interface:
+		return &interfaceDecoder{}, nil
 	case reflect.Struct:
 		return decoderOfStruct(type_)
 	case reflect.Slice: