.github
alerting
client
config
controller
core
docs
example
jsonpath
k8s
k8stest
metric
pattern
security
static
storage
vendor
cloud.google.com
github.com
TwinProduction
beorn7
boltdb
cespare
davecgh
go-ping
gogo
golang
google
googleapis
gorilla
imdario
json-iterator
go
.codecov.yml
.gitignore
.travis.yml
Gopkg.lock
Gopkg.toml
LICENSE
README.md
adapter.go
any.go
any_array.go
any_bool.go
any_float.go
any_int32.go
any_int64.go
any_invalid.go
any_nil.go
any_number.go
any_object.go
any_str.go
any_uint32.go
any_uint64.go
build.sh
config.go
fuzzy_mode_convert_table.md
go.mod
go.sum
iter.go
iter_array.go
iter_float.go
iter_int.go
iter_object.go
iter_skip.go
iter_skip_sloppy.go
iter_skip_strict.go
iter_str.go
jsoniter.go
pool.go
reflect.go
reflect_array.go
reflect_dynamic.go
reflect_extension.go
reflect_json_number.go
reflect_json_raw_message.go
reflect_map.go
reflect_marshaler.go
reflect_native.go
reflect_optional.go
reflect_slice.go
reflect_struct_decoder.go
reflect_struct_encoder.go
stream.go
stream_float.go
stream_int.go
stream_str.go
test.sh
matttproud
miekg
modern-go
prometheus
spf13
golang.org
google.golang.org
gopkg.in
k8s.io
sigs.k8s.io
modules.txt
watchdog
.dockerignore
.gitattributes
.gitignore
Dockerfile
LICENSE.md
README.md
config.yaml
go.mod
go.sum
main.go
212 lines
5.2 KiB
Go
212 lines
5.2 KiB
Go
package jsoniter
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/modern-go/reflect2"
|
|
"io"
|
|
"reflect"
|
|
"unsafe"
|
|
)
|
|
|
|
func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder {
|
|
type bindingTo struct {
|
|
binding *Binding
|
|
toName string
|
|
ignored bool
|
|
}
|
|
orderedBindings := []*bindingTo{}
|
|
structDescriptor := describeStruct(ctx, typ)
|
|
for _, binding := range structDescriptor.Fields {
|
|
for _, toName := range binding.ToNames {
|
|
new := &bindingTo{
|
|
binding: binding,
|
|
toName: toName,
|
|
}
|
|
for _, old := range orderedBindings {
|
|
if old.toName != toName {
|
|
continue
|
|
}
|
|
old.ignored, new.ignored = resolveConflictBinding(ctx.frozenConfig, old.binding, new.binding)
|
|
}
|
|
orderedBindings = append(orderedBindings, new)
|
|
}
|
|
}
|
|
if len(orderedBindings) == 0 {
|
|
return &emptyStructEncoder{}
|
|
}
|
|
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}
|
|
}
|
|
|
|
func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty {
|
|
encoder := createEncoderOfNative(ctx, typ)
|
|
if encoder != nil {
|
|
return encoder
|
|
}
|
|
kind := typ.Kind()
|
|
switch kind {
|
|
case reflect.Interface:
|
|
return &dynamicEncoder{typ}
|
|
case reflect.Struct:
|
|
return &structEncoder{typ: typ}
|
|
case reflect.Array:
|
|
return &arrayEncoder{}
|
|
case reflect.Slice:
|
|
return &sliceEncoder{}
|
|
case reflect.Map:
|
|
return encoderOfMap(ctx, typ)
|
|
case reflect.Ptr:
|
|
return &OptionalEncoder{}
|
|
default:
|
|
return &lazyErrorEncoder{err: fmt.Errorf("unsupported type: %v", typ)}
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
type structFieldEncoder struct {
|
|
field reflect2.StructField
|
|
fieldEncoder ValEncoder
|
|
omitempty bool
|
|
}
|
|
|
|
func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
|
fieldPtr := encoder.field.UnsafeGet(ptr)
|
|
encoder.fieldEncoder.Encode(fieldPtr, stream)
|
|
if stream.Error != nil && stream.Error != io.EOF {
|
|
stream.Error = fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error.Error())
|
|
}
|
|
}
|
|
|
|
func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
|
fieldPtr := encoder.field.UnsafeGet(ptr)
|
|
return encoder.fieldEncoder.IsEmpty(fieldPtr)
|
|
}
|
|
|
|
func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool {
|
|
isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil)
|
|
if !converted {
|
|
return false
|
|
}
|
|
fieldPtr := encoder.field.UnsafeGet(ptr)
|
|
return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr)
|
|
}
|
|
|
|
type IsEmbeddedPtrNil interface {
|
|
IsEmbeddedPtrNil(ptr unsafe.Pointer) bool
|
|
}
|
|
|
|
type structEncoder struct {
|
|
typ reflect2.Type
|
|
fields []structFieldTo
|
|
}
|
|
|
|
type structFieldTo struct {
|
|
encoder *structFieldEncoder
|
|
toName string
|
|
}
|
|
|
|
func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
|
stream.WriteObjectStart()
|
|
isNotFirst := false
|
|
for _, field := range encoder.fields {
|
|
if field.encoder.omitempty && field.encoder.IsEmpty(ptr) {
|
|
continue
|
|
}
|
|
if field.encoder.IsEmbeddedPtrNil(ptr) {
|
|
continue
|
|
}
|
|
if isNotFirst {
|
|
stream.WriteMore()
|
|
}
|
|
stream.WriteObjectField(field.toName)
|
|
field.encoder.Encode(ptr, stream)
|
|
isNotFirst = true
|
|
}
|
|
stream.WriteObjectEnd()
|
|
if stream.Error != nil && stream.Error != io.EOF {
|
|
stream.Error = fmt.Errorf("%v.%s", encoder.typ, stream.Error.Error())
|
|
}
|
|
}
|
|
|
|
func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
|
return false
|
|
}
|
|
|
|
type emptyStructEncoder struct {
|
|
}
|
|
|
|
func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
|
stream.WriteEmptyObject()
|
|
}
|
|
|
|
func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
|
return false
|
|
}
|
|
|
|
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
|
|
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)
|
|
}
|