1
0
mirror of https://github.com/json-iterator/go.git synced 2025-04-20 11:28:49 +02:00

when embedded ptr is nil, the fields should be omitted

This commit is contained in:
Tao Wen 2018-02-16 17:32:41 +08:00
parent a7a34507ab
commit 9dafbc667f
6 changed files with 66 additions and 50 deletions

View File

@ -340,14 +340,10 @@ func createEncoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) Val
}
if typ.Implements(textMarshalerType) {
checkIsEmpty := createCheckIsEmpty(cfg, typ)
templateInterface := reflect.New(typ).Elem().Interface()
var encoder ValEncoder = &textMarshalerEncoder{
templateInterface: extractInterface(templateInterface),
valType: reflect2.Type2(typ),
checkIsEmpty: checkIsEmpty,
}
if typ.Kind() == reflect.Ptr {
encoder = &OptionalEncoder{encoder}
}
return encoder
}
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
@ -393,10 +389,7 @@ func createCheckIsEmpty(cfg *frozenConfig, typ reflect.Type) checkIsEmpty {
case reflect.Bool:
return &boolCodec{}
case reflect.Interface:
if typ.NumMethod() == 0 {
return &emptyInterfaceCodec{}
}
return &nonEmptyInterfaceCodec{}
return &dynamicEncoder{reflect2.Type2(typ)}
case reflect.Struct:
return &structEncoder{typ: typ}
case reflect.Array:
@ -492,10 +485,7 @@ func createEncoderOfSimpleType(cfg *frozenConfig, prefix string, typ reflect.Typ
}
return &boolCodec{}
case reflect.Interface:
if typ.NumMethod() == 0 {
return &emptyInterfaceCodec{}
}
return &nonEmptyInterfaceCodec{}
return &dynamicEncoder{reflect2.Type2(typ)}
case reflect.Struct:
return encoderOfStruct(cfg, prefix, typ)
case reflect.Array:

View File

@ -17,8 +17,6 @@ var extensions = []Extension{}
// StructDescriptor describe how should we encode/decode the struct
type StructDescriptor struct {
onePtrEmbedded bool
onePtrOptimization bool
Type reflect.Type
Fields []*Binding
}
@ -297,25 +295,7 @@ func describeStruct(cfg *frozenConfig, prefix string, typ reflect.Type) *StructD
return createStructDescriptor(cfg, typ, bindings, embeddedBindings)
}
func createStructDescriptor(cfg *frozenConfig, typ reflect.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor {
onePtrEmbedded := false
onePtrOptimization := false
if typ.NumField() == 1 {
firstField := typ.Field(0)
switch firstField.Type.Kind() {
case reflect.Ptr:
if firstField.Anonymous && firstField.Type.Elem().Kind() == reflect.Struct {
onePtrEmbedded = true
}
fallthrough
case reflect.Map:
onePtrOptimization = true
case reflect.Struct:
onePtrOptimization = isStructOnePtr(firstField.Type)
}
}
structDescriptor := &StructDescriptor{
onePtrEmbedded: onePtrEmbedded,
onePtrOptimization: onePtrOptimization,
Type: typ,
Fields: bindings,
}

View File

@ -357,6 +357,20 @@ func (codec *nonEmptyInterfaceCodec) IsEmpty(ptr unsafe.Pointer) bool {
return nonEmptyInterface.word == nil
}
type dynamicEncoder struct {
valType reflect2.Type
}
func (encoder *dynamicEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
obj := encoder.valType.UnsafeIndirect(ptr)
stream.WriteVal(obj)
}
func (encoder *dynamicEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.valType.UnsafeIndirect(ptr) == nil
}
type anyCodec struct {
}
@ -390,7 +404,7 @@ func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
number := *((*json.Number)(ptr))
if len(number) == 0 {
stream.WriteRaw("0")
stream.writeByte('0')
} else {
stream.WriteRaw(string(number))
}
@ -418,7 +432,7 @@ func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
number := *((*Number)(ptr))
if len(number) == 0 {
stream.WriteRaw("0")
stream.writeByte('0')
} else {
stream.WriteRaw(string(number))
}
@ -603,15 +617,17 @@ func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
}
type textMarshalerEncoder struct {
templateInterface emptyInterface
valType reflect2.Type
checkIsEmpty checkIsEmpty
}
func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
templateInterface := encoder.templateInterface
templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
marshaler := (*realInterface).(encoding.TextMarshaler)
obj := encoder.valType.UnsafeIndirect(ptr)
if obj == nil {
stream.WriteNil()
return
}
marshaler := (obj).(encoding.TextMarshaler)
bytes, err := marshaler.MarshalText()
if err != nil {
stream.Error = err

View File

@ -88,5 +88,22 @@ func (encoder *dereferenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
}
func (encoder *dereferenceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.ValueEncoder.IsEmpty(*((*unsafe.Pointer)(ptr)))
dePtr := *((*unsafe.Pointer)(ptr))
if dePtr == nil {
return true
}
return encoder.ValueEncoder.IsEmpty(dePtr)
}
func (encoder *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool {
deReferenced := *((*unsafe.Pointer)(ptr))
if deReferenced == nil {
return true
}
isEmbeddedPtrNil, converted := encoder.ValueEncoder.(IsEmbeddedPtrNil)
if !converted {
return false
}
fieldPtr := unsafe.Pointer(deReferenced)
return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr)
}

View File

@ -42,8 +42,7 @@ func encoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValEnco
})
}
}
return &structEncoder{typ, structDescriptor.onePtrEmbedded,
structDescriptor.onePtrOptimization, finalOrderedFields}
return &structEncoder{typ, finalOrderedFields}
}
func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) {
@ -120,11 +119,22 @@ func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.fieldEncoder.IsEmpty(fieldPtr)
}
func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool {
isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil)
if !converted {
return false
}
fieldPtr := unsafe.Pointer(uintptr(ptr) + encoder.field.Offset)
return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr)
}
type IsEmbeddedPtrNil interface {
IsEmbeddedPtrNil(ptr unsafe.Pointer) bool
}
type structEncoder struct {
typ reflect.Type
onePtrEmbedded bool
onePtrOptimization bool
fields []structFieldTo
typ reflect.Type
fields []structFieldTo
}
type structFieldTo struct {
@ -139,6 +149,9 @@ func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
if field.encoder.omitempty && field.encoder.IsEmpty(ptr) {
continue
}
if field.encoder.IsEmbeddedPtrNil(ptr) {
continue
}
if isNotFirst {
stream.WriteMore()
}

View File

@ -92,7 +92,8 @@ func init() {
}{&StructVarious{}},
struct {
*StructVarious
}{},
Field int
}{nil, 10},
struct {
Field1 int
Field2 [1]*float64
@ -172,7 +173,6 @@ type CacheItem struct {
MaxAge int `json:"cacheAge"`
}
type orderA struct {
Field2 string
}