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