mirror of
https://github.com/json-iterator/go.git
synced 2025-06-03 22:27:26 +02:00
support recursive type
This commit is contained in:
parent
6bd835aeb1
commit
91b9e828b7
@ -181,7 +181,6 @@ func (decoder *optionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type optionalEncoder struct {
|
type optionalEncoder struct {
|
||||||
valueType reflect.Type
|
|
||||||
valueEncoder Encoder
|
valueEncoder Encoder
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,6 +204,30 @@ func (encoder *optionalEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type placeholderEncoder struct {
|
||||||
|
valueEncoder Encoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (encoder *placeholderEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
|
||||||
|
encoder.valueEncoder.encode(ptr, stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (encoder *placeholderEncoder) encodeInterface(val interface{}, stream *Stream) {
|
||||||
|
WriteToStream(val, stream, encoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (encoder *placeholderEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||||
|
return encoder.valueEncoder.isEmpty(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
type placeholderDecoder struct {
|
||||||
|
valueDecoder Decoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *placeholderDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
decoder.valueDecoder.decode(ptr, iter)
|
||||||
|
}
|
||||||
|
|
||||||
type mapDecoder struct {
|
type mapDecoder struct {
|
||||||
mapType reflect.Type
|
mapType reflect.Type
|
||||||
elemType reflect.Type
|
elemType reflect.Type
|
||||||
@ -374,6 +397,20 @@ func decoderOfType(typ reflect.Type) (Decoder, error) {
|
|||||||
if typeDecoder != nil {
|
if typeDecoder != nil {
|
||||||
return typeDecoder, nil
|
return typeDecoder, nil
|
||||||
}
|
}
|
||||||
|
cacheKey := typ
|
||||||
|
cachedDecoder := getDecoderFromCache(cacheKey)
|
||||||
|
if cachedDecoder != nil {
|
||||||
|
return cachedDecoder, nil
|
||||||
|
}
|
||||||
|
placeholder := &placeholderDecoder{}
|
||||||
|
addDecoderToCache(cacheKey, placeholder)
|
||||||
|
newDecoder, err := createDecoderOfType(typ)
|
||||||
|
placeholder.valueDecoder = newDecoder
|
||||||
|
addDecoderToCache(cacheKey, newDecoder)
|
||||||
|
return newDecoder, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDecoderOfType(typ reflect.Type) (Decoder, error) {
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return &stringCodec{}, nil
|
return &stringCodec{}, nil
|
||||||
@ -410,7 +447,7 @@ func decoderOfType(typ reflect.Type) (Decoder, error) {
|
|||||||
return nil, errors.New("unsupportd type: " + typ.String())
|
return nil, errors.New("unsupportd type: " + typ.String())
|
||||||
}
|
}
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
return prefix(fmt.Sprintf("[%s]", typeName)).addToDecoder(decoderOfStruct(typ))
|
return prefix(fmt.Sprintf("[%s]", typ.String())).addToDecoder(decoderOfStruct(typ))
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
return prefix("[slice]").addToDecoder(decoderOfSlice(typ))
|
return prefix("[slice]").addToDecoder(decoderOfSlice(typ))
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
@ -431,6 +468,20 @@ func encoderOfType(typ reflect.Type) (Encoder, error) {
|
|||||||
if typeEncoder != nil {
|
if typeEncoder != nil {
|
||||||
return typeEncoder, nil
|
return typeEncoder, nil
|
||||||
}
|
}
|
||||||
|
cacheKey := typ
|
||||||
|
cachedEncoder := getEncoderFromCache(cacheKey)
|
||||||
|
if cachedEncoder != nil {
|
||||||
|
return cachedEncoder, nil
|
||||||
|
}
|
||||||
|
placeholder := &placeholderEncoder{}
|
||||||
|
addEncoderToCache(cacheKey, placeholder)
|
||||||
|
newEncoder, err := createEncoderOfType(typ)
|
||||||
|
placeholder.valueEncoder = newEncoder
|
||||||
|
addEncoderToCache(cacheKey, newEncoder)
|
||||||
|
return newEncoder, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func createEncoderOfType(typ reflect.Type) (Encoder, error) {
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return &stringCodec{}, nil
|
return &stringCodec{}, nil
|
||||||
@ -463,7 +514,7 @@ func encoderOfType(typ reflect.Type) (Encoder, error) {
|
|||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
return &interfaceCodec{}, nil
|
return &interfaceCodec{}, nil
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
return prefix(fmt.Sprintf("[%s]", typeName)).addToEncoder(encoderOfStruct(typ))
|
return prefix(fmt.Sprintf("[%s]", typ.String())).addToEncoder(encoderOfStruct(typ))
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
return prefix("[slice]").addToEncoder(encoderOfSlice(typ))
|
return prefix("[slice]").addToEncoder(encoderOfSlice(typ))
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
@ -490,7 +541,7 @@ func encoderOfOptional(typ reflect.Type) (Encoder, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &optionalEncoder{elemType, decoder}, nil
|
return &optionalEncoder{ decoder}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decoderOfMap(typ reflect.Type) (Decoder, error) {
|
func decoderOfMap(typ reflect.Type) (Decoder, error) {
|
||||||
|
@ -21,7 +21,7 @@ func encoderOfSlice(typ reflect.Type) (Encoder, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if typ.Elem().Kind() == reflect.Map {
|
if typ.Elem().Kind() == reflect.Map {
|
||||||
encoder = &optionalEncoder{typ.Elem(), encoder}
|
encoder = &optionalEncoder{ encoder}
|
||||||
}
|
}
|
||||||
return &sliceEncoder{typ, typ.Elem(), encoder}, nil
|
return &sliceEncoder{typ, typ.Elem(), encoder}, nil
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ func encoderOfStruct(typ reflect.Type) (Encoder, error) {
|
|||||||
// map is stored as pointer in the struct
|
// map is stored as pointer in the struct
|
||||||
// but if struct only has one map, it is inlined
|
// but if struct only has one map, it is inlined
|
||||||
if field.Type.Kind() == reflect.Map && typ.NumField() > 1 {
|
if field.Type.Kind() == reflect.Map && typ.NumField() > 1 {
|
||||||
encoder = &optionalEncoder{field.Type, encoder}
|
encoder = &optionalEncoder{encoder}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, fieldName := range fieldNames {
|
for _, fieldName := range fieldNames {
|
||||||
|
@ -186,3 +186,17 @@ func Test_any_within_struct(t *testing.T) {
|
|||||||
should.Equal("hello", obj.Field1.ToString())
|
should.Equal("hello", obj.Field1.ToString())
|
||||||
should.Equal("[1,2,3]", obj.Field2.ToString())
|
should.Equal("[1,2,3]", obj.Field2.ToString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_recursive_struct(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
type TestObject struct {
|
||||||
|
Field1 string
|
||||||
|
Me *TestObject
|
||||||
|
}
|
||||||
|
obj := TestObject{}
|
||||||
|
str, err := MarshalToString(obj)
|
||||||
|
should.Nil(err)
|
||||||
|
should.Equal(`{"Field1":"","Me":null}`, str)
|
||||||
|
err = UnmarshalFromString(str, &obj)
|
||||||
|
should.Nil(err)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user