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 }