github.com/segmentio/encoding@v0.4.0/json/json.go (about) 1 package json 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "io" 7 "math/bits" 8 "reflect" 9 "runtime" 10 "sync" 11 "unsafe" 12 ) 13 14 // Delim is documented at https://golang.org/pkg/encoding/json/#Delim 15 type Delim = json.Delim 16 17 // InvalidUTF8Error is documented at https://golang.org/pkg/encoding/json/#InvalidUTF8Error 18 type InvalidUTF8Error = json.InvalidUTF8Error 19 20 // InvalidUnmarshalError is documented at https://golang.org/pkg/encoding/json/#InvalidUnmarshalError 21 type InvalidUnmarshalError = json.InvalidUnmarshalError 22 23 // Marshaler is documented at https://golang.org/pkg/encoding/json/#Marshaler 24 type Marshaler = json.Marshaler 25 26 // MarshalerError is documented at https://golang.org/pkg/encoding/json/#MarshalerError 27 type MarshalerError = json.MarshalerError 28 29 // Number is documented at https://golang.org/pkg/encoding/json/#Number 30 type Number = json.Number 31 32 // RawMessage is documented at https://golang.org/pkg/encoding/json/#RawMessage 33 type RawMessage = json.RawMessage 34 35 // A SyntaxError is a description of a JSON syntax error. 36 type SyntaxError = json.SyntaxError 37 38 // Token is documented at https://golang.org/pkg/encoding/json/#Token 39 type Token = json.Token 40 41 // UnmarshalFieldError is documented at https://golang.org/pkg/encoding/json/#UnmarshalFieldError 42 type UnmarshalFieldError = json.UnmarshalFieldError 43 44 // UnmarshalTypeError is documented at https://golang.org/pkg/encoding/json/#UnmarshalTypeError 45 type UnmarshalTypeError = json.UnmarshalTypeError 46 47 // Unmarshaler is documented at https://golang.org/pkg/encoding/json/#Unmarshaler 48 type Unmarshaler = json.Unmarshaler 49 50 // UnsupportedTypeError is documented at https://golang.org/pkg/encoding/json/#UnsupportedTypeError 51 type UnsupportedTypeError = json.UnsupportedTypeError 52 53 // UnsupportedValueError is documented at https://golang.org/pkg/encoding/json/#UnsupportedValueError 54 type UnsupportedValueError = json.UnsupportedValueError 55 56 // AppendFlags is a type used to represent configuration options that can be 57 // applied when formatting json output. 58 type AppendFlags uint32 59 60 const ( 61 // EscapeHTML is a formatting flag used to to escape HTML in json strings. 62 EscapeHTML AppendFlags = 1 << iota 63 64 // SortMapKeys is formatting flag used to enable sorting of map keys when 65 // encoding JSON (this matches the behavior of the standard encoding/json 66 // package). 67 SortMapKeys 68 69 // TrustRawMessage is a performance optimization flag to skip value 70 // checking of raw messages. It should only be used if the values are 71 // known to be valid json (e.g., they were created by json.Unmarshal). 72 TrustRawMessage 73 74 // appendNewline is a formatting flag to enable the addition of a newline 75 // in Encode (this matches the behavior of the standard encoding/json 76 // package). 77 appendNewline 78 ) 79 80 // ParseFlags is a type used to represent configuration options that can be 81 // applied when parsing json input. 82 type ParseFlags uint32 83 84 func (flags ParseFlags) has(f ParseFlags) bool { 85 return (flags & f) != 0 86 } 87 88 func (f ParseFlags) kind() Kind { 89 return Kind((f >> kindOffset) & 0xFF) 90 } 91 92 func (f ParseFlags) withKind(kind Kind) ParseFlags { 93 return (f & ^(ParseFlags(0xFF) << kindOffset)) | (ParseFlags(kind) << kindOffset) 94 } 95 96 const ( 97 // DisallowUnknownFields is a parsing flag used to prevent decoding of 98 // objects to Go struct values when a field of the input does not match 99 // with any of the struct fields. 100 DisallowUnknownFields ParseFlags = 1 << iota 101 102 // UseNumber is a parsing flag used to load numeric values as Number 103 // instead of float64. 104 UseNumber 105 106 // DontCopyString is a parsing flag used to provide zero-copy support when 107 // loading string values from a json payload. It is not always possible to 108 // avoid dynamic memory allocations, for example when a string is escaped in 109 // the json data a new buffer has to be allocated, but when the `wire` value 110 // can be used as content of a Go value the decoder will simply point into 111 // the input buffer. 112 DontCopyString 113 114 // DontCopyNumber is a parsing flag used to provide zero-copy support when 115 // loading Number values (see DontCopyString and DontCopyRawMessage). 116 DontCopyNumber 117 118 // DontCopyRawMessage is a parsing flag used to provide zero-copy support 119 // when loading RawMessage values from a json payload. When used, the 120 // RawMessage values will not be allocated into new memory buffers and 121 // will instead point directly to the area of the input buffer where the 122 // value was found. 123 DontCopyRawMessage 124 125 // DontMatchCaseInsensitiveStructFields is a parsing flag used to prevent 126 // matching fields in a case-insensitive way. This can prevent degrading 127 // performance on case conversions, and can also act as a stricter decoding 128 // mode. 129 DontMatchCaseInsensitiveStructFields 130 131 // Decode integers into *big.Int. 132 // Takes precedence over UseNumber for integers. 133 UseBigInt 134 135 // Decode in-range integers to int64. 136 // Takes precedence over UseNumber and UseBigInt for in-range integers. 137 UseInt64 138 139 // Decode in-range positive integers to uint64. 140 // Takes precedence over UseNumber, UseBigInt, and UseInt64 141 // for positive, in-range integers. 142 UseUint64 143 144 // ZeroCopy is a parsing flag that combines all the copy optimizations 145 // available in the package. 146 // 147 // The zero-copy optimizations are better used in request-handler style 148 // code where none of the values are retained after the handler returns. 149 ZeroCopy = DontCopyString | DontCopyNumber | DontCopyRawMessage 150 151 // validAsciiPrint is an internal flag indicating that the input contains 152 // only valid ASCII print chars (0x20 <= c <= 0x7E). If the flag is unset, 153 // it's unknown whether the input is valid ASCII print. 154 validAsciiPrint ParseFlags = 1 << 28 155 156 // noBackslach is an internal flag indicating that the input does not 157 // contain a backslash. If the flag is unset, it's unknown whether the 158 // input contains a backslash. 159 noBackslash ParseFlags = 1 << 29 160 161 // Bit offset where the kind of the json value is stored. 162 // 163 // See Kind in token.go for the enum. 164 kindOffset ParseFlags = 16 165 ) 166 167 // Kind represents the different kinds of value that exist in JSON. 168 type Kind uint 169 170 const ( 171 Undefined Kind = 0 172 173 Null Kind = 1 // Null is not zero, so we keep zero for "undefined". 174 175 Bool Kind = 2 // Bit two is set to 1, means it's a boolean. 176 False Kind = 2 // Bool + 0 177 True Kind = 3 // Bool + 1 178 179 Num Kind = 4 // Bit three is set to 1, means it's a number. 180 Uint Kind = 5 // Num + 1 181 Int Kind = 6 // Num + 2 182 Float Kind = 7 // Num + 3 183 184 String Kind = 8 // Bit four is set to 1, means it's a string. 185 Unescaped Kind = 9 // String + 1 186 187 Array Kind = 16 // Equivalent to Delim == '[' 188 Object Kind = 32 // Equivalent to Delim == '{' 189 ) 190 191 // Class returns the class of k. 192 func (k Kind) Class() Kind { return Kind(1 << uint(bits.Len(uint(k))-1)) } 193 194 // Append acts like Marshal but appends the json representation to b instead of 195 // always reallocating a new slice. 196 func Append(b []byte, x interface{}, flags AppendFlags) ([]byte, error) { 197 if x == nil { 198 // Special case for nil values because it makes the rest of the code 199 // simpler to assume that it won't be seeing nil pointers. 200 return append(b, "null"...), nil 201 } 202 203 t := reflect.TypeOf(x) 204 p := (*iface)(unsafe.Pointer(&x)).ptr 205 206 cache := cacheLoad() 207 c, found := cache[typeid(t)] 208 209 if !found { 210 c = constructCachedCodec(t, cache) 211 } 212 213 b, err := c.encode(encoder{flags: flags}, b, p) 214 runtime.KeepAlive(x) 215 return b, err 216 } 217 218 // Escape is a convenience helper to construct an escaped JSON string from s. 219 // The function escales HTML characters, for more control over the escape 220 // behavior and to write to a pre-allocated buffer, use AppendEscape. 221 func Escape(s string) []byte { 222 // +10 for extra escape characters, maybe not enough and the buffer will 223 // be reallocated. 224 b := make([]byte, 0, len(s)+10) 225 return AppendEscape(b, s, EscapeHTML) 226 } 227 228 // AppendEscape appends s to b with the string escaped as a JSON value. 229 // This will include the starting and ending quote characters, and the 230 // appropriate characters will be escaped correctly for JSON encoding. 231 func AppendEscape(b []byte, s string, flags AppendFlags) []byte { 232 e := encoder{flags: flags} 233 b, _ = e.encodeString(b, unsafe.Pointer(&s)) 234 return b 235 } 236 237 // Unescape is a convenience helper to unescape a JSON value. 238 // For more control over the unescape behavior and 239 // to write to a pre-allocated buffer, use AppendUnescape. 240 func Unescape(s []byte) []byte { 241 b := make([]byte, 0, len(s)) 242 return AppendUnescape(b, s, ParseFlags(0)) 243 } 244 245 // AppendUnescape appends s to b with the string unescaped as a JSON value. 246 // This will remove starting and ending quote characters, and the 247 // appropriate characters will be escaped correctly as if JSON decoded. 248 // New space will be reallocated if more space is needed. 249 func AppendUnescape(b []byte, s []byte, flags ParseFlags) []byte { 250 d := decoder{flags: flags} 251 buf := new(string) 252 d.decodeString(s, unsafe.Pointer(buf)) 253 return append(b, *buf...) 254 } 255 256 // Compact is documented at https://golang.org/pkg/encoding/json/#Compact 257 func Compact(dst *bytes.Buffer, src []byte) error { 258 return json.Compact(dst, src) 259 } 260 261 // HTMLEscape is documented at https://golang.org/pkg/encoding/json/#HTMLEscape 262 func HTMLEscape(dst *bytes.Buffer, src []byte) { 263 json.HTMLEscape(dst, src) 264 } 265 266 // Indent is documented at https://golang.org/pkg/encoding/json/#Indent 267 func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { 268 return json.Indent(dst, src, prefix, indent) 269 } 270 271 // Marshal is documented at https://golang.org/pkg/encoding/json/#Marshal 272 func Marshal(x interface{}) ([]byte, error) { 273 var err error 274 var buf = encoderBufferPool.Get().(*encoderBuffer) 275 276 if buf.data, err = Append(buf.data[:0], x, EscapeHTML|SortMapKeys); err != nil { 277 return nil, err 278 } 279 280 b := make([]byte, len(buf.data)) 281 copy(b, buf.data) 282 encoderBufferPool.Put(buf) 283 return b, nil 284 } 285 286 // MarshalIndent is documented at https://golang.org/pkg/encoding/json/#MarshalIndent 287 func MarshalIndent(x interface{}, prefix, indent string) ([]byte, error) { 288 b, err := Marshal(x) 289 290 if err == nil { 291 tmp := &bytes.Buffer{} 292 tmp.Grow(2 * len(b)) 293 294 Indent(tmp, b, prefix, indent) 295 b = tmp.Bytes() 296 } 297 298 return b, err 299 } 300 301 // Unmarshal is documented at https://golang.org/pkg/encoding/json/#Unmarshal 302 func Unmarshal(b []byte, x interface{}) error { 303 r, err := Parse(b, x, 0) 304 if len(r) != 0 { 305 if _, ok := err.(*SyntaxError); !ok { 306 // The encoding/json package prioritizes reporting errors caused by 307 // unexpected trailing bytes over other issues; here we emulate this 308 // behavior by overriding the error. 309 err = syntaxError(r, "invalid character '%c' after top-level value", r[0]) 310 } 311 } 312 return err 313 } 314 315 // Parse behaves like Unmarshal but the caller can pass a set of flags to 316 // configure the parsing behavior. 317 func Parse(b []byte, x interface{}, flags ParseFlags) ([]byte, error) { 318 t := reflect.TypeOf(x) 319 p := (*iface)(unsafe.Pointer(&x)).ptr 320 321 d := decoder{flags: flags | internalParseFlags(b)} 322 323 b = skipSpaces(b) 324 325 if t == nil || p == nil || t.Kind() != reflect.Ptr { 326 _, r, _, err := d.parseValue(b) 327 r = skipSpaces(r) 328 if err != nil { 329 return r, err 330 } 331 return r, &InvalidUnmarshalError{Type: t} 332 } 333 t = t.Elem() 334 335 cache := cacheLoad() 336 c, found := cache[typeid(t)] 337 338 if !found { 339 c = constructCachedCodec(t, cache) 340 } 341 342 r, err := c.decode(d, b, p) 343 return skipSpaces(r), err 344 } 345 346 // Valid is documented at https://golang.org/pkg/encoding/json/#Valid 347 func Valid(data []byte) bool { 348 data = skipSpaces(data) 349 d := decoder{flags: internalParseFlags(data)} 350 _, data, _, err := d.parseValue(data) 351 if err != nil { 352 return false 353 } 354 return len(skipSpaces(data)) == 0 355 } 356 357 // Decoder is documented at https://golang.org/pkg/encoding/json/#Decoder 358 type Decoder struct { 359 reader io.Reader 360 buffer []byte 361 remain []byte 362 inputOffset int64 363 err error 364 flags ParseFlags 365 } 366 367 // NewDecoder is documented at https://golang.org/pkg/encoding/json/#NewDecoder 368 func NewDecoder(r io.Reader) *Decoder { return &Decoder{reader: r} } 369 370 // Buffered is documented at https://golang.org/pkg/encoding/json/#Decoder.Buffered 371 func (dec *Decoder) Buffered() io.Reader { 372 return bytes.NewReader(dec.remain) 373 } 374 375 // Decode is documented at https://golang.org/pkg/encoding/json/#Decoder.Decode 376 func (dec *Decoder) Decode(v interface{}) error { 377 raw, err := dec.readValue() 378 if err != nil { 379 return err 380 } 381 _, err = Parse(raw, v, dec.flags) 382 return err 383 } 384 385 const ( 386 minBufferSize = 32768 387 minReadSize = 4096 388 ) 389 390 // readValue reads one JSON value from the buffer and returns its raw bytes. It 391 // is optimized for the "one JSON value per line" case. 392 func (dec *Decoder) readValue() (v []byte, err error) { 393 var n int 394 var r []byte 395 d := decoder{flags: dec.flags} 396 397 for { 398 if len(dec.remain) != 0 { 399 v, r, _, err = d.parseValue(dec.remain) 400 if err == nil { 401 dec.remain, n = skipSpacesN(r) 402 dec.inputOffset += int64(len(v) + n) 403 return 404 } 405 if len(r) != 0 { 406 // Parsing of the next JSON value stopped at a position other 407 // than the end of the input buffer, which indicaates that a 408 // syntax error was encountered. 409 return 410 } 411 } 412 413 if err = dec.err; err != nil { 414 if len(dec.remain) != 0 && err == io.EOF { 415 err = io.ErrUnexpectedEOF 416 } 417 return 418 } 419 420 if dec.buffer == nil { 421 dec.buffer = make([]byte, 0, minBufferSize) 422 } else { 423 dec.buffer = dec.buffer[:copy(dec.buffer[:cap(dec.buffer)], dec.remain)] 424 dec.remain = nil 425 } 426 427 if (cap(dec.buffer) - len(dec.buffer)) < minReadSize { 428 buf := make([]byte, len(dec.buffer), 2*cap(dec.buffer)) 429 copy(buf, dec.buffer) 430 dec.buffer = buf 431 } 432 433 n, err = io.ReadFull(dec.reader, dec.buffer[len(dec.buffer):cap(dec.buffer)]) 434 if n > 0 { 435 dec.buffer = dec.buffer[:len(dec.buffer)+n] 436 if err != nil { 437 err = nil 438 } 439 } else if err == io.ErrUnexpectedEOF { 440 err = io.EOF 441 } 442 dec.remain, n = skipSpacesN(dec.buffer) 443 d.flags = dec.flags | internalParseFlags(dec.remain) 444 dec.inputOffset += int64(n) 445 dec.err = err 446 } 447 } 448 449 // DisallowUnknownFields is documented at https://golang.org/pkg/encoding/json/#Decoder.DisallowUnknownFields 450 func (dec *Decoder) DisallowUnknownFields() { dec.flags |= DisallowUnknownFields } 451 452 // UseNumber is documented at https://golang.org/pkg/encoding/json/#Decoder.UseNumber 453 func (dec *Decoder) UseNumber() { dec.flags |= UseNumber } 454 455 // DontCopyString is an extension to the standard encoding/json package 456 // which instructs the decoder to not copy strings loaded from the json 457 // payloads when possible. 458 func (dec *Decoder) DontCopyString() { dec.flags |= DontCopyString } 459 460 // DontCopyNumber is an extension to the standard encoding/json package 461 // which instructs the decoder to not copy numbers loaded from the json 462 // payloads. 463 func (dec *Decoder) DontCopyNumber() { dec.flags |= DontCopyNumber } 464 465 // DontCopyRawMessage is an extension to the standard encoding/json package 466 // which instructs the decoder to not allocate RawMessage values in separate 467 // memory buffers (see the documentation of the DontcopyRawMessage flag for 468 // more detais). 469 func (dec *Decoder) DontCopyRawMessage() { dec.flags |= DontCopyRawMessage } 470 471 // DontMatchCaseInsensitiveStructFields is an extension to the standard 472 // encoding/json package which instructs the decoder to not match object fields 473 // against struct fields in a case-insensitive way, the field names have to 474 // match exactly to be decoded into the struct field values. 475 func (dec *Decoder) DontMatchCaseInsensitiveStructFields() { 476 dec.flags |= DontMatchCaseInsensitiveStructFields 477 } 478 479 // ZeroCopy is an extension to the standard encoding/json package which enables 480 // all the copy optimizations of the decoder. 481 func (dec *Decoder) ZeroCopy() { dec.flags |= ZeroCopy } 482 483 // InputOffset returns the input stream byte offset of the current decoder position. 484 // The offset gives the location of the end of the most recently returned token 485 // and the beginning of the next token. 486 func (dec *Decoder) InputOffset() int64 { 487 return dec.inputOffset 488 } 489 490 // Encoder is documented at https://golang.org/pkg/encoding/json/#Encoder 491 type Encoder struct { 492 writer io.Writer 493 prefix string 494 indent string 495 buffer *bytes.Buffer 496 err error 497 flags AppendFlags 498 } 499 500 // NewEncoder is documented at https://golang.org/pkg/encoding/json/#NewEncoder 501 func NewEncoder(w io.Writer) *Encoder { 502 return &Encoder{writer: w, flags: EscapeHTML | SortMapKeys | appendNewline} 503 } 504 505 // Encode is documented at https://golang.org/pkg/encoding/json/#Encoder.Encode 506 func (enc *Encoder) Encode(v interface{}) error { 507 if enc.err != nil { 508 return enc.err 509 } 510 511 var err error 512 var buf = encoderBufferPool.Get().(*encoderBuffer) 513 514 buf.data, err = Append(buf.data[:0], v, enc.flags) 515 516 if err != nil { 517 encoderBufferPool.Put(buf) 518 return err 519 } 520 521 if (enc.flags & appendNewline) != 0 { 522 buf.data = append(buf.data, '\n') 523 } 524 b := buf.data 525 526 if enc.prefix != "" || enc.indent != "" { 527 if enc.buffer == nil { 528 enc.buffer = new(bytes.Buffer) 529 enc.buffer.Grow(2 * len(buf.data)) 530 } else { 531 enc.buffer.Reset() 532 } 533 Indent(enc.buffer, buf.data, enc.prefix, enc.indent) 534 b = enc.buffer.Bytes() 535 } 536 537 if _, err := enc.writer.Write(b); err != nil { 538 enc.err = err 539 } 540 541 encoderBufferPool.Put(buf) 542 return err 543 } 544 545 // SetEscapeHTML is documented at https://golang.org/pkg/encoding/json/#Encoder.SetEscapeHTML 546 func (enc *Encoder) SetEscapeHTML(on bool) { 547 if on { 548 enc.flags |= EscapeHTML 549 } else { 550 enc.flags &= ^EscapeHTML 551 } 552 } 553 554 // SetIndent is documented at https://golang.org/pkg/encoding/json/#Encoder.SetIndent 555 func (enc *Encoder) SetIndent(prefix, indent string) { 556 enc.prefix = prefix 557 enc.indent = indent 558 } 559 560 // SetSortMapKeys is an extension to the standard encoding/json package which 561 // allows the program to toggle sorting of map keys on and off. 562 func (enc *Encoder) SetSortMapKeys(on bool) { 563 if on { 564 enc.flags |= SortMapKeys 565 } else { 566 enc.flags &= ^SortMapKeys 567 } 568 } 569 570 // SetTrustRawMessage skips value checking when encoding a raw json message. It should only 571 // be used if the values are known to be valid json, e.g. because they were originally created 572 // by json.Unmarshal. 573 func (enc *Encoder) SetTrustRawMessage(on bool) { 574 if on { 575 enc.flags |= TrustRawMessage 576 } else { 577 enc.flags &= ^TrustRawMessage 578 } 579 } 580 581 // SetAppendNewline is an extension to the standard encoding/json package which 582 // allows the program to toggle the addition of a newline in Encode on or off. 583 func (enc *Encoder) SetAppendNewline(on bool) { 584 if on { 585 enc.flags |= appendNewline 586 } else { 587 enc.flags &= ^appendNewline 588 } 589 } 590 591 var encoderBufferPool = sync.Pool{ 592 New: func() interface{} { return &encoderBuffer{data: make([]byte, 0, 4096)} }, 593 } 594 595 type encoderBuffer struct{ data []byte }