podman
211 строк · 5.2 Кб
1package jsoniter
2
3import (
4"fmt"
5"github.com/modern-go/reflect2"
6"io"
7"reflect"
8"unsafe"
9)
10
11func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder {
12type bindingTo struct {
13binding *Binding
14toName string
15ignored bool
16}
17orderedBindings := []*bindingTo{}
18structDescriptor := describeStruct(ctx, typ)
19for _, binding := range structDescriptor.Fields {
20for _, toName := range binding.ToNames {
21new := &bindingTo{
22binding: binding,
23toName: toName,
24}
25for _, old := range orderedBindings {
26if old.toName != toName {
27continue
28}
29old.ignored, new.ignored = resolveConflictBinding(ctx.frozenConfig, old.binding, new.binding)
30}
31orderedBindings = append(orderedBindings, new)
32}
33}
34if len(orderedBindings) == 0 {
35return &emptyStructEncoder{}
36}
37finalOrderedFields := []structFieldTo{}
38for _, bindingTo := range orderedBindings {
39if !bindingTo.ignored {
40finalOrderedFields = append(finalOrderedFields, structFieldTo{
41encoder: bindingTo.binding.Encoder.(*structFieldEncoder),
42toName: bindingTo.toName,
43})
44}
45}
46return &structEncoder{typ, finalOrderedFields}
47}
48
49func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty {
50encoder := createEncoderOfNative(ctx, typ)
51if encoder != nil {
52return encoder
53}
54kind := typ.Kind()
55switch kind {
56case reflect.Interface:
57return &dynamicEncoder{typ}
58case reflect.Struct:
59return &structEncoder{typ: typ}
60case reflect.Array:
61return &arrayEncoder{}
62case reflect.Slice:
63return &sliceEncoder{}
64case reflect.Map:
65return encoderOfMap(ctx, typ)
66case reflect.Ptr:
67return &OptionalEncoder{}
68default:
69return &lazyErrorEncoder{err: fmt.Errorf("unsupported type: %v", typ)}
70}
71}
72
73func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) {
74newTagged := new.Field.Tag().Get(cfg.getTagKey()) != ""
75oldTagged := old.Field.Tag().Get(cfg.getTagKey()) != ""
76if newTagged {
77if oldTagged {
78if len(old.levels) > len(new.levels) {
79return true, false
80} else if len(new.levels) > len(old.levels) {
81return false, true
82} else {
83return true, true
84}
85} else {
86return true, false
87}
88} else {
89if oldTagged {
90return true, false
91}
92if len(old.levels) > len(new.levels) {
93return true, false
94} else if len(new.levels) > len(old.levels) {
95return false, true
96} else {
97return true, true
98}
99}
100}
101
102type structFieldEncoder struct {
103field reflect2.StructField
104fieldEncoder ValEncoder
105omitempty bool
106}
107
108func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
109fieldPtr := encoder.field.UnsafeGet(ptr)
110encoder.fieldEncoder.Encode(fieldPtr, stream)
111if stream.Error != nil && stream.Error != io.EOF {
112stream.Error = fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error.Error())
113}
114}
115
116func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool {
117fieldPtr := encoder.field.UnsafeGet(ptr)
118return encoder.fieldEncoder.IsEmpty(fieldPtr)
119}
120
121func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool {
122isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil)
123if !converted {
124return false
125}
126fieldPtr := encoder.field.UnsafeGet(ptr)
127return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr)
128}
129
130type IsEmbeddedPtrNil interface {
131IsEmbeddedPtrNil(ptr unsafe.Pointer) bool
132}
133
134type structEncoder struct {
135typ reflect2.Type
136fields []structFieldTo
137}
138
139type structFieldTo struct {
140encoder *structFieldEncoder
141toName string
142}
143
144func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
145stream.WriteObjectStart()
146isNotFirst := false
147for _, field := range encoder.fields {
148if field.encoder.omitempty && field.encoder.IsEmpty(ptr) {
149continue
150}
151if field.encoder.IsEmbeddedPtrNil(ptr) {
152continue
153}
154if isNotFirst {
155stream.WriteMore()
156}
157stream.WriteObjectField(field.toName)
158field.encoder.Encode(ptr, stream)
159isNotFirst = true
160}
161stream.WriteObjectEnd()
162if stream.Error != nil && stream.Error != io.EOF {
163stream.Error = fmt.Errorf("%v.%s", encoder.typ, stream.Error.Error())
164}
165}
166
167func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool {
168return false
169}
170
171type emptyStructEncoder struct {
172}
173
174func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
175stream.WriteEmptyObject()
176}
177
178func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool {
179return false
180}
181
182type stringModeNumberEncoder struct {
183elemEncoder ValEncoder
184}
185
186func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
187stream.writeByte('"')
188encoder.elemEncoder.Encode(ptr, stream)
189stream.writeByte('"')
190}
191
192func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool {
193return encoder.elemEncoder.IsEmpty(ptr)
194}
195
196type stringModeStringEncoder struct {
197elemEncoder ValEncoder
198cfg *frozenConfig
199}
200
201func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
202tempStream := encoder.cfg.BorrowStream(nil)
203tempStream.Attachment = stream.Attachment
204defer encoder.cfg.ReturnStream(tempStream)
205encoder.elemEncoder.Encode(ptr, tempStream)
206stream.WriteString(string(tempStream.Buffer()))
207}
208
209func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
210return encoder.elemEncoder.IsEmpty(ptr)
211}
212