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"
|
2017-08-25 06:53:23 +02:00
|
|
|
"unsafe"
|
2018-02-20 17:08:58 +02:00
|
|
|
"github.com/v2pro/plz/reflect2"
|
2017-01-07 01:49:50 +02:00
|
|
|
)
|
|
|
|
|
2017-12-15 04:13:11 +02:00
|
|
|
func encoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValEncoder {
|
2017-06-29 14:34:40 +02:00
|
|
|
type bindingTo struct {
|
|
|
|
binding *Binding
|
|
|
|
toName string
|
|
|
|
ignored bool
|
|
|
|
}
|
|
|
|
orderedBindings := []*bindingTo{}
|
2017-12-15 04:13:11 +02:00
|
|
|
structDescriptor := describeStruct(cfg, prefix, typ)
|
2017-06-29 14:34:40 +02:00
|
|
|
for _, binding := range structDescriptor.Fields {
|
2017-06-20 07:33:40 +02:00
|
|
|
for _, toName := range binding.ToNames {
|
2017-06-29 14:34:40 +02:00
|
|
|
new := &bindingTo{
|
|
|
|
binding: binding,
|
|
|
|
toName: toName,
|
2017-06-23 02:21:02 +02:00
|
|
|
}
|
2017-06-29 14:34:40 +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)
|
2017-06-29 14:34:40 +02:00
|
|
|
}
|
|
|
|
orderedBindings = append(orderedBindings, new)
|
2017-06-06 17:27:00 +02:00
|
|
|
}
|
2017-01-09 13:19:48 +02:00
|
|
|
}
|
2017-06-29 14:34:40 +02:00
|
|
|
if len(orderedBindings) == 0 {
|
2017-12-15 04:13:11 +02:00
|
|
|
return &emptyStructEncoder{}
|
2017-01-09 13:19:48 +02:00
|
|
|
}
|
2017-06-23 02:21:02 +02:00
|
|
|
finalOrderedFields := []structFieldTo{}
|
2017-06-29 14:34:40 +02:00
|
|
|
for _, bindingTo := range orderedBindings {
|
|
|
|
if !bindingTo.ignored {
|
|
|
|
finalOrderedFields = append(finalOrderedFields, structFieldTo{
|
|
|
|
encoder: bindingTo.binding.Encoder.(*structFieldEncoder),
|
|
|
|
toName: bindingTo.toName,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2018-02-16 11:32:41 +02:00
|
|
|
return &structEncoder{typ, finalOrderedFields}
|
2017-06-29 14:34:40 +02:00
|
|
|
}
|
|
|
|
|
2018-02-20 17:08:58 +02:00
|
|
|
func createCheckIsEmpty(cfg *frozenConfig, typ reflect.Type) checkIsEmpty {
|
|
|
|
kind := typ.Kind()
|
|
|
|
switch kind {
|
|
|
|
case reflect.String:
|
|
|
|
return &stringCodec{}
|
|
|
|
case reflect.Int:
|
|
|
|
return &intCodec{}
|
|
|
|
case reflect.Int8:
|
|
|
|
return &int8Codec{}
|
|
|
|
case reflect.Int16:
|
|
|
|
return &int16Codec{}
|
|
|
|
case reflect.Int32:
|
|
|
|
return &int32Codec{}
|
|
|
|
case reflect.Int64:
|
|
|
|
return &int64Codec{}
|
|
|
|
case reflect.Uint:
|
|
|
|
return &uintCodec{}
|
|
|
|
case reflect.Uint8:
|
|
|
|
return &uint8Codec{}
|
|
|
|
case reflect.Uint16:
|
|
|
|
return &uint16Codec{}
|
|
|
|
case reflect.Uint32:
|
|
|
|
return &uint32Codec{}
|
|
|
|
case reflect.Uintptr:
|
|
|
|
return &uintptrCodec{}
|
|
|
|
case reflect.Uint64:
|
|
|
|
return &uint64Codec{}
|
|
|
|
case reflect.Float32:
|
|
|
|
return &float32Codec{}
|
|
|
|
case reflect.Float64:
|
|
|
|
return &float64Codec{}
|
|
|
|
case reflect.Bool:
|
|
|
|
return &boolCodec{}
|
|
|
|
case reflect.Interface:
|
|
|
|
return &dynamicEncoder{reflect2.Type2(typ)}
|
|
|
|
case reflect.Struct:
|
|
|
|
return &structEncoder{typ: typ}
|
|
|
|
case reflect.Array:
|
|
|
|
return &arrayEncoder{}
|
|
|
|
case reflect.Slice:
|
|
|
|
return &sliceEncoder{}
|
|
|
|
case reflect.Map:
|
|
|
|
return encoderOfMap(cfg, "", 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) {
|
|
|
|
newTagged := new.Field.Tag.Get(cfg.getTagKey()) != ""
|
|
|
|
oldTagged := old.Field.Tag.Get(cfg.getTagKey()) != ""
|
2017-06-29 14:34:40 +02:00
|
|
|
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
|
2017-07-09 09:07:53 +02:00
|
|
|
}
|
|
|
|
if len(old.levels) > len(new.levels) {
|
|
|
|
return true, false
|
|
|
|
} else if len(new.levels) > len(old.levels) {
|
|
|
|
return false, true
|
2017-06-29 14:34:40 +02:00
|
|
|
} else {
|
2017-07-09 09:07:53 +02:00
|
|
|
return true, true
|
2017-06-23 02:21:02 +02:00
|
|
|
}
|
|
|
|
}
|
2017-01-09 13:19:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type structFieldEncoder struct {
|
|
|
|
field *reflect.StructField
|
2017-06-20 01:59:45 +02:00
|
|
|
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) 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
|
|
|
}
|
|
|
|
|
2018-02-16 11:32:41 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2017-01-09 13:19:48 +02:00
|
|
|
type structEncoder struct {
|
2018-02-16 11:32:41 +02:00
|
|
|
typ reflect.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
|
|
|
|
}
|
2018-02-16 11:32:41 +02:00
|
|
|
if field.encoder.IsEmbeddedPtrNil(ptr) {
|
|
|
|
continue
|
|
|
|
}
|
2017-03-11 12:17:34 +02:00
|
|
|
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()
|
2017-12-15 04:13:11 +02:00
|
|
|
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 {
|
2017-07-01 05:48:17 +02:00
|
|
|
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 {
|
2017-07-01 05:48:17 +02:00
|
|
|
return false
|
2017-03-11 12:17:34 +02:00
|
|
|
}
|
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)
|
|
|
|
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)
|
|
|
|
}
|