1
0
mirror of https://github.com/json-iterator/go.git synced 2025-03-20 20:54:55 +02:00

support non empty interface

This commit is contained in:
Tao Wen 2017-05-27 00:36:21 +08:00
parent a7a7c7879a
commit 707ed3b091
4 changed files with 107 additions and 12 deletions

View File

@ -5,7 +5,6 @@ import (
"reflect"
"sync/atomic"
"unsafe"
"errors"
"encoding/json"
)
@ -235,7 +234,21 @@ func (decoder *placeholderDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *struct{}
typ unsafe.Pointer
word unsafe.Pointer
}
// emptyInterface is the header for an interface with method (not interface{})
type nonEmptyInterface struct {
// see ../runtime/iface.go:/Itab
itab *struct {
ityp unsafe.Pointer // static interface type
typ unsafe.Pointer // dynamic concrete type
link unsafe.Pointer
bad int32
unused int32
fun [100000]unsafe.Pointer // method table
}
word unsafe.Pointer
}
@ -358,9 +371,9 @@ func createDecoderOfType(typ reflect.Type) (Decoder, error) {
return &boolCodec{}, nil
case reflect.Interface:
if typ.NumMethod() == 0 {
return &interfaceCodec{}, nil
return &emptyInterfaceCodec{}, nil
} else {
return nil, errors.New("unsupportd type: " + typ.String())
return &nonEmptyInterfaceCodec{}, nil
}
case reflect.Struct:
return prefix(fmt.Sprintf("[%s]", typ.String())).addToDecoder(decoderOfStruct(typ))
@ -408,7 +421,8 @@ func createEncoderOfType(typ reflect.Type) (Encoder, error) {
templateInterface := reflect.New(typ).Elem().Interface()
return &marshalerEncoder{extractInterface(templateInterface)}, nil
}
switch typ.Kind() {
kind := typ.Kind()
switch kind {
case reflect.String:
return &stringCodec{}, nil
case reflect.Int:
@ -438,7 +452,11 @@ func createEncoderOfType(typ reflect.Type) (Encoder, error) {
case reflect.Bool:
return &boolCodec{}, nil
case reflect.Interface:
return &interfaceCodec{}, nil
if typ.NumMethod() == 0 {
return &emptyInterfaceCodec{}, nil
} else {
return &nonEmptyInterfaceCodec{}, nil
}
case reflect.Struct:
return prefix(fmt.Sprintf("[%s]", typ.String())).addToEncoder(encoderOfStruct(typ))
case reflect.Slice:

View File

@ -272,25 +272,56 @@ func (codec *boolCodec) isEmpty(ptr unsafe.Pointer) bool {
return !(*((*bool)(ptr)))
}
type interfaceCodec struct {
type emptyInterfaceCodec struct {
}
func (codec *interfaceCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
func (codec *emptyInterfaceCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
*((*interface{})(ptr)) = iter.Read()
}
func (codec *interfaceCodec) encode(ptr unsafe.Pointer, stream *Stream) {
func (codec *emptyInterfaceCodec) encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteVal(*((*interface{})(ptr)))
}
func (encoder *interfaceCodec) encodeInterface(val interface{}, stream *Stream) {
func (encoder *emptyInterfaceCodec) encodeInterface(val interface{}, stream *Stream) {
stream.WriteVal(val)
}
func (codec *interfaceCodec) isEmpty(ptr unsafe.Pointer) bool {
func (codec *emptyInterfaceCodec) isEmpty(ptr unsafe.Pointer) bool {
return ptr == nil
}
type nonEmptyInterfaceCodec struct {
}
func (codec *nonEmptyInterfaceCodec) decode(ptr unsafe.Pointer, iter *Iterator) {
nonEmptyInterface := (*nonEmptyInterface)(ptr)
var i interface{}
e := (*emptyInterface)(unsafe.Pointer(&i))
e.typ = nonEmptyInterface.itab.typ
e.word = nonEmptyInterface.word
iter.ReadVal(&i)
nonEmptyInterface.word = e.word
}
func (codec *nonEmptyInterfaceCodec) encode(ptr unsafe.Pointer, stream *Stream) {
nonEmptyInterface := (*nonEmptyInterface)(ptr)
var i interface{}
e := (*emptyInterface)(unsafe.Pointer(&i))
e.typ = nonEmptyInterface.itab.typ
e.word = nonEmptyInterface.word
stream.WriteVal(i)
}
func (encoder *nonEmptyInterfaceCodec) encodeInterface(val interface{}, stream *Stream) {
stream.WriteVal(val)
}
func (codec *nonEmptyInterfaceCodec) isEmpty(ptr unsafe.Pointer) bool {
nonEmptyInterface := (*nonEmptyInterface)(ptr)
return nonEmptyInterface.word == nil
}
type anyCodec struct {
}

View File

@ -212,4 +212,4 @@ func Test_unmarshaler_and_decoder(t *testing.T) {
err = Unmarshal([]byte(`{"Field":"hello"}`), &obj)
should.Nil(err)
should.Equal(10, int(*obj.Field))
}
}

View File

@ -91,4 +91,50 @@ func Test_read_custom_interface(t *testing.T) {
err := UnmarshalFromString(`"hello"`, &val)
should.Nil(err)
should.Equal("hello", val.Hello())
}
func Test_decode_object_contain_empty_interface(t *testing.T) {
type TestObject struct {
Field interface{}
}
should := require.New(t)
obj := TestObject{}
obj.Field = 1024
should.Nil(UnmarshalFromString(`{"Field": "hello"}`, &obj))
should.Equal("hello", obj.Field)
}
func Test_decode_object_contain_non_empty_interface(t *testing.T) {
type TestObject struct {
Field MyInterface
}
should := require.New(t)
obj := TestObject{}
obj.Field = MyString("abc")
should.Nil(UnmarshalFromString(`{"Field": "hello"}`, &obj))
should.Equal(MyString("hello"), obj.Field)
}
func Test_encode_object_contain_empty_interface(t *testing.T) {
type TestObject struct {
Field interface{}
}
should := require.New(t)
obj := TestObject{}
obj.Field = 1024
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Field":1024}`, str)
}
func Test_encode_object_contain_non_empty_interface(t *testing.T) {
type TestObject struct {
Field MyInterface
}
should := require.New(t)
obj := TestObject{}
obj.Field = MyString("hello")
str, err := MarshalToString(obj)
should.Nil(err)
should.Equal(`{"Field":"hello"}`, str)
}