gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

config.go (10545B)


      1 package jsoniter
      2 
      3 import (
      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.
     16 type 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.
     32 type 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
     50 var ConfigDefault = Config{
     51 	EscapeHTML: true,
     52 }.Froze()
     53 
     54 // ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior
     55 var ConfigCompatibleWithStandardLibrary = Config{
     56 	EscapeHTML:             true,
     57 	SortMapKeys:            true,
     58 	ValidateJsonRawMessage: true,
     59 }.Froze()
     60 
     61 // ConfigFastest marshals float with only 6 digits precision
     62 var ConfigFastest = Config{
     63 	EscapeHTML:                    false,
     64 	MarshalFloatWith6Digits:       true, // will lose precession
     65 	ObjectFieldMustBeSimpleString: true, // do not unescape object field
     66 }.Froze()
     67 
     68 type 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 
     85 func (cfg *frozenConfig) initCache() {
     86 	cfg.decoderCache = concurrent.NewMap()
     87 	cfg.encoderCache = concurrent.NewMap()
     88 }
     89 
     90 func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) {
     91 	cfg.decoderCache.Store(cacheKey, decoder)
     92 }
     93 
     94 func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) {
     95 	cfg.encoderCache.Store(cacheKey, encoder)
     96 }
     97 
     98 func (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 
    106 func (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 
    114 var cfgCache = concurrent.NewMap()
    115 
    116 func getFrozenConfigFromCache(cfg Config) *frozenConfig {
    117 	obj, found := cfgCache.Load(cfg)
    118 	if found {
    119 		return obj.(*frozenConfig)
    120 	}
    121 	return nil
    122 }
    123 
    124 func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) {
    125 	cfgCache.Store(cfg, frozenConfig)
    126 }
    127 
    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,
    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 
    169 func (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 
    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))
    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 
    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)
    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 }
    214 func (cfg *frozenConfig) getTagKey() string {
    215 	tagKey := cfg.configBeforeFrozen.TagKey
    216 	if tagKey == "" {
    217 		return "json"
    218 	}
    219 	return tagKey
    220 }
    221 
    222 func (cfg *frozenConfig) RegisterExtension(extension Extension) {
    223 	cfg.extraExtensions = append(cfg.extraExtensions, extension)
    224 	copied := cfg.configBeforeFrozen
    225 	cfg.configBeforeFrozen = copied
    226 }
    227 
    228 type lossyFloat32Encoder struct {
    229 }
    230 
    231 func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
    232 	stream.WriteFloat32Lossy(*((*float32)(ptr)))
    233 }
    234 
    235 func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool {
    236 	return *((*float32)(ptr)) == 0
    237 }
    238 
    239 type lossyFloat64Encoder struct {
    240 }
    241 
    242 func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) {
    243 	stream.WriteFloat64Lossy(*((*float64)(ptr)))
    244 }
    245 
    246 func (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.
    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{}
    256 }
    257 
    258 type htmlEscapedStringEncoder struct {
    259 }
    260 
    261 func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
    262 	str := *((*string)(ptr))
    263 	stream.WriteStringWithHTMLEscaped(str)
    264 }
    265 
    266 func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
    267 	return *((*string)(ptr)) == ""
    268 }
    269 
    270 func (cfg *frozenConfig) escapeHTML(encoderExtension EncoderExtension) {
    271 	encoderExtension[reflect2.TypeOfPtr((*string)(nil)).Elem()] = &htmlEscapedStringEncoder{}
    272 }
    273 
    274 func (cfg *frozenConfig) cleanDecoders() {
    275 	typeDecoders = map[string]ValDecoder{}
    276 	fieldDecoders = map[string]ValDecoder{}
    277 	*cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
    278 }
    279 
    280 func (cfg *frozenConfig) cleanEncoders() {
    281 	typeEncoders = map[string]ValEncoder{}
    282 	fieldEncoders = map[string]ValEncoder{}
    283 	*cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig))
    284 }
    285 
    286 func (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 
    296 func (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 
    309 func (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 
    323 func (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 
    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)
    343 }
    344 
    345 func (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 
    360 func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder {
    361 	stream := NewStream(cfg, writer, 512)
    362 	return &Encoder{stream}
    363 }
    364 
    365 func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder {
    366 	iter := Parse(cfg, reader, 512)
    367 	return &Decoder{iter}
    368 }
    369 
    370 func (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 }