Tao Wen 8 лет назад
Родитель
Сommit
85edb698c8

+ 4 - 1
feature_any.go

@@ -1,7 +1,10 @@
 package jsoniter
 
+import "fmt"
+
 type Any interface {
 	LastError() error
+	ValueType() ValueType
 	ToBool() bool
 	ToInt() int
 	ToInt32() int32
@@ -26,7 +29,7 @@ type Any interface {
 type baseAny struct{}
 
 func (any *baseAny) Get(path ...interface{}) Any {
-	return &invalidAny{}
+	return &invalidAny{baseAny{}, fmt.Errorf("Get %v from simple value", path)}
 }
 
 func (any *baseAny) Size() int {

+ 17 - 4
feature_any_array.go

@@ -2,6 +2,7 @@ package jsoniter
 
 import (
 	"unsafe"
+	"fmt"
 )
 
 type arrayLazyAny struct {
@@ -13,6 +14,10 @@ type arrayLazyAny struct {
 	remaining []byte
 }
 
+func (any *arrayLazyAny) ValueType() ValueType {
+	return Array
+}
+
 func (any *arrayLazyAny) Parse() *Iterator {
 	iter := any.iter
 	if iter == nil {
@@ -176,12 +181,20 @@ func (any *arrayLazyAny) Get(path ...interface{}) Any {
 	if len(path) == 0 {
 		return any
 	}
+	var element Any
+	idx, ok := path[0].(int)
+	if ok {
+		element = any.fillCacheUntil(idx)
+		if element == nil {
+			element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", idx, any.cache)}
+		}
+	} else {
+		element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", idx, any.cache)}
+	}
 	if len(path) == 1 {
-		idx := path[0].(int)
-		return any.fillCacheUntil(idx)
+		return element
 	} else {
-		idx := path[0].(int)
-		return any.fillCacheUntil(idx).Get(path[1:]...)
+		return element.Get(path[1:]...)
 	}
 }
 

+ 8 - 0
feature_any_bool.go

@@ -48,6 +48,10 @@ func (any *trueAny) GetInterface() interface{} {
 	return true
 }
 
+func (any *trueAny) ValueType() ValueType {
+	return Bool
+}
+
 type falseAny struct {
 	baseAny
 }
@@ -95,3 +99,7 @@ func (any *falseAny) Parse() *Iterator {
 func (any *falseAny) GetInterface() interface{} {
 	return false
 }
+
+func (any *falseAny) ValueType() ValueType {
+	return Bool
+}

+ 4 - 0
feature_any_float.go

@@ -22,6 +22,10 @@ func (any *floatLazyAny) Parse() *Iterator {
 	return iter
 }
 
+func (any *floatLazyAny) ValueType() ValueType {
+	return Number
+}
+
 func (any *floatLazyAny) fillCache() {
 	if any.err != nil {
 		return

+ 8 - 0
feature_any_int.go

@@ -14,6 +14,10 @@ type intLazyAny struct {
 	cache int64
 }
 
+func (any *intLazyAny) ValueType() ValueType {
+	return Number
+}
+
 func (any *intLazyAny) Parse() *Iterator {
 	iter := any.iter
 	if iter == nil {
@@ -91,6 +95,10 @@ func (any *intAny) LastError() error {
 	return any.err
 }
 
+func (any *intAny) ValueType() ValueType {
+	return Number
+}
+
 func (any *intAny) ToBool() bool {
 	return any.ToInt64() != 0
 }

+ 13 - 2
feature_any_invalid.go

@@ -1,11 +1,18 @@
 package jsoniter
 
+import "fmt"
+
 type invalidAny struct {
 	baseAny
+	err error
 }
 
 func (any *invalidAny) LastError() error {
-	return nil
+	return any.err
+}
+
+func (any *invalidAny) ValueType() ValueType {
+	return Invalid
 }
 
 func (any *invalidAny) ToBool() bool {
@@ -40,7 +47,11 @@ func (any *invalidAny) WriteTo(stream *Stream) {
 }
 
 func (any *invalidAny) Get(path ...interface{}) Any {
-	return 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 {

+ 4 - 0
feature_any_nil.go

@@ -8,6 +8,10 @@ func (any *nilAny) LastError() error {
 	return nil
 }
 
+func (any *nilAny) ValueType() ValueType {
+	return Nil
+}
+
 func (any *nilAny) ToBool() bool {
 	return false
 }

+ 17 - 4
feature_any_object.go

@@ -2,6 +2,7 @@ package jsoniter
 
 import (
 	"unsafe"
+	"fmt"
 )
 
 type objectLazyAny struct {
@@ -13,6 +14,10 @@ type objectLazyAny struct {
 	remaining []byte
 }
 
+func (any *objectLazyAny) ValueType() ValueType {
+	return Object
+}
+
 func (any *objectLazyAny) Parse() *Iterator {
 	iter := any.iter
 	if iter == nil {
@@ -178,12 +183,20 @@ func (any *objectLazyAny) Get(path ...interface{}) Any {
 	if len(path) == 0 {
 		return any
 	}
+	var element Any
+	key, ok := path[0].(string)
+	if ok {
+		element = any.fillCacheUntil(key)
+		if element == nil {
+			element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", key, any.cache)}
+		}
+	} else {
+		element = &invalidAny{baseAny{}, fmt.Errorf("%v not found in %v", key, any.cache)}
+	}
 	if len(path) == 1 {
-		key := path[0].(string)
-		return any.fillCacheUntil(key)
+		return element
 	} else {
-		key := path[0].(string)
-		return any.fillCacheUntil(key).Get(path[1:]...)
+		return element.Get(path[1:]...)
 	}
 }
 

+ 4 - 0
feature_any_string.go

@@ -12,6 +12,10 @@ type stringLazyAny struct{
 	cache string
 }
 
+func (any *stringLazyAny) ValueType() ValueType {
+	return String
+}
+
 func (any *stringLazyAny) Parse() *Iterator {
 	iter := any.iter
 	if iter == nil {

+ 10 - 0
jsoniter_array_test.go

@@ -90,6 +90,16 @@ func Test_array_lazy_any_get(t *testing.T) {
 	should.Equal("[1,[2,3],4]", any.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]")

+ 7 - 0
jsoniter_int_test.go

@@ -110,6 +110,13 @@ func Test_read_int64_as_any(t *testing.T) {
 	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))

+ 8 - 0
jsoniter_object_test.go

@@ -147,6 +147,14 @@ func Test_object_lazy_any_get(t *testing.T) {
 	should.Equal("d", any.Get("a", "b", "c").ToString())
 }
 
+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"}}}`)