10 "github.com/modern-go/concurrent"
11 "github.com/modern-go/reflect2"
14 // Config customize how the API should behave.
15 // The API is created from Config by Froze.
18 MarshalFloatWith6Digits bool
22 DisallowUnknownFields bool
25 ValidateJsonRawMessage bool
26 ObjectFieldMustBeSimpleString bool
30 // API the public interface of this package.
31 // Primary Marshal and Unmarshal.
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
49 // ConfigDefault the default API
50 var ConfigDefault = Config{
54 // ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior
55 var ConfigCompatibleWithStandardLibrary = Config{
58 ValidateJsonRawMessage: true,
61 // ConfigFastest marshals float with only 6 digits precision
62 var ConfigFastest = Config{
64 MarshalFloatWith6Digits: true, // will lose precession
65 ObjectFieldMustBeSimpleString: true, // do not unescape object field
68 type frozenConfig struct {
69 configBeforeFrozen Config
72 objectFieldMustBeSimpleString bool
74 disallowUnknownFields bool
75 decoderCache *concurrent.Map
76 encoderCache *concurrent.Map
77 encoderExtension Extension
78 decoderExtension Extension
79 extraExtensions []Extension
81 iteratorPool *sync.Pool
85 func (cfg *frozenConfig) initCache() {
86 cfg.decoderCache = concurrent.NewMap()
87 cfg.encoderCache = concurrent.NewMap()
90 func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) {
91 cfg.decoderCache.Store(cacheKey, decoder)
94 func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) {
95 cfg.encoderCache.Store(cacheKey, encoder)
98 func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder {
99 decoder, found := cfg.decoderCache.Load(cacheKey)
101 return decoder.(ValDecoder)
106 func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder {
107 encoder, found := cfg.encoderCache.Load(cacheKey)
109 return encoder.(ValEncoder)
114 var cfgCache = concurrent.NewMap()
116 func getFrozenConfigFromCache(cfg Config) *frozenConfig {
117 obj, found := cfgCache.Load(cfg)
119 return obj.(*frozenConfig)
124 func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) {
125 cfgCache.Store(cfg, frozenConfig)
128 // Froze forge API from config
129 func (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,
138 api.streamPool = &sync.Pool{
139 New: func() interface{} {
140 return NewStream(api, nil, 512)
143 api.iteratorPool = &sync.Pool{
144 New: func() interface{} {
145 return NewIterator(api)
149 encoderExtension := EncoderExtension{}
150 decoderExtension := DecoderExtension{}
151 if cfg.MarshalFloatWith6Digits {
152 api.marshalFloatWith6Digits(encoderExtension)
155 api.escapeHTML(encoderExtension)
158 api.useNumber(decoderExtension)
160 if cfg.ValidateJsonRawMessage {
161 api.validateJsonRawMessage(encoderExtension)
163 api.encoderExtension = encoderExtension
164 api.decoderExtension = decoderExtension
165 api.configBeforeFrozen = cfg
169 func (cfg Config) frozeWithCacheReuse(extraExtensions []Extension) *frozenConfig {
170 api := getFrozenConfigFromCache(cfg)
174 api = cfg.Froze().(*frozenConfig)
175 for _, extension := range extraExtensions {
176 api.RegisterExtension(extension)
178 addFrozenConfigToCache(cfg, api)
182 func (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))
187 if iter.Error != nil {
188 stream.WriteRaw("null")
190 cfg.ReturnIterator(iter)
191 stream.WriteRaw(string(rawMessage))
193 }, func(ptr unsafe.Pointer) bool {
194 return len(*((*json.RawMessage)(ptr))) == 0
196 extension[reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()] = encoder
197 extension[reflect2.TypeOfPtr((*RawMessage)(nil)).Elem()] = encoder
200 func (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)
207 if iter.WhatIsNext() == NumberValue {
208 *((*interface{})(ptr)) = json.Number(iter.readNumberAsString())
210 *((*interface{})(ptr)) = iter.Read()
214 func (cfg *frozenConfig) getTagKey() string {
215 tagKey := cfg.configBeforeFrozen.TagKey
222 func (cfg *frozenConfig) RegisterExtension(extension Extension) {
223 cfg.extraExtensions = append(cfg.extraExtensions, extension)
224 copied := cfg.configBeforeFrozen
225 cfg.configBeforeFrozen = copied
228 type lossyFloat32Encoder struct {
231 func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
232 stream.WriteFloat32Lossy(*((*float32)(ptr)))
235 func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool {
236 return *((*float32)(ptr)) == 0
239 type lossyFloat64Encoder struct {
242 func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
243 stream.WriteFloat64Lossy(*((*float64)(ptr)))
246 func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool {
247 return *((*float64)(ptr)) == 0
250 // EnableLossyFloatMarshalling keeps 10**(-6) precision
251 // for float variables for better performance.
252 func (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{}
258 type htmlEscapedStringEncoder struct {
261 func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
262 str := *((*string)(ptr))
263 stream.WriteStringWithHTMLEscaped(str)
266 func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
267 return *((*string)(ptr)) == ""
270 func (cfg *frozenConfig) escapeHTML(encoderExtension EncoderExtension) {
271 encoderExtension[reflect2.TypeOfPtr((*string)(nil)).Elem()] = &htmlEscapedStringEncoder{}
274 func (cfg *frozenConfig) cleanDecoders() {
275 typeDecoders = map[string]ValDecoder{}
276 fieldDecoders = map[string]ValDecoder{}
277 *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
280 func (cfg *frozenConfig) cleanEncoders() {
281 typeEncoders = map[string]ValEncoder{}
282 fieldEncoders = map[string]ValEncoder{}
283 *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
286 func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) {
287 stream := cfg.BorrowStream(nil)
288 defer cfg.ReturnStream(stream)
290 if stream.Error != nil {
291 return "", stream.Error
293 return string(stream.Buffer()), nil
296 func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) {
297 stream := cfg.BorrowStream(nil)
298 defer cfg.ReturnStream(stream)
300 if stream.Error != nil {
301 return nil, stream.Error
303 result := stream.Buffer()
304 copied := make([]byte, len(result))
309 func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
311 panic("prefix is not supported")
313 for _, r := range indent {
315 panic("indent can only be space")
318 newCfg := cfg.configBeforeFrozen
319 newCfg.IndentionStep = len(indent)
320 return newCfg.frozeWithCacheReuse(cfg.extraExtensions).Marshal(v)
323 func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error {
325 iter := cfg.BorrowIterator(data)
326 defer cfg.ReturnIterator(iter)
328 c := iter.nextToken()
330 if iter.Error == io.EOF {
335 iter.ReportError("Unmarshal", "there are bytes left after unmarshal")
339 func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any {
340 iter := cfg.BorrowIterator(data)
341 defer cfg.ReturnIterator(iter)
342 return locatePath(iter, path)
345 func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error {
346 iter := cfg.BorrowIterator(data)
347 defer cfg.ReturnIterator(iter)
349 c := iter.nextToken()
351 if iter.Error == io.EOF {
356 iter.ReportError("Unmarshal", "there are bytes left after unmarshal")
360 func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder {
361 stream := NewStream(cfg, writer, 512)
362 return &Encoder{stream}
365 func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder {
366 iter := Parse(cfg, reader, 512)
367 return &Decoder{iter}
370 func (cfg *frozenConfig) Valid(data []byte) bool {
371 iter := cfg.BorrowIterator(data)
372 defer cfg.ReturnIterator(iter)
374 return iter.Error == nil