Matthias Andreas Benkard | 832a54e | 2019-01-29 09:27:38 +0100 | [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 | extensions []Extension |
| 78 | streamPool *sync.Pool |
| 79 | iteratorPool *sync.Pool |
| 80 | caseSensitive bool |
| 81 | } |
| 82 | |
| 83 | func (cfg *frozenConfig) initCache() { |
| 84 | cfg.decoderCache = concurrent.NewMap() |
| 85 | cfg.encoderCache = concurrent.NewMap() |
| 86 | } |
| 87 | |
| 88 | func (cfg *frozenConfig) addDecoderToCache(cacheKey uintptr, decoder ValDecoder) { |
| 89 | cfg.decoderCache.Store(cacheKey, decoder) |
| 90 | } |
| 91 | |
| 92 | func (cfg *frozenConfig) addEncoderToCache(cacheKey uintptr, encoder ValEncoder) { |
| 93 | cfg.encoderCache.Store(cacheKey, encoder) |
| 94 | } |
| 95 | |
| 96 | func (cfg *frozenConfig) getDecoderFromCache(cacheKey uintptr) ValDecoder { |
| 97 | decoder, found := cfg.decoderCache.Load(cacheKey) |
| 98 | if found { |
| 99 | return decoder.(ValDecoder) |
| 100 | } |
| 101 | return nil |
| 102 | } |
| 103 | |
| 104 | func (cfg *frozenConfig) getEncoderFromCache(cacheKey uintptr) ValEncoder { |
| 105 | encoder, found := cfg.encoderCache.Load(cacheKey) |
| 106 | if found { |
| 107 | return encoder.(ValEncoder) |
| 108 | } |
| 109 | return nil |
| 110 | } |
| 111 | |
| 112 | var cfgCache = concurrent.NewMap() |
| 113 | |
| 114 | func getFrozenConfigFromCache(cfg Config) *frozenConfig { |
| 115 | obj, found := cfgCache.Load(cfg) |
| 116 | if found { |
| 117 | return obj.(*frozenConfig) |
| 118 | } |
| 119 | return nil |
| 120 | } |
| 121 | |
| 122 | func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) { |
| 123 | cfgCache.Store(cfg, frozenConfig) |
| 124 | } |
| 125 | |
| 126 | // Froze forge API from config |
| 127 | func (cfg Config) Froze() API { |
| 128 | api := &frozenConfig{ |
| 129 | sortMapKeys: cfg.SortMapKeys, |
| 130 | indentionStep: cfg.IndentionStep, |
| 131 | objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString, |
| 132 | onlyTaggedField: cfg.OnlyTaggedField, |
| 133 | disallowUnknownFields: cfg.DisallowUnknownFields, |
| 134 | caseSensitive: cfg.CaseSensitive, |
| 135 | } |
| 136 | api.streamPool = &sync.Pool{ |
| 137 | New: func() interface{} { |
| 138 | return NewStream(api, nil, 512) |
| 139 | }, |
| 140 | } |
| 141 | api.iteratorPool = &sync.Pool{ |
| 142 | New: func() interface{} { |
| 143 | return NewIterator(api) |
| 144 | }, |
| 145 | } |
| 146 | api.initCache() |
| 147 | encoderExtension := EncoderExtension{} |
| 148 | decoderExtension := DecoderExtension{} |
| 149 | if cfg.MarshalFloatWith6Digits { |
| 150 | api.marshalFloatWith6Digits(encoderExtension) |
| 151 | } |
| 152 | if cfg.EscapeHTML { |
| 153 | api.escapeHTML(encoderExtension) |
| 154 | } |
| 155 | if cfg.UseNumber { |
| 156 | api.useNumber(decoderExtension) |
| 157 | } |
| 158 | if cfg.ValidateJsonRawMessage { |
| 159 | api.validateJsonRawMessage(encoderExtension) |
| 160 | } |
| 161 | if len(encoderExtension) > 0 { |
| 162 | api.extensions = append(api.extensions, encoderExtension) |
| 163 | } |
| 164 | if len(decoderExtension) > 0 { |
| 165 | api.extensions = append(api.extensions, decoderExtension) |
| 166 | } |
| 167 | api.configBeforeFrozen = cfg |
| 168 | return api |
| 169 | } |
| 170 | |
| 171 | func (cfg Config) frozeWithCacheReuse() *frozenConfig { |
| 172 | api := getFrozenConfigFromCache(cfg) |
| 173 | if api != nil { |
| 174 | return api |
| 175 | } |
| 176 | api = cfg.Froze().(*frozenConfig) |
| 177 | addFrozenConfigToCache(cfg, api) |
| 178 | return api |
| 179 | } |
| 180 | |
| 181 | func (cfg *frozenConfig) validateJsonRawMessage(extension EncoderExtension) { |
| 182 | encoder := &funcEncoder{func(ptr unsafe.Pointer, stream *Stream) { |
| 183 | rawMessage := *(*json.RawMessage)(ptr) |
| 184 | iter := cfg.BorrowIterator([]byte(rawMessage)) |
| 185 | iter.Read() |
| 186 | if iter.Error != nil { |
| 187 | stream.WriteRaw("null") |
| 188 | } else { |
| 189 | cfg.ReturnIterator(iter) |
| 190 | stream.WriteRaw(string(rawMessage)) |
| 191 | } |
| 192 | }, func(ptr unsafe.Pointer) bool { |
| 193 | return false |
| 194 | }} |
| 195 | extension[reflect2.TypeOfPtr((*json.RawMessage)(nil)).Elem()] = encoder |
| 196 | extension[reflect2.TypeOfPtr((*RawMessage)(nil)).Elem()] = encoder |
| 197 | } |
| 198 | |
| 199 | func (cfg *frozenConfig) useNumber(extension DecoderExtension) { |
| 200 | extension[reflect2.TypeOfPtr((*interface{})(nil)).Elem()] = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) { |
| 201 | exitingValue := *((*interface{})(ptr)) |
| 202 | if exitingValue != nil && reflect.TypeOf(exitingValue).Kind() == reflect.Ptr { |
| 203 | iter.ReadVal(exitingValue) |
| 204 | return |
| 205 | } |
| 206 | if iter.WhatIsNext() == NumberValue { |
| 207 | *((*interface{})(ptr)) = json.Number(iter.readNumberAsString()) |
| 208 | } else { |
| 209 | *((*interface{})(ptr)) = iter.Read() |
| 210 | } |
| 211 | }} |
| 212 | } |
| 213 | func (cfg *frozenConfig) getTagKey() string { |
| 214 | tagKey := cfg.configBeforeFrozen.TagKey |
| 215 | if tagKey == "" { |
| 216 | return "json" |
| 217 | } |
| 218 | return tagKey |
| 219 | } |
| 220 | |
| 221 | func (cfg *frozenConfig) RegisterExtension(extension Extension) { |
| 222 | cfg.extensions = append(cfg.extensions, extension) |
| 223 | } |
| 224 | |
| 225 | type lossyFloat32Encoder struct { |
| 226 | } |
| 227 | |
| 228 | func (encoder *lossyFloat32Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { |
| 229 | stream.WriteFloat32Lossy(*((*float32)(ptr))) |
| 230 | } |
| 231 | |
| 232 | func (encoder *lossyFloat32Encoder) IsEmpty(ptr unsafe.Pointer) bool { |
| 233 | return *((*float32)(ptr)) == 0 |
| 234 | } |
| 235 | |
| 236 | type lossyFloat64Encoder struct { |
| 237 | } |
| 238 | |
| 239 | func (encoder *lossyFloat64Encoder) Encode(ptr unsafe.Pointer, stream *Stream) { |
| 240 | stream.WriteFloat64Lossy(*((*float64)(ptr))) |
| 241 | } |
| 242 | |
| 243 | func (encoder *lossyFloat64Encoder) IsEmpty(ptr unsafe.Pointer) bool { |
| 244 | return *((*float64)(ptr)) == 0 |
| 245 | } |
| 246 | |
| 247 | // EnableLossyFloatMarshalling keeps 10**(-6) precision |
| 248 | // for float variables for better performance. |
| 249 | func (cfg *frozenConfig) marshalFloatWith6Digits(extension EncoderExtension) { |
| 250 | // for better performance |
| 251 | extension[reflect2.TypeOfPtr((*float32)(nil)).Elem()] = &lossyFloat32Encoder{} |
| 252 | extension[reflect2.TypeOfPtr((*float64)(nil)).Elem()] = &lossyFloat64Encoder{} |
| 253 | } |
| 254 | |
| 255 | type htmlEscapedStringEncoder struct { |
| 256 | } |
| 257 | |
| 258 | func (encoder *htmlEscapedStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) { |
| 259 | str := *((*string)(ptr)) |
| 260 | stream.WriteStringWithHTMLEscaped(str) |
| 261 | } |
| 262 | |
| 263 | func (encoder *htmlEscapedStringEncoder) IsEmpty(ptr unsafe.Pointer) bool { |
| 264 | return *((*string)(ptr)) == "" |
| 265 | } |
| 266 | |
| 267 | func (cfg *frozenConfig) escapeHTML(encoderExtension EncoderExtension) { |
| 268 | encoderExtension[reflect2.TypeOfPtr((*string)(nil)).Elem()] = &htmlEscapedStringEncoder{} |
| 269 | } |
| 270 | |
| 271 | func (cfg *frozenConfig) cleanDecoders() { |
| 272 | typeDecoders = map[string]ValDecoder{} |
| 273 | fieldDecoders = map[string]ValDecoder{} |
| 274 | *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) |
| 275 | } |
| 276 | |
| 277 | func (cfg *frozenConfig) cleanEncoders() { |
| 278 | typeEncoders = map[string]ValEncoder{} |
| 279 | fieldEncoders = map[string]ValEncoder{} |
| 280 | *cfg = *(cfg.configBeforeFrozen.Froze().(*frozenConfig)) |
| 281 | } |
| 282 | |
| 283 | func (cfg *frozenConfig) MarshalToString(v interface{}) (string, error) { |
| 284 | stream := cfg.BorrowStream(nil) |
| 285 | defer cfg.ReturnStream(stream) |
| 286 | stream.WriteVal(v) |
| 287 | if stream.Error != nil { |
| 288 | return "", stream.Error |
| 289 | } |
| 290 | return string(stream.Buffer()), nil |
| 291 | } |
| 292 | |
| 293 | func (cfg *frozenConfig) Marshal(v interface{}) ([]byte, error) { |
| 294 | stream := cfg.BorrowStream(nil) |
| 295 | defer cfg.ReturnStream(stream) |
| 296 | stream.WriteVal(v) |
| 297 | if stream.Error != nil { |
| 298 | return nil, stream.Error |
| 299 | } |
| 300 | result := stream.Buffer() |
| 301 | copied := make([]byte, len(result)) |
| 302 | copy(copied, result) |
| 303 | return copied, nil |
| 304 | } |
| 305 | |
| 306 | func (cfg *frozenConfig) MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { |
| 307 | if prefix != "" { |
| 308 | panic("prefix is not supported") |
| 309 | } |
| 310 | for _, r := range indent { |
| 311 | if r != ' ' { |
| 312 | panic("indent can only be space") |
| 313 | } |
| 314 | } |
| 315 | newCfg := cfg.configBeforeFrozen |
| 316 | newCfg.IndentionStep = len(indent) |
| 317 | return newCfg.frozeWithCacheReuse().Marshal(v) |
| 318 | } |
| 319 | |
| 320 | func (cfg *frozenConfig) UnmarshalFromString(str string, v interface{}) error { |
| 321 | data := []byte(str) |
| 322 | iter := cfg.BorrowIterator(data) |
| 323 | defer cfg.ReturnIterator(iter) |
| 324 | iter.ReadVal(v) |
| 325 | c := iter.nextToken() |
| 326 | if c == 0 { |
| 327 | if iter.Error == io.EOF { |
| 328 | return nil |
| 329 | } |
| 330 | return iter.Error |
| 331 | } |
| 332 | iter.ReportError("Unmarshal", "there are bytes left after unmarshal") |
| 333 | return iter.Error |
| 334 | } |
| 335 | |
| 336 | func (cfg *frozenConfig) Get(data []byte, path ...interface{}) Any { |
| 337 | iter := cfg.BorrowIterator(data) |
| 338 | defer cfg.ReturnIterator(iter) |
| 339 | return locatePath(iter, path) |
| 340 | } |
| 341 | |
| 342 | func (cfg *frozenConfig) Unmarshal(data []byte, v interface{}) error { |
| 343 | iter := cfg.BorrowIterator(data) |
| 344 | defer cfg.ReturnIterator(iter) |
| 345 | iter.ReadVal(v) |
| 346 | c := iter.nextToken() |
| 347 | if c == 0 { |
| 348 | if iter.Error == io.EOF { |
| 349 | return nil |
| 350 | } |
| 351 | return iter.Error |
| 352 | } |
| 353 | iter.ReportError("Unmarshal", "there are bytes left after unmarshal") |
| 354 | return iter.Error |
| 355 | } |
| 356 | |
| 357 | func (cfg *frozenConfig) NewEncoder(writer io.Writer) *Encoder { |
| 358 | stream := NewStream(cfg, writer, 512) |
| 359 | return &Encoder{stream} |
| 360 | } |
| 361 | |
| 362 | func (cfg *frozenConfig) NewDecoder(reader io.Reader) *Decoder { |
| 363 | iter := Parse(cfg, reader, 512) |
| 364 | return &Decoder{iter} |
| 365 | } |
| 366 | |
| 367 | func (cfg *frozenConfig) Valid(data []byte) bool { |
| 368 | iter := cfg.BorrowIterator(data) |
| 369 | defer cfg.ReturnIterator(iter) |
| 370 | iter.Skip() |
| 371 | return iter.Error == nil |
| 372 | } |