1
0
mirror of https://github.com/json-iterator/go.git synced 2024-12-03 08:45:22 +02:00
json-iterator/reflect_struct_encoder.go

212 lines
5.2 KiB
Go
Raw Normal View History

2017-01-07 01:49:50 +02:00
package jsoniter
import (
"fmt"
2018-02-28 11:09:30 +02:00
"github.com/modern-go/reflect2"
2017-06-06 17:27:00 +02:00
"io"
2017-01-07 01:49:50 +02:00
"reflect"
2017-08-25 06:53:23 +02:00
"unsafe"
2017-01-07 01:49:50 +02:00
)
2018-02-22 04:12:08 +02:00
func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder {
type bindingTo struct {
binding *Binding
toName string
ignored bool
}
orderedBindings := []*bindingTo{}
2018-02-21 11:59:41 +02:00
structDescriptor := describeStruct(ctx, typ)
for _, binding := range structDescriptor.Fields {
2017-06-20 07:33:40 +02:00
for _, toName := range binding.ToNames {
new := &bindingTo{
binding: binding,
toName: toName,
2017-06-23 02:21:02 +02:00
}
for _, old := range orderedBindings {
if old.toName != toName {
continue
}
2018-02-21 11:59:41 +02:00
old.ignored, new.ignored = resolveConflictBinding(ctx.frozenConfig, old.binding, new.binding)
}
orderedBindings = append(orderedBindings, new)
2017-06-06 17:27:00 +02:00
}
2017-01-09 13:19:48 +02:00
}
if len(orderedBindings) == 0 {
return &emptyStructEncoder{}
2017-01-09 13:19:48 +02:00
}
2017-06-23 02:21:02 +02:00
finalOrderedFields := []structFieldTo{}
for _, bindingTo := range orderedBindings {
if !bindingTo.ignored {
finalOrderedFields = append(finalOrderedFields, structFieldTo{
encoder: bindingTo.binding.Encoder.(*structFieldEncoder),
toName: bindingTo.toName,
})
}
}
return &structEncoder{typ, finalOrderedFields}
}
2018-02-22 04:12:08 +02:00
func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty {
2018-02-23 02:12:45 +02:00
encoder := createEncoderOfNative(ctx, typ)
if encoder != nil {
return encoder
}
kind := typ.Kind()
switch kind {
case reflect.Interface:
2018-02-22 04:12:08 +02:00
return &dynamicEncoder{typ}
case reflect.Struct:
return &structEncoder{typ: typ}
case reflect.Array:
return &arrayEncoder{}
case reflect.Slice:
return &sliceEncoder{}
case reflect.Map:
2018-02-21 11:59:41 +02:00
return encoderOfMap(ctx, typ)
case reflect.Ptr:
return &OptionalEncoder{}
default:
return &lazyErrorEncoder{err: fmt.Errorf("unsupported type: %v", typ)}
}
}
2017-08-21 18:12:09 +02:00
func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) {
2018-02-22 04:12:08 +02:00
newTagged := new.Field.Tag().Get(cfg.getTagKey()) != ""
oldTagged := old.Field.Tag().Get(cfg.getTagKey()) != ""
if newTagged {
if oldTagged {
if len(old.levels) > len(new.levels) {
return true, false
} else if len(new.levels) > len(old.levels) {
return false, true
} else {
return true, true
}
} else {
return true, false
}
} else {
if oldTagged {
return true, false
}
if len(old.levels) > len(new.levels) {
return true, false
} else if len(new.levels) > len(old.levels) {
return false, true
} else {
return true, true
2017-06-23 02:21:02 +02:00
}
}
2017-01-09 13:19:48 +02:00
}
type structFieldEncoder struct {
2018-02-22 04:12:08 +02:00
field reflect2.StructField
fieldEncoder ValEncoder
2017-03-08 17:38:25 +02:00
omitempty bool
2017-01-09 13:19:48 +02:00
}
2017-06-20 09:11:01 +02:00
func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
2018-02-22 04:12:08 +02:00
fieldPtr := encoder.field.UnsafeGet(ptr)
2017-07-09 05:24:26 +02:00
encoder.fieldEncoder.Encode(fieldPtr, stream)
2017-01-09 13:19:48 +02:00
if stream.Error != nil && stream.Error != io.EOF {
2018-02-22 04:12:08 +02:00
stream.Error = fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error.Error())
2017-01-09 13:19:48 +02:00
}
}
2017-06-20 09:11:01 +02:00
func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool {
2018-02-22 04:12:08 +02:00
fieldPtr := encoder.field.UnsafeGet(ptr)
2017-07-09 05:24:26 +02:00
return encoder.fieldEncoder.IsEmpty(fieldPtr)
2017-03-08 17:38:25 +02:00
}
func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool {
isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil)
if !converted {
return false
}
2018-02-22 04:12:08 +02:00
fieldPtr := encoder.field.UnsafeGet(ptr)
return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr)
}
type IsEmbeddedPtrNil interface {
IsEmbeddedPtrNil(ptr unsafe.Pointer) bool
}
2017-01-09 13:19:48 +02:00
type structEncoder struct {
2018-02-22 04:12:08 +02:00
typ reflect2.Type
fields []structFieldTo
2017-06-23 02:21:02 +02:00
}
type structFieldTo struct {
encoder *structFieldEncoder
toName string
2017-01-09 13:19:48 +02:00
}
2017-06-20 09:11:01 +02:00
func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
2017-01-09 13:19:48 +02:00
stream.WriteObjectStart()
2017-03-08 17:38:25 +02:00
isNotFirst := false
2017-06-23 02:21:02 +02:00
for _, field := range encoder.fields {
if field.encoder.omitempty && field.encoder.IsEmpty(ptr) {
2017-03-08 17:38:25 +02:00
continue
}
if field.encoder.IsEmbeddedPtrNil(ptr) {
continue
}
if isNotFirst {
stream.WriteMore()
}
2017-06-23 02:21:02 +02:00
stream.WriteObjectField(field.toName)
field.encoder.Encode(ptr, stream)
2017-03-08 17:38:25 +02:00
isNotFirst = true
2017-01-09 13:19:48 +02:00
}
stream.WriteObjectEnd()
if stream.Error != nil && stream.Error != io.EOF {
stream.Error = fmt.Errorf("%v.%s", encoder.typ, stream.Error.Error())
}
2017-01-09 13:19:48 +02:00
}
2017-06-20 09:11:01 +02:00
func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return false
2017-03-08 17:38:25 +02:00
}
2017-01-09 13:19:48 +02:00
type emptyStructEncoder struct {
}
2017-06-20 09:11:01 +02:00
func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
2017-01-09 13:48:57 +02:00
stream.WriteEmptyObject()
2017-01-25 18:25:17 +02:00
}
2017-06-20 09:11:01 +02:00
func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return false
}
2018-02-20 16:38:35 +02:00
type stringModeNumberEncoder struct {
elemEncoder ValEncoder
}
func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.writeByte('"')
encoder.elemEncoder.Encode(ptr, stream)
stream.writeByte('"')
}
func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.elemEncoder.IsEmpty(ptr)
}
type stringModeStringEncoder struct {
elemEncoder ValEncoder
cfg *frozenConfig
}
func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
tempStream := encoder.cfg.BorrowStream(nil)
tempStream.Attachment = stream.Attachment
2018-02-20 16:38:35 +02:00
defer encoder.cfg.ReturnStream(tempStream)
encoder.elemEncoder.Encode(ptr, tempStream)
stream.WriteString(string(tempStream.Buffer()))
}
func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.elemEncoder.IsEmpty(ptr)
}