1package jsoniter
2
3import (
4	"encoding/json"
5	"errors"
6	"io"
7	"reflect"
8	"sync/atomic"
9	"unsafe"
10)
11
12// Config customize how the API should behave.
13// The API is created from Config by Froze.
14type Config struct {
15	IndentionStep           int
16	MarshalFloatWith6Digits bool
17	EscapeHTML              bool
18	SortMapKeys             bool
19	UseNumber               bool
20	TagKey                  string
21}
22
23type frozenConfig struct {
24	configBeforeFrozen Config
25	sortMapKeys        bool
26	indentionStep      int
27	decoderCache       unsafe.Pointer
28	encoderCache       unsafe.Pointer
29	extensions         []Extension
30	streamPool         chan *Stream
31	iteratorPool       chan *Iterator
32}
33
34// API the public interface of this package.
35// Primary Marshal and Unmarshal.
36type API interface {
37	IteratorPool
38	StreamPool
39	MarshalToString(v interface{}) (string, error)
40	Marshal(v interface{}) ([]byte, error)
41	MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
42	UnmarshalFromString(str string, v interface{}) error
43	Unmarshal(data []byte, v interface{}) error
44	Get(data []byte, path ...interface{}) Any
45	NewEncoder(writer io.Writer) *Encoder
46	NewDecoder(reader io.Reader) *Decoder
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}.Froze()
59
60// ConfigFastest marshals float with only 6 digits precision
61var ConfigFastest = Config{
62	EscapeHTML:              false,
63	MarshalFloatWith6Digits: true,
64}.Froze()
65
66// Froze forge API from config
67func (cfg Config) Froze() API {
68	// TODO: cache frozen config
69	frozenConfig := &frozenConfig{
70		sortMapKeys:   cfg.SortMapKeys,
71		indentionStep: cfg.IndentionStep,
72		streamPool:    make(chan *Stream, 16),
73		iteratorPool:  make(chan *Iterator, 16),
74	}
75	atomic.StorePointer(&frozenConfig.decoderCache, unsafe.Pointer(&map[string]ValDecoder{}))
76	atomic.StorePointer(&frozenConfig.encoderCache, unsafe.Pointer(&map[string]ValEncoder{}))
77	if cfg.MarshalFloatWith6Digits {
78		frozenConfig.marshalFloatWith6Digits()
79	}
80	if cfg.EscapeHTML {
81		frozenConfig.escapeHTML()
82	}
83	if cfg.UseNumber {
84		frozenConfig.useNumber()
85	}
86	frozenConfig.configBeforeFrozen = cfg
87	return frozenConfig
88}
89
90func (cfg *frozenConfig) useNumber() {
91	cfg.addDecoderToCache(reflect.TypeOf((*interface{})(nil)).Elem(), &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) {
92		if iter.WhatIsNext() == NumberValue {
93			*((*interface{})(ptr)) = json.Number(iter.readNumberAsString())
94		} else {
95			*((*interface{})(ptr)) = iter.Read()
96		}
97	}})
98}
99func (cfg *frozenConfig) getTagKey() string {
100	tagKey := cfg.configBeforeFrozen.TagKey
101	if tagKey == "" {
102		return "json"
103	}
104	return tagKey
105}
106
107func (cfg *frozenConfig) registerExtension(extension Extension) {
108	cfg.extensions = append(cfg.extensions, extension)
109}
110
111type lossyFloat32Encoder struct {
112}
113
114func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
115	stream.WriteFloat32Lossy(*((*float32)(ptr)))
116}
117
118func (encoder *lossyFloat32Encoder) EncodeInterface(val interface{}, stream *Stream) {
119	WriteToStream(val, stream, encoder)
120}
121
122func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool {
123	return *((*float32)(ptr)) == 0
124}
125
126type lossyFloat64Encoder struct {
127}
128
129func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
130	stream.WriteFloat64Lossy(*((*float64)(ptr)))
131}
132
133func (encoder *lossyFloat64Encoder) EncodeInterface(val interface{}, stream *Stream) {
134	WriteToStream(val, stream, encoder)
135}
136
137func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool {
138	return *((*float64)(ptr)) == 0
139}
140
141// EnableLossyFloatMarshalling keeps 10**(-6) precision
142// for float variables for better performance.
143func (cfg *frozenConfig) marshalFloatWith6Digits() {
144	// for better performance
145	cfg.addEncoderToCache(reflect.TypeOf((*float32)(nil)).Elem(), &lossyFloat32Encoder{})
146	cfg.addEncoderToCache(reflect.TypeOf((*float64)(nil)).Elem(), &lossyFloat64Encoder{})
147}
148
149type htmlEscapedStringEncoder struct {
150}
151
152func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
153	str := *((*string)(ptr))
154	stream.WriteStringWithHTMLEscaped(str)
155}
156
157func (encoder *htmlEscapedStringEncoder) EncodeInterface(val interface{}, stream *Stream) {
158	WriteToStream(val, stream, encoder)
159}
160
161func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
162	return *((*string)(ptr)) == ""
163}
164
165func (cfg *frozenConfig) escapeHTML() {
166	cfg.addEncoderToCache(reflect.TypeOf((*string)(nil)).Elem(), &htmlEscapedStringEncoder{})
167}
168
169func (cfg *frozenConfig) addDecoderToCache(cacheKey reflect.Type, decoder ValDecoder) {
170	done := false
171	for !done {
172		ptr := atomic.LoadPointer(&cfg.decoderCache)
173		cache := *(*map[reflect.Type]ValDecoder)(ptr)
174		copied := map[reflect.Type]ValDecoder{}
175		for k, v := range cache {
176			copied[k] = v
177		}
178		copied[cacheKey] = decoder
179		done = atomic.CompareAndSwapPointer(&cfg.decoderCache, ptr, unsafe.Pointer(&copied))
180	}
181}
182
183func (cfg *frozenConfig) addEncoderToCache(cacheKey reflect.Type, encoder ValEncoder) {
184	done := false
185	for !done {
186		ptr := atomic.LoadPointer(&cfg.encoderCache)
187		cache := *(*map[reflect.Type]ValEncoder)(ptr)
188		copied := map[reflect.Type]ValEncoder{}
189		for k, v := range cache {
190			copied[k] = v
191		}
192		copied[cacheKey] = encoder
193		done = atomic.CompareAndSwapPointer(&cfg.encoderCache, ptr, unsafe.Pointer(&copied))
194	}
195}
196
197func (cfg *frozenConfig) getDecoderFromCache(cacheKey reflect.Type) ValDecoder {
198	ptr := atomic.LoadPointer(&cfg.decoderCache)
199	cache := *(*map[reflect.Type]ValDecoder)(ptr)
200	return cache[cacheKey]
201}
202
203func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) ValEncoder {
204	ptr := atomic.LoadPointer(&cfg.encoderCache)
205	cache := *(*map[reflect.Type]ValEncoder)(ptr)
206	return cache[cacheKey]
207}
208
209func (cfg *frozenConfig) cleanDecoders() {
210	typeDecoders = map[string]ValDecoder{}
211	fieldDecoders = map[string]ValDecoder{}
212	*cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
213}
214
215func (cfg *frozenConfig) cleanEncoders() {
216	typeEncoders = map[string]ValEncoder{}
217	fieldEncoders = map[string]ValEncoder{}
218	*cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
219}
220
221func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) {
222	stream := cfg.BorrowStream(nil)
223	defer cfg.ReturnStream(stream)
224	stream.WriteVal(v)
225	if stream.Error != nil {
226		return "", stream.Error
227	}
228	return string(stream.Buffer()), nil
229}
230
231func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) {
232	stream := cfg.BorrowStream(nil)
233	defer cfg.ReturnStream(stream)
234	stream.WriteVal(v)
235	if stream.Error != nil {
236		return nil, stream.Error
237	}
238	result := stream.Buffer()
239	copied := make([]byte, len(result))
240	copy(copied, result)
241	return copied, nil
242}
243
244func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
245	if prefix != "" {
246		panic("prefix is not supported")
247	}
248	for _, r := range indent {
249		if r != ' ' {
250			panic("indent can only be space")
251		}
252	}
253	newCfg := cfg.configBeforeFrozen
254	newCfg.IndentionStep = len(indent)
255	return newCfg.Froze().Marshal(v)
256}
257
258func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error {
259	data := []byte(str)
260	data = data[:lastNotSpacePos(data)]
261	iter := cfg.BorrowIterator(data)
262	defer cfg.ReturnIterator(iter)
263	iter.ReadVal(v)
264	if iter.head == iter.tail {
265		iter.loadMore()
266	}
267	if iter.Error == io.EOF {
268		return nil
269	}
270	if iter.Error == nil {
271		iter.ReportError("UnmarshalFromString", "there are bytes left after unmarshal")
272	}
273	return iter.Error
274}
275
276func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any {
277	iter := cfg.BorrowIterator(data)
278	defer cfg.ReturnIterator(iter)
279	return locatePath(iter, path)
280}
281
282func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error {
283	data = data[:lastNotSpacePos(data)]
284	iter := cfg.BorrowIterator(data)
285	defer cfg.ReturnIterator(iter)
286	typ := reflect.TypeOf(v)
287	if typ.Kind() != reflect.Ptr {
288		// return non-pointer error
289		return errors.New("the second param must be ptr type")
290	}
291	iter.ReadVal(v)
292	if iter.head == iter.tail {
293		iter.loadMore()
294	}
295	if iter.Error == io.EOF {
296		return nil
297	}
298	if iter.Error == nil {
299		iter.ReportError("Unmarshal", "there are bytes left after unmarshal")
300	}
301	return iter.Error
302}
303
304func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder {
305	stream := NewStream(cfg, writer, 512)
306	return &Encoder{stream}
307}
308
309func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder {
310	iter := Parse(cfg, reader, 512)
311	return &Decoder{iter}
312}
313