DockerCLI/vendor/github.com/json-iterator/go/reflect_struct_encoder.go

212 lines
5.2 KiB
Go
Raw Normal View History

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)
[20.10] vendor: github.com/json-iterator/go v1.1.12 for Go 1.18 compatibility full diff: https://github.com/json-iterator/go/compare/0ff49de124c6f76f8494e194af75bde0f1a49a29...024077e996b048517130b21ea6bf12aa23055d3d Fixes a nil-pointer exception on go 1.18; ``` === FAIL: cli/context/kubernetes TestSaveLoadContexts (0.00s) panic: runtime error: invalid memory address or nil pointer dereference [recovered] panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x40fcbc] goroutine 19 [running]: testing.tRunner.func1.2({0xa7e080, 0x1073930}) /usr/local/go/src/testing/testing.go:1389 +0x24e testing.tRunner.func1() /usr/local/go/src/testing/testing.go:1392 +0x39f panic({0xa7e080, 0x1073930}) /usr/local/go/src/runtime/panic.go:838 +0x207 reflect.mapiternext(0x40?) /usr/local/go/src/runtime/map.go:1378 +0x19 github.com/docker/cli/vendor/github.com/modern-go/reflect2.(*UnsafeMapIterator).UnsafeNext(0x8?) /go/src/github.com/docker/cli/vendor/github.com/modern-go/reflect2/unsafe_map.go:136 +0x32 github.com/docker/cli/vendor/github.com/json-iterator/go.(*sortKeysMapEncoder).Encode(0xc000478930, 0xc0000ca3a8, 0xc0000bae40) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect_map.go:293 +0x335 github.com/docker/cli/vendor/github.com/json-iterator/go.(*placeholderEncoder).Encode(0xc00046c898?, 0x95d787?, 0xc0000bae58?) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect.go:327 +0x22 github.com/docker/cli/vendor/github.com/json-iterator/go.(*structFieldEncoder).Encode(0xc000482630, 0xa2790c?, 0xc0000bae40) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect_struct_encoder.go:110 +0x56 github.com/docker/cli/vendor/github.com/json-iterator/go.(*structEncoder).Encode(0xc000482780, 0xb3a599?, 0xc0000bae40) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect_struct_encoder.go:158 +0x652 github.com/docker/cli/vendor/github.com/json-iterator/go.(*placeholderEncoder).Encode(0xc00046ca10?, 0x95d787?, 0xc0000bae58?) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect.go:327 +0x22 github.com/docker/cli/vendor/github.com/json-iterator/go.(*structFieldEncoder).Encode(0xc0004829f0, 0xa0fd11?, 0xc0000bae40) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect_struct_encoder.go:110 +0x56 github.com/docker/cli/vendor/github.com/json-iterator/go.(*structEncoder).Encode(0xc000482a50, 0x40aa15?, 0xc0000bae40) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect_struct_encoder.go:158 +0x652 github.com/docker/cli/vendor/github.com/json-iterator/go.(*sliceEncoder).Encode(0xc00047e198, 0xc0003a83c8, 0xc0000bae40) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect_slice.go:38 +0x2bb github.com/docker/cli/vendor/github.com/json-iterator/go.(*structFieldEncoder).Encode(0xc0004837a0, 0xa12e12?, 0xc0000bae40) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect_struct_encoder.go:110 +0x56 github.com/docker/cli/vendor/github.com/json-iterator/go.(*structEncoder).Encode(0xc000483890, 0x0?, 0xc0000bae40) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect_struct_encoder.go:158 +0x652 github.com/docker/cli/vendor/github.com/json-iterator/go.(*OptionalEncoder).Encode(0xc0003b6be0?, 0x0?, 0x0?) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect_optional.go:74 +0xa4 github.com/docker/cli/vendor/github.com/json-iterator/go.(*onePtrEncoder).Encode(0xc000471e30, 0xc0003a8370, 0xc000460720?) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect.go:214 +0x82 github.com/docker/cli/vendor/github.com/json-iterator/go.(*Stream).WriteVal(0xc0000bae40, {0xabe4a0, 0xc0003a8370}) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/reflect.go:93 +0x158 github.com/docker/cli/vendor/github.com/json-iterator/go.(*frozenConfig).Marshal(0xc0003b6be0, {0xabe4a0, 0xc0003a8370}) /go/src/github.com/docker/cli/vendor/github.com/json-iterator/go/config.go:299 +0xc9 github.com/docker/cli/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json.(*Serializer).Encode(0xc00043aee0?, {0xc375c0?, 0xc0003a8370?}, {0xc339e0, 0xc000460210}) /go/src/github.com/docker/cli/vendor/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go:310 +0x6d github.com/docker/cli/vendor/k8s.io/apimachinery/pkg/runtime/serializer/versioning.(*codec).Encode(0xc0000f8480, {0xc37570?, 0xc0000bacc0}, {0xc339e0, 0xc000460210}) /go/src/github.com/docker/cli/vendor/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning.go:231 +0x926 github.com/docker/cli/vendor/k8s.io/apimachinery/pkg/runtime.Encode({0x7f48b36ce5c0, 0xc0000f8480}, {0xc37570, 0xc0000bacc0}) /go/src/github.com/docker/cli/vendor/k8s.io/apimachinery/pkg/runtime/codec.go:46 +0x64 github.com/docker/cli/vendor/k8s.io/client-go/tools/clientcmd.Write(...) /go/src/github.com/docker/cli/vendor/k8s.io/client-go/tools/clientcmd/loader.go:469 github.com/docker/cli/cli/context/kubernetes.TestSaveLoadContexts(0xc0004561a0?) /go/src/github.com/docker/cli/cli/context/kubernetes/endpoint_test.go:75 +0xf0a testing.tRunner(0xc0004561a0, 0xb89ea0) /usr/local/go/src/testing/testing.go:1439 +0x102 created by testing.(*T).Run /usr/local/go/src/testing/testing.go:1486 +0x35f ``` Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-08-19 10:12:25 -04:00
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)
}