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