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