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 }