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

196 lines
5.0 KiB
Go
Raw Normal View History

2017-01-07 01:49:50 +02:00
package jsoniter
import (
"fmt"
2017-06-06 17:27:00 +02:00
"io"
2017-01-07 01:49:50 +02:00
"reflect"
"strings"
2017-08-25 06:53:23 +02:00
"unsafe"
2017-01-07 01:49:50 +02:00
)
func encoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder {
type bindingTo struct {
binding *Binding
toName string
ignored bool
}
orderedBindings := []*bindingTo{}
structDescriptor := describeStruct(cfg, prefix, 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
}
2017-08-21 18:12:09 +02:00
old.ignored, new.ignored = resolveConflictBinding(cfg, 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, structDescriptor.onePtrEmbedded,
structDescriptor.onePtrOptimization, finalOrderedFields}
}
2017-08-21 18:12:09 +02:00
func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) {
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
}
func decoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValDecoder {
bindings := map[string]*Binding{}
structDescriptor := describeStruct(cfg, prefix, typ)
for _, binding := range structDescriptor.Fields {
2017-06-20 07:33:40 +02:00
for _, fromName := range binding.FromNames {
old := bindings[fromName]
if old == nil {
bindings[fromName] = binding
continue
}
2017-08-21 18:12:09 +02:00
ignoreOld, ignoreNew := resolveConflictBinding(cfg, old, binding)
if ignoreOld {
delete(bindings, fromName)
}
if !ignoreNew {
bindings[fromName] = binding
}
2017-05-24 03:39:11 +02:00
}
}
fields := map[string]*structFieldDecoder{}
for k, binding := range bindings {
fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder)
}
return createStructDecoder(typ, fields)
2017-05-24 03:39:11 +02:00
}
2017-01-09 13:19:48 +02:00
type structFieldEncoder struct {
field *reflect.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) {
2017-07-09 05:24:26 +02:00
fieldPtr := unsafe.Pointer(uintptr(ptr) + encoder.field.Offset)
encoder.fieldEncoder.Encode(fieldPtr, stream)
2017-01-09 13:19:48 +02:00
if stream.Error != nil && stream.Error != io.EOF {
stream.Error = fmt.Errorf("%s: %s", encoder.field.Name, stream.Error.Error())
}
}
2017-06-20 09:11:01 +02:00
func (encoder *structFieldEncoder) EncodeInterface(val interface{}, stream *Stream) {
2017-06-20 11:43:47 +02:00
WriteToStream(val, stream, encoder)
2017-01-25 18:25:17 +02:00
}
2017-06-20 09:11:01 +02:00
func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool {
2017-07-09 05:24:26 +02:00
fieldPtr := unsafe.Pointer(uintptr(ptr) + encoder.field.Offset)
return encoder.fieldEncoder.IsEmpty(fieldPtr)
2017-03-08 17:38:25 +02:00
}
2017-01-09 13:19:48 +02:00
type structEncoder struct {
typ reflect.Type
onePtrEmbedded bool
onePtrOptimization bool
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 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) EncodeInterface(val interface{}, stream *Stream) {
e := (*emptyInterface)(unsafe.Pointer(&val))
if encoder.onePtrOptimization {
if e.word == nil && encoder.onePtrEmbedded {
stream.WriteObjectStart()
stream.WriteObjectEnd()
return
}
ptr := uintptr(e.word)
e.word = unsafe.Pointer(&ptr)
}
if reflect.TypeOf(val).Kind() == reflect.Ptr {
encoder.Encode(unsafe.Pointer(&e.word), stream)
} else {
encoder.Encode(e.word, stream)
}
2017-01-25 18:25:17 +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) EncodeInterface(val interface{}, stream *Stream) {
2017-06-20 11:43:47 +02:00
WriteToStream(val, stream, encoder)
2017-03-08 17:38:25 +02:00
}
2017-06-20 09:11:01 +02:00
func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return false
}