khenaidoo | ab1f7bd | 2019-11-14 14:00:27 -0500 | [diff] [blame] | 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 | iter.Read() |
| 187 | if iter.Error != nil { |
| 188 | stream.WriteRaw("null") |
| 189 | } else { |
| 190 | cfg.ReturnIterator(iter) |
| 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 | } |