podman

Форк
0
/
reflect_struct_encoder.go 
211 строк · 5.2 Кб
1
package jsoniter
2

3
import (
4
	"fmt"
5
	"github.com/modern-go/reflect2"
6
	"io"
7
	"reflect"
8
	"unsafe"
9
)
10

11
func encoderOfStruct(ctx *ctx, typ reflect2.Type) ValEncoder {
12
	type bindingTo struct {
13
		binding *Binding
14
		toName  string
15
		ignored bool
16
	}
17
	orderedBindings := []*bindingTo{}
18
	structDescriptor := describeStruct(ctx, typ)
19
	for _, binding := range structDescriptor.Fields {
20
		for _, toName := range binding.ToNames {
21
			new := &bindingTo{
22
				binding: binding,
23
				toName:  toName,
24
			}
25
			for _, old := range orderedBindings {
26
				if old.toName != toName {
27
					continue
28
				}
29
				old.ignored, new.ignored = resolveConflictBinding(ctx.frozenConfig, old.binding, new.binding)
30
			}
31
			orderedBindings = append(orderedBindings, new)
32
		}
33
	}
34
	if len(orderedBindings) == 0 {
35
		return &emptyStructEncoder{}
36
	}
37
	finalOrderedFields := []structFieldTo{}
38
	for _, bindingTo := range orderedBindings {
39
		if !bindingTo.ignored {
40
			finalOrderedFields = append(finalOrderedFields, structFieldTo{
41
				encoder: bindingTo.binding.Encoder.(*structFieldEncoder),
42
				toName:  bindingTo.toName,
43
			})
44
		}
45
	}
46
	return &structEncoder{typ, finalOrderedFields}
47
}
48

49
func createCheckIsEmpty(ctx *ctx, typ reflect2.Type) checkIsEmpty {
50
	encoder := createEncoderOfNative(ctx, typ)
51
	if encoder != nil {
52
		return encoder
53
	}
54
	kind := typ.Kind()
55
	switch kind {
56
	case reflect.Interface:
57
		return &dynamicEncoder{typ}
58
	case reflect.Struct:
59
		return &structEncoder{typ: typ}
60
	case reflect.Array:
61
		return &arrayEncoder{}
62
	case reflect.Slice:
63
		return &sliceEncoder{}
64
	case reflect.Map:
65
		return encoderOfMap(ctx, typ)
66
	case reflect.Ptr:
67
		return &OptionalEncoder{}
68
	default:
69
		return &lazyErrorEncoder{err: fmt.Errorf("unsupported type: %v", typ)}
70
	}
71
}
72

73
func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) {
74
	newTagged := new.Field.Tag().Get(cfg.getTagKey()) != ""
75
	oldTagged := old.Field.Tag().Get(cfg.getTagKey()) != ""
76
	if newTagged {
77
		if oldTagged {
78
			if len(old.levels) > len(new.levels) {
79
				return true, false
80
			} else if len(new.levels) > len(old.levels) {
81
				return false, true
82
			} else {
83
				return true, true
84
			}
85
		} else {
86
			return true, false
87
		}
88
	} else {
89
		if oldTagged {
90
			return true, false
91
		}
92
		if len(old.levels) > len(new.levels) {
93
			return true, false
94
		} else if len(new.levels) > len(old.levels) {
95
			return false, true
96
		} else {
97
			return true, true
98
		}
99
	}
100
}
101

102
type structFieldEncoder struct {
103
	field        reflect2.StructField
104
	fieldEncoder ValEncoder
105
	omitempty    bool
106
}
107

108
func (encoder *structFieldEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
109
	fieldPtr := encoder.field.UnsafeGet(ptr)
110
	encoder.fieldEncoder.Encode(fieldPtr, stream)
111
	if stream.Error != nil && stream.Error != io.EOF {
112
		stream.Error = fmt.Errorf("%s: %s", encoder.field.Name(), stream.Error.Error())
113
	}
114
}
115

116
func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool {
117
	fieldPtr := encoder.field.UnsafeGet(ptr)
118
	return encoder.fieldEncoder.IsEmpty(fieldPtr)
119
}
120

121
func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool {
122
	isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil)
123
	if !converted {
124
		return false
125
	}
126
	fieldPtr := encoder.field.UnsafeGet(ptr)
127
	return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr)
128
}
129

130
type IsEmbeddedPtrNil interface {
131
	IsEmbeddedPtrNil(ptr unsafe.Pointer) bool
132
}
133

134
type structEncoder struct {
135
	typ    reflect2.Type
136
	fields []structFieldTo
137
}
138

139
type structFieldTo struct {
140
	encoder *structFieldEncoder
141
	toName  string
142
}
143

144
func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
145
	stream.WriteObjectStart()
146
	isNotFirst := false
147
	for _, field := range encoder.fields {
148
		if field.encoder.omitempty && field.encoder.IsEmpty(ptr) {
149
			continue
150
		}
151
		if field.encoder.IsEmbeddedPtrNil(ptr) {
152
			continue
153
		}
154
		if isNotFirst {
155
			stream.WriteMore()
156
		}
157
		stream.WriteObjectField(field.toName)
158
		field.encoder.Encode(ptr, stream)
159
		isNotFirst = true
160
	}
161
	stream.WriteObjectEnd()
162
	if stream.Error != nil && stream.Error != io.EOF {
163
		stream.Error = fmt.Errorf("%v.%s", encoder.typ, stream.Error.Error())
164
	}
165
}
166

167
func (encoder *structEncoder) IsEmpty(ptr unsafe.Pointer) bool {
168
	return false
169
}
170

171
type emptyStructEncoder struct {
172
}
173

174
func (encoder *emptyStructEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
175
	stream.WriteEmptyObject()
176
}
177

178
func (encoder *emptyStructEncoder) IsEmpty(ptr unsafe.Pointer) bool {
179
	return false
180
}
181

182
type stringModeNumberEncoder struct {
183
	elemEncoder ValEncoder
184
}
185

186
func (encoder *stringModeNumberEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
187
	stream.writeByte('"')
188
	encoder.elemEncoder.Encode(ptr, stream)
189
	stream.writeByte('"')
190
}
191

192
func (encoder *stringModeNumberEncoder) IsEmpty(ptr unsafe.Pointer) bool {
193
	return encoder.elemEncoder.IsEmpty(ptr)
194
}
195

196
type stringModeStringEncoder struct {
197
	elemEncoder ValEncoder
198
	cfg         *frozenConfig
199
}
200

201
func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
202
	tempStream := encoder.cfg.BorrowStream(nil)
203
	tempStream.Attachment = stream.Attachment
204
	defer encoder.cfg.ReturnStream(tempStream)
205
	encoder.elemEncoder.Encode(ptr, tempStream)
206
	stream.WriteString(string(tempStream.Buffer()))
207
}
208

209
func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
210
	return encoder.elemEncoder.IsEmpty(ptr)
211
}
212

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.