blob: 835819129c551d28ec73492ac74b7dbc3665355a [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001package 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 extensions []Extension
78 streamPool *sync.Pool
79 iteratorPool *sync.Pool
80 caseSensitive bool
81}
82
83func (cfg *frozenConfig) initCache() {
84 cfg.decoderCache = concurrent.NewMap()
85 cfg.encoderCache = concurrent.NewMap()
86}
87
88func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) {
89 cfg.decoderCache.Store(cacheKey, decoder)
90}
91
92func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) {
93 cfg.encoderCache.Store(cacheKey, encoder)
94}
95
96func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder {
97 decoder, found := cfg.decoderCache.Load(cacheKey)
98 if found {
99 return decoder.(ValDecoder)
100 }
101 return nil
102}
103
104func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder {
105 encoder, found := cfg.encoderCache.Load(cacheKey)
106 if found {
107 return encoder.(ValEncoder)
108 }
109 return nil
110}
111
112var cfgCache = concurrent.NewMap()
113
114func getFrozenConfigFromCache(cfg Config) *frozenConfig {
115 obj, found := cfgCache.Load(cfg)
116 if found {
117 return obj.(*frozenConfig)
118 }
119 return nil
120}
121
122func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) {
123 cfgCache.Store(cfg, frozenConfig)
124}
125
126// Froze forge API from config
127func (cfg Config) Froze() API {
128 api := &frozenConfig{
129 sortMapKeys: cfg.SortMapKeys,
130 indentionStep: cfg.IndentionStep,
131 objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString,
132 onlyTaggedField: cfg.OnlyTaggedField,
133 disallowUnknownFields: cfg.DisallowUnknownFields,
134 caseSensitive: cfg.CaseSensitive,
135 }
136 api.streamPool = &sync.Pool{
137 New: func() interface{} {
138 return NewStream(api, nil, 512)
139 },
140 }
141 api.iteratorPool = &sync.Pool{
142 New: func() interface{} {
143 return NewIterator(api)
144 },
145 }
146 api.initCache()
147 encoderExtension := EncoderExtension{}
148 decoderExtension := DecoderExtension{}
149 if cfg.MarshalFloatWith6Digits {
150 api.marshalFloatWith6Digits(encoderExtension)
151 }
152 if cfg.EscapeHTML {
153 api.escapeHTML(encoderExtension)
154 }
155 if cfg.UseNumber {
156 api.useNumber(decoderExtension)
157 }
158 if cfg.ValidateJsonRawMessage {
159 api.validateJsonRawMessage(encoderExtension)
160 }
161 if len(encoderExtension) > 0 {
162 api.extensions = append(api.extensions, encoderExtension)
163 }
164 if len(decoderExtension) > 0 {
165 api.extensions = append(api.extensions, decoderExtension)
166 }
167 api.configBeforeFrozen = cfg
168 return api
169}
170
171func (cfg Config) frozeWithCacheReuse() *frozenConfig {
172 api := getFrozenConfigFromCache(cfg)
173 if api != nil {
174 return api
175 }
176 api = cfg.Froze().(*frozenConfig)
177 addFrozenConfigToCache(cfg, api)
178 return api
179}
180
181func (cfg *frozenConfig) validateJsonRawMessage(extension EncoderExtension) {
182 encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) {
183 rawMessage := *(*json.RawMessage)(ptr)
184 iter := cfg.BorrowIterator([]byte(rawMessage))
185 iter.Read()
186 if iter.Error != nil {
187 stream.WriteRaw("null")
188 } else {
189 cfg.ReturnIterator(iter)
190 stream.WriteRaw(string(rawMessage))
191 }
192 }, func(ptr unsafe.Pointer) bool {
193 return false
194 }}
195 extension[reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()] = encoder
196 extension[reflect2.TypeOfPtr((*RawMessage)(nil)).Elem()] = encoder
197}
198
199func (cfg *frozenConfig) useNumber(extension DecoderExtension) {
200 extension[reflect2.TypeOfPtr((*interface{})(nil)).Elem()] = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) {
201 exitingValue := *((*interface{})(ptr))
202 if exitingValue != nil && reflect.TypeOf(exitingValue).Kind() == reflect.Ptr {
203 iter.ReadVal(exitingValue)
204 return
205 }
206 if iter.WhatIsNext() == NumberValue {
207 *((*interface{})(ptr)) = json.Number(iter.readNumberAsString())
208 } else {
209 *((*interface{})(ptr)) = iter.Read()
210 }
211 }}
212}
213func (cfg *frozenConfig) getTagKey() string {
214 tagKey := cfg.configBeforeFrozen.TagKey
215 if tagKey == "" {
216 return "json"
217 }
218 return tagKey
219}
220
221func (cfg *frozenConfig) RegisterExtension(extension Extension) {
222 cfg.extensions = append(cfg.extensions, extension)
223}
224
225type lossyFloat32Encoder struct {
226}
227
228func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
229 stream.WriteFloat32Lossy(*((*float32)(ptr)))
230}
231
232func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool {
233 return *((*float32)(ptr)) == 0
234}
235
236type lossyFloat64Encoder struct {
237}
238
239func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
240 stream.WriteFloat64Lossy(*((*float64)(ptr)))
241}
242
243func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool {
244 return *((*float64)(ptr)) == 0
245}
246
247// EnableLossyFloatMarshalling keeps 10**(-6) precision
248// for float variables for better performance.
249func (cfg *frozenConfig) marshalFloatWith6Digits(extension EncoderExtension) {
250 // for better performance
251 extension[reflect2.TypeOfPtr((*float32)(nil)).Elem()] = &lossyFloat32Encoder{}
252 extension[reflect2.TypeOfPtr((*float64)(nil)).Elem()] = &lossyFloat64Encoder{}
253}
254
255type htmlEscapedStringEncoder struct {
256}
257
258func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
259 str := *((*string)(ptr))
260 stream.WriteStringWithHTMLEscaped(str)
261}
262
263func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
264 return *((*string)(ptr)) == ""
265}
266
267func (cfg *frozenConfig) escapeHTML(encoderExtension EncoderExtension) {
268 encoderExtension[reflect2.TypeOfPtr((*string)(nil)).Elem()] = &htmlEscapedStringEncoder{}
269}
270
271func (cfg *frozenConfig) cleanDecoders() {
272 typeDecoders = map[string]ValDecoder{}
273 fieldDecoders = map[string]ValDecoder{}
274 *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
275}
276
277func (cfg *frozenConfig) cleanEncoders() {
278 typeEncoders = map[string]ValEncoder{}
279 fieldEncoders = map[string]ValEncoder{}
280 *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
281}
282
283func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) {
284 stream := cfg.BorrowStream(nil)
285 defer cfg.ReturnStream(stream)
286 stream.WriteVal(v)
287 if stream.Error != nil {
288 return "", stream.Error
289 }
290 return string(stream.Buffer()), nil
291}
292
293func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) {
294 stream := cfg.BorrowStream(nil)
295 defer cfg.ReturnStream(stream)
296 stream.WriteVal(v)
297 if stream.Error != nil {
298 return nil, stream.Error
299 }
300 result := stream.Buffer()
301 copied := make([]byte, len(result))
302 copy(copied, result)
303 return copied, nil
304}
305
306func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
307 if prefix != "" {
308 panic("prefix is not supported")
309 }
310 for _, r := range indent {
311 if r != ' ' {
312 panic("indent can only be space")
313 }
314 }
315 newCfg := cfg.configBeforeFrozen
316 newCfg.IndentionStep = len(indent)
317 return newCfg.frozeWithCacheReuse().Marshal(v)
318}
319
320func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error {
321 data := []byte(str)
322 iter := cfg.BorrowIterator(data)
323 defer cfg.ReturnIterator(iter)
324 iter.ReadVal(v)
325 c := iter.nextToken()
326 if c == 0 {
327 if iter.Error == io.EOF {
328 return nil
329 }
330 return iter.Error
331 }
332 iter.ReportError("Unmarshal", "there are bytes left after unmarshal")
333 return iter.Error
334}
335
336func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any {
337 iter := cfg.BorrowIterator(data)
338 defer cfg.ReturnIterator(iter)
339 return locatePath(iter, path)
340}
341
342func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error {
343 iter := cfg.BorrowIterator(data)
344 defer cfg.ReturnIterator(iter)
345 iter.ReadVal(v)
346 c := iter.nextToken()
347 if c == 0 {
348 if iter.Error == io.EOF {
349 return nil
350 }
351 return iter.Error
352 }
353 iter.ReportError("Unmarshal", "there are bytes left after unmarshal")
354 return iter.Error
355}
356
357func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder {
358 stream := NewStream(cfg, writer, 512)
359 return &Encoder{stream}
360}
361
362func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder {
363 iter := Parse(cfg, reader, 512)
364 return &Decoder{iter}
365}
366
367func (cfg *frozenConfig) Valid(data []byte) bool {
368 iter := cfg.BorrowIterator(data)
369 defer cfg.ReturnIterator(iter)
370 iter.Skip()
371 return iter.Error == nil
372}