Prechádzať zdrojové kódy

support map of interface{}

Tao Wen 8 rokov pred
rodič
commit
f1c4dbde29

+ 31 - 3
feature_any.go

@@ -14,9 +14,14 @@ type Any interface {
 	Keys() []string
 	IterateObject() (func() (string, Any, bool), bool)
 	IterateArray() (func() (Any, bool), bool)
+	GetArray() []Any
+	SetArray(newList []Any) bool
+	GetObject() map[string]Any
+	SetObject(map[string]Any) bool
+	WriteTo(stream *Stream)
 }
 
-type baseAny struct {}
+type baseAny struct{}
 
 func (any *baseAny) Get(path ...interface{}) Any {
 	return &invalidAny{}
@@ -38,6 +43,29 @@ func (any *baseAny) IterateArray() (func() (Any, bool), bool) {
 	return nil, false
 }
 
+func (any *baseAny) GetArray() []Any {
+	return []Any{}
+}
+
+func (any *baseAny) SetArray(newList []Any) bool {
+	return false
+}
+
+func (any *baseAny) GetObject() map[string]Any {
+	return map[string]Any{}
+}
+
+func (any *baseAny) SetObject(map[string]Any) bool {
+	return false
+}
+
+func (any *baseAny) WriteTo(stream *Stream) {
+}
+
+func WrapInt64(val int64) Any {
+	return &intAny{baseAny{}, nil, val}
+}
+
 func (iter *Iterator) ReadAny() Any {
 	return iter.readAny(nil)
 }
@@ -81,7 +109,7 @@ func (iter *Iterator) readNumberAny(reusableIter *Iterator) Any {
 				lazyBuf = append(lazyBuf, iter.buf[iter.head:i]...)
 				iter.head = i
 				if dotFound {
-					return &floatLazyAny{baseAny{},lazyBuf, reusableIter, nil, 0}
+					return &floatLazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
 				} else {
 					return &intLazyAny{baseAny{}, lazyBuf, reusableIter, nil, 0}
 				}
@@ -175,7 +203,7 @@ func (iter *Iterator) readArrayAny(reusableIter *Iterator) Any {
 				if level == 0 {
 					iter.head = i + 1
 					lazyBuf = append(lazyBuf, iter.buf[start:iter.head]...)
-					return &arrayLazyAny{baseAny{},lazyBuf, reusableIter, nil, nil, lazyBuf}
+					return &arrayLazyAny{baseAny{}, lazyBuf, reusableIter, nil, nil, lazyBuf}
 				}
 			}
 		}

+ 43 - 0
feature_any_int.go

@@ -3,6 +3,7 @@ package jsoniter
 import (
 	"io"
 	"unsafe"
+	"strconv"
 )
 
 type intLazyAny struct {
@@ -64,4 +65,46 @@ func (any *intLazyAny) ToFloat64() float64 {
 
 func (any *intLazyAny) ToString() string {
 	return *(*string)(unsafe.Pointer(&any.buf))
+}
+
+type intAny struct {
+	baseAny
+	err   error
+	val int64
+}
+
+func (any *intAny) LastError() error {
+	return any.err
+}
+
+func (any *intAny) ToBool() bool {
+	return any.ToInt64() != 0
+}
+
+func (any *intAny) ToInt() int {
+	return int(any.val)
+}
+
+func (any *intAny) ToInt32() int32 {
+	return int32(any.val)
+}
+
+func (any *intAny) ToInt64() int64 {
+	return any.val
+}
+
+func (any *intAny) ToFloat32() float32 {
+	return float32(any.val)
+}
+
+func (any *intAny) ToFloat64() float64 {
+	return float64(any.val)
+}
+
+func (any *intAny) ToString() string {
+	return strconv.FormatInt(any.val, 10)
+}
+
+func (any *intAny) WriteTo(stream *Stream) {
+	stream.WriteInt64(any.val)
 }

+ 14 - 2
feature_any_object.go

@@ -161,8 +161,10 @@ func (any *objectLazyAny) ToString() string {
 		// nothing has been parsed yet
 		return *(*string)(unsafe.Pointer(&any.buf))
 	} else {
-		// TODO: serialize the cache
-		return ""
+		any.fillCache()
+		str, err := MarshalToString(any.cache)
+		any.err = err
+		return str
 	}
 }
 
@@ -261,3 +263,13 @@ func (any *objectLazyAny) IterateObject() (func() (string, Any, bool), bool) {
 	}, true
 }
 
+func (any *objectLazyAny) GetObject() map[string]Any {
+	any.fillCache()
+	return any.cache
+}
+
+func (any *objectLazyAny) SetObject(val map[string]Any) bool {
+	any.fillCache()
+	any.cache = val
+	return true
+}

+ 59 - 1
feature_reflect.go

@@ -24,6 +24,7 @@ type Encoder interface {
 }
 
 type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
+type EncoderFunc func(ptr unsafe.Pointer, stream *Stream)
 type ExtensionFunc func(typ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc)
 
 type funcDecoder struct {
@@ -34,19 +35,35 @@ func (decoder *funcDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
 	decoder.fun(ptr, iter)
 }
 
+type funcEncoder struct {
+	fun EncoderFunc
+}
+
+func (encoder *funcEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
+	encoder.fun(ptr, stream)
+}
+
 var DECODERS unsafe.Pointer
 var ENCODERS unsafe.Pointer
 
 var typeDecoders map[string]Decoder
 var fieldDecoders map[string]Decoder
+var typeEncoders map[string]Encoder
+var fieldEncoders map[string]Encoder
 var extensions []ExtensionFunc
 
 func init() {
 	typeDecoders = map[string]Decoder{}
 	fieldDecoders = map[string]Decoder{}
+	typeEncoders = map[string]Encoder{}
+	fieldEncoders = map[string]Encoder{}
 	extensions = []ExtensionFunc{}
 	atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
 	atomic.StorePointer(&ENCODERS, unsafe.Pointer(&map[string]Encoder{}))
+	RegisterTypeEncoder("*jsoniter.intAny", func(ptr unsafe.Pointer, stream *Stream) {
+		val := *(**intAny)(ptr)
+		val.WriteTo(stream)
+	})
 }
 
 func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
@@ -99,6 +116,14 @@ func RegisterFieldDecoder(typ string, field string, fun DecoderFunc) {
 	fieldDecoders[fmt.Sprintf("%s/%s", typ, field)] = &funcDecoder{fun}
 }
 
+func RegisterTypeEncoder(typ string, fun EncoderFunc) {
+	typeEncoders[typ] = &funcEncoder{fun}
+}
+
+func RegisterFieldEncoder(typ string, field string, fun EncoderFunc) {
+	fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = &funcEncoder{fun}
+}
+
 // RegisterExtension can register a custom extension
 func RegisterExtension(extension ExtensionFunc) {
 	extensions = append(extensions, extension)
@@ -192,6 +217,31 @@ func (encoder *mapEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
 	stream.WriteObjectEnd()
 }
 
+type mapInterfaceEncoder struct {
+	mapType      reflect.Type
+	elemType     reflect.Type
+	elemEncoder  Encoder
+	mapInterface emptyInterface
+}
+
+func (encoder *mapInterfaceEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
+	mapInterface := encoder.mapInterface
+	mapInterface.word = ptr
+	realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
+	realVal := reflect.ValueOf(*realInterface)
+
+	stream.WriteObjectStart()
+	for i, key := range realVal.MapKeys() {
+		if i != 0 {
+			stream.WriteMore()
+		}
+		stream.WriteObjectField(key.String())
+		val := realVal.MapIndex(key).Interface()
+		encoder.elemEncoder.encode(unsafe.Pointer(&val), stream)
+	}
+	stream.WriteObjectEnd()
+}
+
 // emptyInterface is the header for an interface{} value.
 type emptyInterface struct {
 	typ  *struct{}
@@ -311,6 +361,10 @@ func decoderOfType(typ reflect.Type) (Decoder, error) {
 
 func encoderOfType(typ reflect.Type) (Encoder, error) {
 	typeName := typ.String()
+	typeEncoder := typeEncoders[typeName]
+	if typeEncoder != nil {
+		return typeEncoder, nil
+	}
 	switch typ.Kind() {
 	case reflect.String:
 		return &stringCodec{}, nil
@@ -388,5 +442,9 @@ func encoderOfMap(typ reflect.Type) (Encoder, error) {
 		return nil, err
 	}
 	mapInterface := reflect.New(typ).Elem().Interface()
-	return &mapEncoder{typ, typ.Elem(), encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
+	if typ.Elem().Kind() == reflect.Interface {
+		return &mapInterfaceEncoder{typ, typ.Elem(), encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
+	} else {
+		return &mapEncoder{typ, typ.Elem(), encoder, *((*emptyInterface)(unsafe.Pointer(&mapInterface)))}, nil
+	}
 }

+ 3 - 1
feature_reflect_native.go

@@ -1,6 +1,8 @@
 package jsoniter
 
-import "unsafe"
+import (
+	"unsafe"
+)
 
 type stringCodec struct {
 }

+ 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_wrap_int(t *testing.T) {
+	should := require.New(t)
+	str, err := MarshalToString(WrapInt64(100))
+	should.Nil(err)
+	should.Equal("100", str)
+}
+
 func Test_write_uint8(t *testing.T) {
 	vals := []uint8{0, 1, 11, 111, 255}
 	for _, val := range vals {

+ 28 - 0
jsoniter_interface_test.go

@@ -11,4 +11,32 @@ func Test_write_array_of_interface(t *testing.T) {
 	str, err := MarshalToString(array)
 	should.Nil(err)
 	should.Equal(`["hello"]`, str)
+}
+
+func Test_write_map_of_interface(t *testing.T) {
+	should := require.New(t)
+	val := map[string]interface{}{"hello":"world"}
+	str, err := MarshalToString(val)
+	should.Nil(err)
+	should.Equal(`{"hello":"world"}`, str)
+}
+
+type MyInterface interface {
+}
+
+func Test_write_map_of_custom_interface(t *testing.T) {
+	should := require.New(t)
+	val := map[string]MyInterface{"hello":"world"}
+	str, err := MarshalToString(val)
+	should.Nil(err)
+	should.Equal(`{"hello":"world"}`, str)
+}
+
+func Test_write_interface(t *testing.T) {
+	should := require.New(t)
+	var val interface{}
+	val = "hello"
+	str, err := MarshalToString(val)
+	should.Nil(err)
+	should.Equal(`"hello"`, str)
 }

+ 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_set(t *testing.T) {
+	should := require.New(t)
+	any, err := UnmarshalAnyFromString(`{"a":{"b":{"c":"d"}}}`)
+	should.Nil(err)
+	any.GetObject()["a"] = WrapInt64(1)
+	should.Equal(`{"a":1}`, any.ToString())
+}
+
 func Test_write_object(t *testing.T) {
 	should := require.New(t)
 	buf := &bytes.Buffer{}