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 }