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