blob: 2adcdc3b790e53e4192655b15680a596a52449dd [file] [log] [blame]
khenaidoo59ce9dd2019-11-11 13:05:32 -05001package jsoniter
2
3import (
4 "encoding/json"
5 "io"
6 "reflect"
7 "sync"
8 "unsafe"
9
10 "github.com/modern-go/concurrent"
11 "github.com/modern-go/reflect2"
12)
13
14// Config customize how the API should behave.
15// The API is created from Config by Froze.
16type Config struct {
17 IndentionStep int
18 MarshalFloatWith6Digits bool
19 EscapeHTML bool
20 SortMapKeys bool
21 UseNumber bool
22 DisallowUnknownFields bool
23 TagKey string
24 OnlyTaggedField bool
25 ValidateJsonRawMessage bool
26 ObjectFieldMustBeSimpleString bool
27 CaseSensitive bool
28}
29
30// API the public interface of this package.
31// Primary Marshal and Unmarshal.
32type API interface {
33 IteratorPool
34 StreamPool
35 MarshalToString(v interface{}) (string, error)
36 Marshal(v interface{}) ([]byte, error)
37 MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
38 UnmarshalFromString(str string, v interface{}) error
39 Unmarshal(data []byte, v interface{}) error
40 Get(data []byte, path ...interface{}) Any
41 NewEncoder(writer io.Writer) *Encoder
42 NewDecoder(reader io.Reader) *Decoder
43 Valid(data []byte) bool
44 RegisterExtension(extension Extension)
45 DecoderOf(typ reflect2.Type) ValDecoder
46 EncoderOf(typ reflect2.Type) ValEncoder
47}
48
49// ConfigDefault the default API
50var ConfigDefault = Config{
51 EscapeHTML: true,
52}.Froze()
53
54// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior
55var ConfigCompatibleWithStandardLibrary = Config{
56 EscapeHTML: true,
57 SortMapKeys: true,
58 ValidateJsonRawMessage: true,
59}.Froze()
60
61// ConfigFastest marshals float with only 6 digits precision
62var ConfigFastest = Config{
63 EscapeHTML: false,
64 MarshalFloatWith6Digits: true, // will lose precession
65 ObjectFieldMustBeSimpleString: true, // do not unescape object field
66}.Froze()
67
68type frozenConfig struct {
69 configBeforeFrozen Config
70 sortMapKeys bool
71 indentionStep int
72 objectFieldMustBeSimpleString bool
73 onlyTaggedField bool
74 disallowUnknownFields bool
75 decoderCache *concurrent.Map
76 encoderCache *concurrent.Map
77 encoderExtension Extension
78 decoderExtension Extension
79 extraExtensions []Extension
80 streamPool *sync.Pool
81 iteratorPool *sync.Pool
82 caseSensitive bool
83}
84
85func (cfg *frozenConfig) initCache() {
86 cfg.decoderCache = concurrent.NewMap()
87 cfg.encoderCache = concurrent.NewMap()
88}
89
90func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) {
91 cfg.decoderCache.Store(cacheKey, decoder)
92}
93
94func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) {
95 cfg.encoderCache.Store(cacheKey, encoder)
96}
97
98func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder {
99 decoder, found := cfg.decoderCache.Load(cacheKey)
100 if found {
101 return decoder.(ValDecoder)
102 }
103 return nil
104}
105
106func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder {
107 encoder, found := cfg.encoderCache.Load(cacheKey)
108 if found {
109 return encoder.(ValEncoder)
110 }
111 return nil
112}
113
114var cfgCache = concurrent.NewMap()
115
116func getFrozenConfigFromCache(cfg Config) *frozenConfig {
117 obj, found := cfgCache.Load(cfg)
118 if found {
119 return obj.(*frozenConfig)
120 }
121 return nil
122}
123
124func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) {
125 cfgCache.Store(cfg, frozenConfig)
126}
127
128// Froze forge API from config
129func (cfg Config) Froze() API {
130 api := &frozenConfig{
131 sortMapKeys: cfg.SortMapKeys,
132 indentionStep: cfg.IndentionStep,
133 objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString,
134 onlyTaggedField: cfg.OnlyTaggedField,
135 disallowUnknownFields: cfg.DisallowUnknownFields,
136 caseSensitive: cfg.CaseSensitive,
137 }
138 api.streamPool = &sync.Pool{
139 New: func() interface{} {
140 return NewStream(api, nil, 512)
141 },
142 }
143 api.iteratorPool = &sync.Pool{
144 New: func() interface{} {
145 return NewIterator(api)
146 },
147 }
148 api.initCache()
149 encoderExtension := EncoderExtension{}
150 decoderExtension := DecoderExtension{}
151 if cfg.MarshalFloatWith6Digits {
152 api.marshalFloatWith6Digits(encoderExtension)
153 }
154 if cfg.EscapeHTML {
155 api.escapeHTML(encoderExtension)
156 }
157 if cfg.UseNumber {
158 api.useNumber(decoderExtension)
159 }
160 if cfg.ValidateJsonRawMessage {
161 api.validateJsonRawMessage(encoderExtension)
162 }
163 api.encoderExtension = encoderExtension
164 api.decoderExtension = decoderExtension
165 api.configBeforeFrozen = cfg
166 return api
167}
168
169func (cfg Config) frozeWithCacheReuse(extraExtensions []Extension) *frozenConfig {
170 api := getFrozenConfigFromCache(cfg)
171 if api != nil {
172 return api
173 }
174 api = cfg.Froze().(*frozenConfig)
175 for _, extension := range extraExtensions {
176 api.RegisterExtension(extension)
177 }
178 addFrozenConfigToCache(cfg, api)
179 return api
180}
181
182func (cfg *frozenConfig) validateJsonRawMessage(extension EncoderExtension) {
183 encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) {
184 rawMessage := *(*json.RawMessage)(ptr)
185 iter := cfg.BorrowIterator([]byte(rawMessage))
khenaidoo26721882021-08-11 17:42:52 -0400186 defer cfg.ReturnIterator(iter)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500187 iter.Read()
khenaidoo26721882021-08-11 17:42:52 -0400188 if iter.Error != nil && iter.Error != io.EOF {
khenaidoo59ce9dd2019-11-11 13:05:32 -0500189 stream.WriteRaw("null")
190 } else {
khenaidoo59ce9dd2019-11-11 13:05:32 -0500191 stream.WriteRaw(string(rawMessage))
192 }
193 }, func(ptr unsafe.Pointer) bool {
194 return len(*((*json.RawMessage)(ptr))) == 0
195 }}
196 extension[reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()] = encoder
197 extension[reflect2.TypeOfPtr((*RawMessage)(nil)).Elem()] = encoder
198}
199
200func (cfg *frozenConfig) useNumber(extension DecoderExtension) {
201 extension[reflect2.TypeOfPtr((*interface{})(nil)).Elem()] = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) {
202 exitingValue := *((*interface{})(ptr))
203 if exitingValue != nil && reflect.TypeOf(exitingValue).Kind() == reflect.Ptr {
204 iter.ReadVal(exitingValue)
205 return
206 }
207 if iter.WhatIsNext() == NumberValue {
208 *((*interface{})(ptr)) = json.Number(iter.readNumberAsString())
209 } else {
210 *((*interface{})(ptr)) = iter.Read()
211 }
212 }}
213}
214func (cfg *frozenConfig) getTagKey() string {
215 tagKey := cfg.configBeforeFrozen.TagKey
216 if tagKey == "" {
217 return "json"
218 }
219 return tagKey
220}
221
222func (cfg *frozenConfig) RegisterExtension(extension Extension) {
223 cfg.extraExtensions = append(cfg.extraExtensions, extension)
224 copied := cfg.configBeforeFrozen
225 cfg.configBeforeFrozen = copied
226}
227
228type lossyFloat32Encoder struct {
229}
230
231func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
232 stream.WriteFloat32Lossy(*((*float32)(ptr)))
233}
234
235func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool {
236 return *((*float32)(ptr)) == 0
237}
238
239type lossyFloat64Encoder struct {
240}
241
242func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
243 stream.WriteFloat64Lossy(*((*float64)(ptr)))
244}
245
246func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool {
247 return *((*float64)(ptr)) == 0
248}
249
250// EnableLossyFloatMarshalling keeps 10**(-6) precision
251// for float variables for better performance.
252func (cfg *frozenConfig) marshalFloatWith6Digits(extension EncoderExtension) {
253 // for better performance
254 extension[reflect2.TypeOfPtr((*float32)(nil)).Elem()] = &lossyFloat32Encoder{}
255 extension[reflect2.TypeOfPtr((*float64)(nil)).Elem()] = &lossyFloat64Encoder{}
256}
257
258type htmlEscapedStringEncoder struct {
259}
260
261func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
262 str := *((*string)(ptr))
263 stream.WriteStringWithHTMLEscaped(str)
264}
265
266func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
267 return *((*string)(ptr)) == ""
268}
269
270func (cfg *frozenConfig) escapeHTML(encoderExtension EncoderExtension) {
271 encoderExtension[reflect2.TypeOfPtr((*string)(nil)).Elem()] = &htmlEscapedStringEncoder{}
272}
273
274func (cfg *frozenConfig) cleanDecoders() {
275 typeDecoders = map[string]ValDecoder{}
276 fieldDecoders = map[string]ValDecoder{}
277 *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
278}
279
280func (cfg *frozenConfig) cleanEncoders() {
281 typeEncoders = map[string]ValEncoder{}
282 fieldEncoders = map[string]ValEncoder{}
283 *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
284}
285
286func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) {
287 stream := cfg.BorrowStream(nil)
288 defer cfg.ReturnStream(stream)
289 stream.WriteVal(v)
290 if stream.Error != nil {
291 return "", stream.Error
292 }
293 return string(stream.Buffer()), nil
294}
295
296func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) {
297 stream := cfg.BorrowStream(nil)
298 defer cfg.ReturnStream(stream)
299 stream.WriteVal(v)
300 if stream.Error != nil {
301 return nil, stream.Error
302 }
303 result := stream.Buffer()
304 copied := make([]byte, len(result))
305 copy(copied, result)
306 return copied, nil
307}
308
309func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
310 if prefix != "" {
311 panic("prefix is not supported")
312 }
313 for _, r := range indent {
314 if r != ' ' {
315 panic("indent can only be space")
316 }
317 }
318 newCfg := cfg.configBeforeFrozen
319 newCfg.IndentionStep = len(indent)
320 return newCfg.frozeWithCacheReuse(cfg.extraExtensions).Marshal(v)
321}
322
323func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error {
324 data := []byte(str)
325 iter := cfg.BorrowIterator(data)
326 defer cfg.ReturnIterator(iter)
327 iter.ReadVal(v)
328 c := iter.nextToken()
329 if c == 0 {
330 if iter.Error == io.EOF {
331 return nil
332 }
333 return iter.Error
334 }
335 iter.ReportError("Unmarshal", "there are bytes left after unmarshal")
336 return iter.Error
337}
338
339func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any {
340 iter := cfg.BorrowIterator(data)
341 defer cfg.ReturnIterator(iter)
342 return locatePath(iter, path)
343}
344
345func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error {
346 iter := cfg.BorrowIterator(data)
347 defer cfg.ReturnIterator(iter)
348 iter.ReadVal(v)
349 c := iter.nextToken()
350 if c == 0 {
351 if iter.Error == io.EOF {
352 return nil
353 }
354 return iter.Error
355 }
356 iter.ReportError("Unmarshal", "there are bytes left after unmarshal")
357 return iter.Error
358}
359
360func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder {
361 stream := NewStream(cfg, writer, 512)
362 return &Encoder{stream}
363}
364
365func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder {
366 iter := Parse(cfg, reader, 512)
367 return &Decoder{iter}
368}
369
370func (cfg *frozenConfig) Valid(data []byte) bool {
371 iter := cfg.BorrowIterator(data)
372 defer cfg.ReturnIterator(iter)
373 iter.Skip()
374 return iter.Error == nil
375}