podman
225 строк · 5.8 Кб
1package jsoniter
2
3import (
4"encoding"
5"encoding/json"
6"unsafe"
7
8"github.com/modern-go/reflect2"
9)
10
11var marshalerType = reflect2.TypeOfPtr((*json.Marshaler)(nil)).Elem()
12var unmarshalerType = reflect2.TypeOfPtr((*json.Unmarshaler)(nil)).Elem()
13var textMarshalerType = reflect2.TypeOfPtr((*encoding.TextMarshaler)(nil)).Elem()
14var textUnmarshalerType = reflect2.TypeOfPtr((*encoding.TextUnmarshaler)(nil)).Elem()
15
16func createDecoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValDecoder {
17ptrType := reflect2.PtrTo(typ)
18if ptrType.Implements(unmarshalerType) {
19return &referenceDecoder{
20&unmarshalerDecoder{ptrType},
21}
22}
23if ptrType.Implements(textUnmarshalerType) {
24return &referenceDecoder{
25&textUnmarshalerDecoder{ptrType},
26}
27}
28return nil
29}
30
31func createEncoderOfMarshaler(ctx *ctx, typ reflect2.Type) ValEncoder {
32if typ == marshalerType {
33checkIsEmpty := createCheckIsEmpty(ctx, typ)
34var encoder ValEncoder = &directMarshalerEncoder{
35checkIsEmpty: checkIsEmpty,
36}
37return encoder
38}
39if typ.Implements(marshalerType) {
40checkIsEmpty := createCheckIsEmpty(ctx, typ)
41var encoder ValEncoder = &marshalerEncoder{
42valType: typ,
43checkIsEmpty: checkIsEmpty,
44}
45return encoder
46}
47ptrType := reflect2.PtrTo(typ)
48if ctx.prefix != "" && ptrType.Implements(marshalerType) {
49checkIsEmpty := createCheckIsEmpty(ctx, ptrType)
50var encoder ValEncoder = &marshalerEncoder{
51valType: ptrType,
52checkIsEmpty: checkIsEmpty,
53}
54return &referenceEncoder{encoder}
55}
56if typ == textMarshalerType {
57checkIsEmpty := createCheckIsEmpty(ctx, typ)
58var encoder ValEncoder = &directTextMarshalerEncoder{
59checkIsEmpty: checkIsEmpty,
60stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
61}
62return encoder
63}
64if typ.Implements(textMarshalerType) {
65checkIsEmpty := createCheckIsEmpty(ctx, typ)
66var encoder ValEncoder = &textMarshalerEncoder{
67valType: typ,
68stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
69checkIsEmpty: checkIsEmpty,
70}
71return encoder
72}
73// if prefix is empty, the type is the root type
74if ctx.prefix != "" && ptrType.Implements(textMarshalerType) {
75checkIsEmpty := createCheckIsEmpty(ctx, ptrType)
76var encoder ValEncoder = &textMarshalerEncoder{
77valType: ptrType,
78stringEncoder: ctx.EncoderOf(reflect2.TypeOf("")),
79checkIsEmpty: checkIsEmpty,
80}
81return &referenceEncoder{encoder}
82}
83return nil
84}
85
86type marshalerEncoder struct {
87checkIsEmpty checkIsEmpty
88valType reflect2.Type
89}
90
91func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
92obj := encoder.valType.UnsafeIndirect(ptr)
93if encoder.valType.IsNullable() && reflect2.IsNil(obj) {
94stream.WriteNil()
95return
96}
97marshaler := obj.(json.Marshaler)
98bytes, err := marshaler.MarshalJSON()
99if err != nil {
100stream.Error = err
101} else {
102// html escape was already done by jsoniter
103// but the extra '\n' should be trimed
104l := len(bytes)
105if l > 0 && bytes[l-1] == '\n' {
106bytes = bytes[:l-1]
107}
108stream.Write(bytes)
109}
110}
111
112func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
113return encoder.checkIsEmpty.IsEmpty(ptr)
114}
115
116type directMarshalerEncoder struct {
117checkIsEmpty checkIsEmpty
118}
119
120func (encoder *directMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
121marshaler := *(*json.Marshaler)(ptr)
122if marshaler == nil {
123stream.WriteNil()
124return
125}
126bytes, err := marshaler.MarshalJSON()
127if err != nil {
128stream.Error = err
129} else {
130stream.Write(bytes)
131}
132}
133
134func (encoder *directMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
135return encoder.checkIsEmpty.IsEmpty(ptr)
136}
137
138type textMarshalerEncoder struct {
139valType reflect2.Type
140stringEncoder ValEncoder
141checkIsEmpty checkIsEmpty
142}
143
144func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
145obj := encoder.valType.UnsafeIndirect(ptr)
146if encoder.valType.IsNullable() && reflect2.IsNil(obj) {
147stream.WriteNil()
148return
149}
150marshaler := (obj).(encoding.TextMarshaler)
151bytes, err := marshaler.MarshalText()
152if err != nil {
153stream.Error = err
154} else {
155str := string(bytes)
156encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream)
157}
158}
159
160func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
161return encoder.checkIsEmpty.IsEmpty(ptr)
162}
163
164type directTextMarshalerEncoder struct {
165stringEncoder ValEncoder
166checkIsEmpty checkIsEmpty
167}
168
169func (encoder *directTextMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
170marshaler := *(*encoding.TextMarshaler)(ptr)
171if marshaler == nil {
172stream.WriteNil()
173return
174}
175bytes, err := marshaler.MarshalText()
176if err != nil {
177stream.Error = err
178} else {
179str := string(bytes)
180encoder.stringEncoder.Encode(unsafe.Pointer(&str), stream)
181}
182}
183
184func (encoder *directTextMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
185return encoder.checkIsEmpty.IsEmpty(ptr)
186}
187
188type unmarshalerDecoder struct {
189valType reflect2.Type
190}
191
192func (decoder *unmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
193valType := decoder.valType
194obj := valType.UnsafeIndirect(ptr)
195unmarshaler := obj.(json.Unmarshaler)
196iter.nextToken()
197iter.unreadByte() // skip spaces
198bytes := iter.SkipAndReturnBytes()
199err := unmarshaler.UnmarshalJSON(bytes)
200if err != nil {
201iter.ReportError("unmarshalerDecoder", err.Error())
202}
203}
204
205type textUnmarshalerDecoder struct {
206valType reflect2.Type
207}
208
209func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
210valType := decoder.valType
211obj := valType.UnsafeIndirect(ptr)
212if reflect2.IsNil(obj) {
213ptrType := valType.(*reflect2.UnsafePtrType)
214elemType := ptrType.Elem()
215elem := elemType.UnsafeNew()
216ptrType.UnsafeSet(ptr, unsafe.Pointer(&elem))
217obj = valType.UnsafeIndirect(ptr)
218}
219unmarshaler := (obj).(encoding.TextUnmarshaler)
220str := iter.ReadString()
221err := unmarshaler.UnmarshalText([]byte(str))
222if err != nil {
223iter.ReportError("textUnmarshalerDecoder", err.Error())
224}
225}
226