mirror of
https://github.com/json-iterator/go.git
synced 2025-05-28 22:17:38 +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 {
|
||||
valueType reflect.Type
|
||||
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 {
|
||||
mapType reflect.Type
|
||||
elemType reflect.Type
|
||||
@ -374,6 +397,20 @@ func decoderOfType(typ reflect.Type) (Decoder, error) {
|
||||
if 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() {
|
||||
case reflect.String:
|
||||
return &stringCodec{}, nil
|
||||
@ -410,7 +447,7 @@ func decoderOfType(typ reflect.Type) (Decoder, error) {
|
||||
return nil, errors.New("unsupportd type: " + typ.String())
|
||||
}
|
||||
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:
|
||||
return prefix("[slice]").addToDecoder(decoderOfSlice(typ))
|
||||
case reflect.Map:
|
||||
@ -431,6 +468,20 @@ func encoderOfType(typ reflect.Type) (Encoder, error) {
|
||||
if 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() {
|
||||
case reflect.String:
|
||||
return &stringCodec{}, nil
|
||||
@ -463,7 +514,7 @@ func encoderOfType(typ reflect.Type) (Encoder, error) {
|
||||
case reflect.Interface:
|
||||
return &interfaceCodec{}, nil
|
||||
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:
|
||||
return prefix("[slice]").addToEncoder(encoderOfSlice(typ))
|
||||
case reflect.Map:
|
||||
@ -490,7 +541,7 @@ func encoderOfOptional(typ reflect.Type) (Encoder, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &optionalEncoder{elemType, decoder}, nil
|
||||
return &optionalEncoder{ decoder}, nil
|
||||
}
|
||||
|
||||
func decoderOfMap(typ reflect.Type) (Decoder, error) {
|
||||
|
@ -21,7 +21,7 @@ func encoderOfSlice(typ reflect.Type) (Encoder, error) {
|
||||
return nil, err
|
||||
}
|
||||
if typ.Elem().Kind() == reflect.Map {
|
||||
encoder = &optionalEncoder{typ.Elem(), encoder}
|
||||
encoder = &optionalEncoder{ encoder}
|
||||
}
|
||||
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
|
||||
// but if struct only has one map, it is inlined
|
||||
if field.Type.Kind() == reflect.Map && typ.NumField() > 1 {
|
||||
encoder = &optionalEncoder{field.Type, encoder}
|
||||
encoder = &optionalEncoder{encoder}
|
||||
}
|
||||
}
|
||||
for _, fieldName := range fieldNames {
|
||||
|
@ -186,3 +186,17 @@ func Test_any_within_struct(t *testing.T) {
|
||||
should.Equal("hello", obj.Field1.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