1
0
mirror of https://github.com/json-iterator/go.git synced 2025-03-26 21:12:40 +02:00

make any easier to work with

This commit is contained in:
Tao Wen 2016-12-11 10:04:26 +08:00
parent e427475e9c
commit 2895fe2215
6 changed files with 188 additions and 64 deletions

148
any.go
View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@ import "testing"
func Test_read_string_as_any(t *testing.T) { func Test_read_string_as_any(t *testing.T) {
iter := ParseString(`[1, {"hello": "world"}, 2]`) iter := ParseString(`[1, {"hello": "world"}, 2]`)
any := iter.ReadAny() any := iter.ReadAny()
if any.GetString(1, "hello") != "world" { if any.ToString(1, "hello") != "world" {
t.FailNow() t.FailNow()
} }
} }
@ -13,7 +13,7 @@ func Test_read_string_as_any(t *testing.T) {
func Test_read_float64_as_any(t *testing.T) { func Test_read_float64_as_any(t *testing.T) {
iter := ParseString(`1.23`) iter := ParseString(`1.23`)
any := iter.ReadAny() any := iter.ReadAny()
if any.GetFloat32() != 1.23 { if any.ToFloat32() != 1.23 {
t.FailNow() t.FailNow()
} }
} }
@ -21,7 +21,7 @@ func Test_read_float64_as_any(t *testing.T) {
func Test_read_int_as_any(t *testing.T) { func Test_read_int_as_any(t *testing.T) {
iter := ParseString(`123`) iter := ParseString(`123`)
any := iter.ReadAny() any := iter.ReadAny()
if any.GetFloat32() != 123 { if any.ToFloat32() != 123 {
t.FailNow() t.FailNow()
} }
} }

View File

@ -15,3 +15,23 @@ func Test_read_map(t *testing.T) {
t.Fatal(m) 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)
}
}

View File

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