1package 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))
186		defer cfg.ReturnIterator(iter)
187		iter.Read()
188		if iter.Error != nil && iter.Error != io.EOF {
189			stream.WriteRaw("null")
190		} else {
191			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}
376