...
Run Format

Source file src/encoding/json/encode.go

  // Copyright 2010 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  // Package json implements encoding and decoding of JSON as defined in
  // RFC 4627. The mapping between JSON and Go values is described
  // in the documentation for the Marshal and Unmarshal functions.
  //
  // See "JSON and Go" for an introduction to this package:
  // https://golang.org/doc/articles/json_and_go.html
  package json
  
  import (
  	"bytes"
  	"encoding"
  	"encoding/base64"
  	"fmt"
  	"math"
  	"reflect"
  	"runtime"
  	"sort"
  	"strconv"
  	"strings"
  	"sync"
  	"sync/atomic"
  	"unicode"
  	"unicode/utf8"
  )
  
  // Marshal returns the JSON encoding of v.
  //
  // Marshal traverses the value v recursively.
  // If an encountered value implements the Marshaler interface
  // and is not a nil pointer, Marshal calls its MarshalJSON method
  // to produce JSON. If no MarshalJSON method is present but the
  // value implements encoding.TextMarshaler instead, Marshal calls
  // its MarshalText method and encodes the result as a JSON string.
  // The nil pointer exception is not strictly necessary
  // but mimics a similar, necessary exception in the behavior of
  // UnmarshalJSON.
  //
  // Otherwise, Marshal uses the following type-dependent default encodings:
  //
  // Boolean values encode as JSON booleans.
  //
  // Floating point, integer, and Number values encode as JSON numbers.
  //
  // String values encode as JSON strings coerced to valid UTF-8,
  // replacing invalid bytes with the Unicode replacement rune.
  // The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
  // to keep some browsers from misinterpreting JSON output as HTML.
  // Ampersand "&" is also escaped to "\u0026" for the same reason.
  // This escaping can be disabled using an Encoder that had SetEscapeHTML(false)
  // called on it.
  //
  // Array and slice values encode as JSON arrays, except that
  // []byte encodes as a base64-encoded string, and a nil slice
  // encodes as the null JSON value.
  //
  // Struct values encode as JSON objects.
  // Each exported struct field becomes a member of the object, using the
  // field name as the object key, unless the field is omitted for one of the
  // reasons given below.
  //
  // The encoding of each struct field can be customized by the format string
  // stored under the "json" key in the struct field's tag.
  // The format string gives the name of the field, possibly followed by a
  // comma-separated list of options. The name may be empty in order to
  // specify options without overriding the default field name.
  //
  // The "omitempty" option specifies that the field should be omitted
  // from the encoding if the field has an empty value, defined as
  // false, 0, a nil pointer, a nil interface value, and any empty array,
  // slice, map, or string.
  //
  // As a special case, if the field tag is "-", the field is always omitted.
  // Note that a field with name "-" can still be generated using the tag "-,".
  //
  // Examples of struct field tags and their meanings:
  //
  //   // Field appears in JSON as key "myName".
  //   Field int `json:"myName"`
  //
  //   // Field appears in JSON as key "myName" and
  //   // the field is omitted from the object if its value is empty,
  //   // as defined above.
  //   Field int `json:"myName,omitempty"`
  //
  //   // Field appears in JSON as key "Field" (the default), but
  //   // the field is skipped if empty.
  //   // Note the leading comma.
  //   Field int `json:",omitempty"`
  //
  //   // Field is ignored by this package.
  //   Field int `json:"-"`
  //
  //   // Field appears in JSON as key "-".
  //   Field int `json:"-,"`
  //
  // The "string" option signals that a field is stored as JSON inside a
  // JSON-encoded string. It applies only to fields of string, floating point,
  // integer, or boolean types. This extra level of encoding is sometimes used
  // when communicating with JavaScript programs:
  //
  //    Int64String int64 `json:",string"`
  //
  // The key name will be used if it's a non-empty string consisting of
  // only Unicode letters, digits, and ASCII punctuation except quotation
  // marks, backslash, and comma.
  //
  // Anonymous struct fields are usually marshaled as if their inner exported fields
  // were fields in the outer struct, subject to the usual Go visibility rules amended
  // as described in the next paragraph.
  // An anonymous struct field with a name given in its JSON tag is treated as
  // having that name, rather than being anonymous.
  // An anonymous struct field of interface type is treated the same as having
  // that type as its name, rather than being anonymous.
  //
  // The Go visibility rules for struct fields are amended for JSON when
  // deciding which field to marshal or unmarshal. If there are
  // multiple fields at the same level, and that level is the least
  // nested (and would therefore be the nesting level selected by the
  // usual Go rules), the following extra rules apply:
  //
  // 1) Of those fields, if any are JSON-tagged, only tagged fields are considered,
  // even if there are multiple untagged fields that would otherwise conflict.
  //
  // 2) If there is exactly one field (tagged or not according to the first rule), that is selected.
  //
  // 3) Otherwise there are multiple fields, and all are ignored; no error occurs.
  //
  // Handling of anonymous struct fields is new in Go 1.1.
  // Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of
  // an anonymous struct field in both current and earlier versions, give the field
  // a JSON tag of "-".
  //
  // Map values encode as JSON objects. The map's key type must either be a
  // string, an integer type, or implement encoding.TextMarshaler. The map keys
  // are sorted and used as JSON object keys by applying the following rules,
  // subject to the UTF-8 coercion described for string values above:
  //   - string keys are used directly
  //   - encoding.TextMarshalers are marshaled
  //   - integer keys are converted to strings
  //
  // Pointer values encode as the value pointed to.
  // A nil pointer encodes as the null JSON value.
  //
  // Interface values encode as the value contained in the interface.
  // A nil interface value encodes as the null JSON value.
  //
  // Channel, complex, and function values cannot be encoded in JSON.
  // Attempting to encode such a value causes Marshal to return
  // an UnsupportedTypeError.
  //
  // JSON cannot represent cyclic data structures and Marshal does not
  // handle them. Passing cyclic structures to Marshal will result in
  // an infinite recursion.
  //
  func Marshal(v interface{}) ([]byte, error) {
  	e := &encodeState{}
  	err := e.marshal(v, encOpts{escapeHTML: true})
  	if err != nil {
  		return nil, err
  	}
  	return e.Bytes(), nil
  }
  
  // MarshalIndent is like Marshal but applies Indent to format the output.
  func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
  	b, err := Marshal(v)
  	if err != nil {
  		return nil, err
  	}
  	var buf bytes.Buffer
  	err = Indent(&buf, b, prefix, indent)
  	if err != nil {
  		return nil, err
  	}
  	return buf.Bytes(), nil
  }
  
  // HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
  // characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029
  // so that the JSON will be safe to embed inside HTML <script> tags.
  // For historical reasons, web browsers don't honor standard HTML
  // escaping within <script> tags, so an alternative JSON encoding must
  // be used.
  func HTMLEscape(dst *bytes.Buffer, src []byte) {
  	// The characters can only appear in string literals,
  	// so just scan the string one byte at a time.
  	start := 0
  	for i, c := range src {
  		if c == '<' || c == '>' || c == '&' {
  			if start < i {
  				dst.Write(src[start:i])
  			}
  			dst.WriteString(`\u00`)
  			dst.WriteByte(hex[c>>4])
  			dst.WriteByte(hex[c&0xF])
  			start = i + 1
  		}
  		// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
  		if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
  			if start < i {
  				dst.Write(src[start:i])
  			}
  			dst.WriteString(`\u202`)
  			dst.WriteByte(hex[src[i+2]&0xF])
  			start = i + 3
  		}
  	}
  	if start < len(src) {
  		dst.Write(src[start:])
  	}
  }
  
  // Marshaler is the interface implemented by types that
  // can marshal themselves into valid JSON.
  type Marshaler interface {
  	MarshalJSON() ([]byte, error)
  }
  
  // An UnsupportedTypeError is returned by Marshal when attempting
  // to encode an unsupported value type.
  type UnsupportedTypeError struct {
  	Type reflect.Type
  }
  
  func (e *UnsupportedTypeError) Error() string {
  	return "json: unsupported type: " + e.Type.String()
  }
  
  type UnsupportedValueError struct {
  	Value reflect.Value
  	Str   string
  }
  
  func (e *UnsupportedValueError) Error() string {
  	return "json: unsupported value: " + e.Str
  }
  
  // Before Go 1.2, an InvalidUTF8Error was returned by Marshal when
  // attempting to encode a string value with invalid UTF-8 sequences.
  // As of Go 1.2, Marshal instead coerces the string to valid UTF-8 by
  // replacing invalid bytes with the Unicode replacement rune U+FFFD.
  // This error is no longer generated but is kept for backwards compatibility
  // with programs that might mention it.
  type InvalidUTF8Error struct {
  	S string // the whole string value that caused the error
  }
  
  func (e *InvalidUTF8Error) Error() string {
  	return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
  }
  
  type MarshalerError struct {
  	Type reflect.Type
  	Err  error
  }
  
  func (e *MarshalerError) Error() string {
  	return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Err.Error()
  }
  
  var hex = "0123456789abcdef"
  
  // An encodeState encodes JSON into a bytes.Buffer.
  type encodeState struct {
  	bytes.Buffer // accumulated output
  	scratch      [64]byte
  }
  
  var encodeStatePool sync.Pool
  
  func newEncodeState() *encodeState {
  	if v := encodeStatePool.Get(); v != nil {
  		e := v.(*encodeState)
  		e.Reset()
  		return e
  	}
  	return new(encodeState)
  }
  
  func (e *encodeState) marshal(v interface{}, opts encOpts) (err error) {
  	defer func() {
  		if r := recover(); r != nil {
  			if _, ok := r.(runtime.Error); ok {
  				panic(r)
  			}
  			if s, ok := r.(string); ok {
  				panic(s)
  			}
  			err = r.(error)
  		}
  	}()
  	e.reflectValue(reflect.ValueOf(v), opts)
  	return nil
  }
  
  func (e *encodeState) error(err error) {
  	panic(err)
  }
  
  func isEmptyValue(v reflect.Value) bool {
  	switch v.Kind() {
  	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
  		return v.Len() == 0
  	case reflect.Bool:
  		return !v.Bool()
  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  		return v.Int() == 0
  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  		return v.Uint() == 0
  	case reflect.Float32, reflect.Float64:
  		return v.Float() == 0
  	case reflect.Interface, reflect.Ptr:
  		return v.IsNil()
  	}
  	return false
  }
  
  func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) {
  	valueEncoder(v)(e, v, opts)
  }
  
  type encOpts struct {
  	// quoted causes primitive fields to be encoded inside JSON strings.
  	quoted bool
  	// escapeHTML causes '<', '>', and '&' to be escaped in JSON strings.
  	escapeHTML bool
  }
  
  type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts)
  
  var encoderCache struct {
  	sync.RWMutex
  	m map[reflect.Type]encoderFunc
  }
  
  func valueEncoder(v reflect.Value) encoderFunc {
  	if !v.IsValid() {
  		return invalidValueEncoder
  	}
  	return typeEncoder(v.Type())
  }
  
  func typeEncoder(t reflect.Type) encoderFunc {
  	encoderCache.RLock()
  	f := encoderCache.m[t]
  	encoderCache.RUnlock()
  	if f != nil {
  		return f
  	}
  
  	// To deal with recursive types, populate the map with an
  	// indirect func before we build it. This type waits on the
  	// real func (f) to be ready and then calls it. This indirect
  	// func is only used for recursive types.
  	encoderCache.Lock()
  	if encoderCache.m == nil {
  		encoderCache.m = make(map[reflect.Type]encoderFunc)
  	}
  	var wg sync.WaitGroup
  	wg.Add(1)
  	encoderCache.m[t] = func(e *encodeState, v reflect.Value, opts encOpts) {
  		wg.Wait()
  		f(e, v, opts)
  	}
  	encoderCache.Unlock()
  
  	// Compute fields without lock.
  	// Might duplicate effort but won't hold other computations back.
  	f = newTypeEncoder(t, true)
  	wg.Done()
  	encoderCache.Lock()
  	encoderCache.m[t] = f
  	encoderCache.Unlock()
  	return f
  }
  
  var (
  	marshalerType     = reflect.TypeOf(new(Marshaler)).Elem()
  	textMarshalerType = reflect.TypeOf(new(encoding.TextMarshaler)).Elem()
  )
  
  // newTypeEncoder constructs an encoderFunc for a type.
  // The returned encoder only checks CanAddr when allowAddr is true.
  func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
  	if t.Implements(marshalerType) {
  		return marshalerEncoder
  	}
  	if t.Kind() != reflect.Ptr && allowAddr {
  		if reflect.PtrTo(t).Implements(marshalerType) {
  			return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false))
  		}
  	}
  
  	if t.Implements(textMarshalerType) {
  		return textMarshalerEncoder
  	}
  	if t.Kind() != reflect.Ptr && allowAddr {
  		if reflect.PtrTo(t).Implements(textMarshalerType) {
  			return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false))
  		}
  	}
  
  	switch t.Kind() {
  	case reflect.Bool:
  		return boolEncoder
  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  		return intEncoder
  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  		return uintEncoder
  	case reflect.Float32:
  		return float32Encoder
  	case reflect.Float64:
  		return float64Encoder
  	case reflect.String:
  		return stringEncoder
  	case reflect.Interface:
  		return interfaceEncoder
  	case reflect.Struct:
  		return newStructEncoder(t)
  	case reflect.Map:
  		return newMapEncoder(t)
  	case reflect.Slice:
  		return newSliceEncoder(t)
  	case reflect.Array:
  		return newArrayEncoder(t)
  	case reflect.Ptr:
  		return newPtrEncoder(t)
  	default:
  		return unsupportedTypeEncoder
  	}
  }
  
  func invalidValueEncoder(e *encodeState, v reflect.Value, _ encOpts) {
  	e.WriteString("null")
  }
  
  func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
  	if v.Kind() == reflect.Ptr && v.IsNil() {
  		e.WriteString("null")
  		return
  	}
  	m, ok := v.Interface().(Marshaler)
  	if !ok {
  		e.WriteString("null")
  		return
  	}
  	b, err := m.MarshalJSON()
  	if err == nil {
  		// copy JSON into buffer, checking validity.
  		err = compact(&e.Buffer, b, opts.escapeHTML)
  	}
  	if err != nil {
  		e.error(&MarshalerError{v.Type(), err})
  	}
  }
  
  func addrMarshalerEncoder(e *encodeState, v reflect.Value, _ encOpts) {
  	va := v.Addr()
  	if va.IsNil() {
  		e.WriteString("null")
  		return
  	}
  	m := va.Interface().(Marshaler)
  	b, err := m.MarshalJSON()
  	if err == nil {
  		// copy JSON into buffer, checking validity.
  		err = compact(&e.Buffer, b, true)
  	}
  	if err != nil {
  		e.error(&MarshalerError{v.Type(), err})
  	}
  }
  
  func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
  	if v.Kind() == reflect.Ptr && v.IsNil() {
  		e.WriteString("null")
  		return
  	}
  	m := v.Interface().(encoding.TextMarshaler)
  	b, err := m.MarshalText()
  	if err != nil {
  		e.error(&MarshalerError{v.Type(), err})
  	}
  	e.stringBytes(b, opts.escapeHTML)
  }
  
  func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
  	va := v.Addr()
  	if va.IsNil() {
  		e.WriteString("null")
  		return
  	}
  	m := va.Interface().(encoding.TextMarshaler)
  	b, err := m.MarshalText()
  	if err != nil {
  		e.error(&MarshalerError{v.Type(), err})
  	}
  	e.stringBytes(b, opts.escapeHTML)
  }
  
  func boolEncoder(e *encodeState, v reflect.Value, opts encOpts) {
  	if opts.quoted {
  		e.WriteByte('"')
  	}
  	if v.Bool() {
  		e.WriteString("true")
  	} else {
  		e.WriteString("false")
  	}
  	if opts.quoted {
  		e.WriteByte('"')
  	}
  }
  
  func intEncoder(e *encodeState, v reflect.Value, opts encOpts) {
  	b := strconv.AppendInt(e.scratch[:0], v.Int(), 10)
  	if opts.quoted {
  		e.WriteByte('"')
  	}
  	e.Write(b)
  	if opts.quoted {
  		e.WriteByte('"')
  	}
  }
  
  func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) {
  	b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10)
  	if opts.quoted {
  		e.WriteByte('"')
  	}
  	e.Write(b)
  	if opts.quoted {
  		e.WriteByte('"')
  	}
  }
  
  type floatEncoder int // number of bits
  
  func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
  	f := v.Float()
  	if math.IsInf(f, 0) || math.IsNaN(f) {
  		e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))})
  	}
  
  	// Convert as if by ES6 number to string conversion.
  	// This matches most other JSON generators.
  	// See golang.org/issue/6384 and golang.org/issue/14135.
  	// Like fmt %g, but the exponent cutoffs are different
  	// and exponents themselves are not padded to two digits.
  	b := e.scratch[:0]
  	abs := math.Abs(f)
  	fmt := byte('f')
  	// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
  	if abs != 0 {
  		if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
  			fmt = 'e'
  		}
  	}
  	b = strconv.AppendFloat(b, f, fmt, -1, int(bits))
  	if fmt == 'e' {
  		// clean up e-09 to e-9
  		n := len(b)
  		if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' {
  			b[n-2] = b[n-1]
  			b = b[:n-1]
  		}
  	}
  
  	if opts.quoted {
  		e.WriteByte('"')
  	}
  	e.Write(b)
  	if opts.quoted {
  		e.WriteByte('"')
  	}
  }
  
  var (
  	float32Encoder = (floatEncoder(32)).encode
  	float64Encoder = (floatEncoder(64)).encode
  )
  
  func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) {
  	if v.Type() == numberType {
  		numStr := v.String()
  		// In Go1.5 the empty string encodes to "0", while this is not a valid number literal
  		// we keep compatibility so check validity after this.
  		if numStr == "" {
  			numStr = "0" // Number's zero-val
  		}
  		if !isValidNumber(numStr) {
  			e.error(fmt.Errorf("json: invalid number literal %q", numStr))
  		}
  		e.WriteString(numStr)
  		return
  	}
  	if opts.quoted {
  		sb, err := Marshal(v.String())
  		if err != nil {
  			e.error(err)
  		}
  		e.string(string(sb), opts.escapeHTML)
  	} else {
  		e.string(v.String(), opts.escapeHTML)
  	}
  }
  
  func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) {
  	if v.IsNil() {
  		e.WriteString("null")
  		return
  	}
  	e.reflectValue(v.Elem(), opts)
  }
  
  func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) {
  	e.error(&UnsupportedTypeError{v.Type()})
  }
  
  type structEncoder struct {
  	fields    []field
  	fieldEncs []encoderFunc
  }
  
  func (se *structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
  	e.WriteByte('{')
  	first := true
  	for i, f := range se.fields {
  		fv := fieldByIndex(v, f.index)
  		if !fv.IsValid() || f.omitEmpty && isEmptyValue(fv) {
  			continue
  		}
  		if first {
  			first = false
  		} else {
  			e.WriteByte(',')
  		}
  		e.string(f.name, opts.escapeHTML)
  		e.WriteByte(':')
  		opts.quoted = f.quoted
  		se.fieldEncs[i](e, fv, opts)
  	}
  	e.WriteByte('}')
  }
  
  func newStructEncoder(t reflect.Type) encoderFunc {
  	fields := cachedTypeFields(t)
  	se := &structEncoder{
  		fields:    fields,
  		fieldEncs: make([]encoderFunc, len(fields)),
  	}
  	for i, f := range fields {
  		se.fieldEncs[i] = typeEncoder(typeByIndex(t, f.index))
  	}
  	return se.encode
  }
  
  type mapEncoder struct {
  	elemEnc encoderFunc
  }
  
  func (me *mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
  	if v.IsNil() {
  		e.WriteString("null")
  		return
  	}
  	e.WriteByte('{')
  
  	// Extract and sort the keys.
  	keys := v.MapKeys()
  	sv := make([]reflectWithString, len(keys))
  	for i, v := range keys {
  		sv[i].v = v
  		if err := sv[i].resolve(); err != nil {
  			e.error(&MarshalerError{v.Type(), err})
  		}
  	}
  	sort.Slice(sv, func(i, j int) bool { return sv[i].s < sv[j].s })
  
  	for i, kv := range sv {
  		if i > 0 {
  			e.WriteByte(',')
  		}
  		e.string(kv.s, opts.escapeHTML)
  		e.WriteByte(':')
  		me.elemEnc(e, v.MapIndex(kv.v), opts)
  	}
  	e.WriteByte('}')
  }
  
  func newMapEncoder(t reflect.Type) encoderFunc {
  	switch t.Key().Kind() {
  	case reflect.String,
  		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  	default:
  		if !t.Key().Implements(textMarshalerType) {
  			return unsupportedTypeEncoder
  		}
  	}
  	me := &mapEncoder{typeEncoder(t.Elem())}
  	return me.encode
  }
  
  func encodeByteSlice(e *encodeState, v reflect.Value, _ encOpts) {
  	if v.IsNil() {
  		e.WriteString("null")
  		return
  	}
  	s := v.Bytes()
  	e.WriteByte('"')
  	if len(s) < 1024 {
  		// for small buffers, using Encode directly is much faster.
  		dst := make([]byte, base64.StdEncoding.EncodedLen(len(s)))
  		base64.StdEncoding.Encode(dst, s)
  		e.Write(dst)
  	} else {
  		// for large buffers, avoid unnecessary extra temporary
  		// buffer space.
  		enc := base64.NewEncoder(base64.StdEncoding, e)
  		enc.Write(s)
  		enc.Close()
  	}
  	e.WriteByte('"')
  }
  
  // sliceEncoder just wraps an arrayEncoder, checking to make sure the value isn't nil.
  type sliceEncoder struct {
  	arrayEnc encoderFunc
  }
  
  func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
  	if v.IsNil() {
  		e.WriteString("null")
  		return
  	}
  	se.arrayEnc(e, v, opts)
  }
  
  func newSliceEncoder(t reflect.Type) encoderFunc {
  	// Byte slices get special treatment; arrays don't.
  	if t.Elem().Kind() == reflect.Uint8 {
  		p := reflect.PtrTo(t.Elem())
  		if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) {
  			return encodeByteSlice
  		}
  	}
  	enc := &sliceEncoder{newArrayEncoder(t)}
  	return enc.encode
  }
  
  type arrayEncoder struct {
  	elemEnc encoderFunc
  }
  
  func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
  	e.WriteByte('[')
  	n := v.Len()
  	for i := 0; i < n; i++ {
  		if i > 0 {
  			e.WriteByte(',')
  		}
  		ae.elemEnc(e, v.Index(i), opts)
  	}
  	e.WriteByte(']')
  }
  
  func newArrayEncoder(t reflect.Type) encoderFunc {
  	enc := &arrayEncoder{typeEncoder(t.Elem())}
  	return enc.encode
  }
  
  type ptrEncoder struct {
  	elemEnc encoderFunc
  }
  
  func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
  	if v.IsNil() {
  		e.WriteString("null")
  		return
  	}
  	pe.elemEnc(e, v.Elem(), opts)
  }
  
  func newPtrEncoder(t reflect.Type) encoderFunc {
  	enc := &ptrEncoder{typeEncoder(t.Elem())}
  	return enc.encode
  }
  
  type condAddrEncoder struct {
  	canAddrEnc, elseEnc encoderFunc
  }
  
  func (ce *condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
  	if v.CanAddr() {
  		ce.canAddrEnc(e, v, opts)
  	} else {
  		ce.elseEnc(e, v, opts)
  	}
  }
  
  // newCondAddrEncoder returns an encoder that checks whether its value
  // CanAddr and delegates to canAddrEnc if so, else to elseEnc.
  func newCondAddrEncoder(canAddrEnc, elseEnc encoderFunc) encoderFunc {
  	enc := &condAddrEncoder{canAddrEnc: canAddrEnc, elseEnc: elseEnc}
  	return enc.encode
  }
  
  func isValidTag(s string) bool {
  	if s == "" {
  		return false
  	}
  	for _, c := range s {
  		switch {
  		case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
  			// Backslash and quote chars are reserved, but
  			// otherwise any punctuation chars are allowed
  			// in a tag name.
  		default:
  			if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
  				return false
  			}
  		}
  	}
  	return true
  }
  
  func fieldByIndex(v reflect.Value, index []int) reflect.Value {
  	for _, i := range index {
  		if v.Kind() == reflect.Ptr {
  			if v.IsNil() {
  				return reflect.Value{}
  			}
  			v = v.Elem()
  		}
  		v = v.Field(i)
  	}
  	return v
  }
  
  func typeByIndex(t reflect.Type, index []int) reflect.Type {
  	for _, i := range index {
  		if t.Kind() == reflect.Ptr {
  			t = t.Elem()
  		}
  		t = t.Field(i).Type
  	}
  	return t
  }
  
  type reflectWithString struct {
  	v reflect.Value
  	s string
  }
  
  func (w *reflectWithString) resolve() error {
  	if w.v.Kind() == reflect.String {
  		w.s = w.v.String()
  		return nil
  	}
  	if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok {
  		buf, err := tm.MarshalText()
  		w.s = string(buf)
  		return err
  	}
  	switch w.v.Kind() {
  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  		w.s = strconv.FormatInt(w.v.Int(), 10)
  		return nil
  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  		w.s = strconv.FormatUint(w.v.Uint(), 10)
  		return nil
  	}
  	panic("unexpected map key type")
  }
  
  // NOTE: keep in sync with stringBytes below.
  func (e *encodeState) string(s string, escapeHTML bool) int {
  	len0 := e.Len()
  	e.WriteByte('"')
  	start := 0
  	for i := 0; i < len(s); {
  		if b := s[i]; b < utf8.RuneSelf {
  			if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
  				i++
  				continue
  			}
  			if start < i {
  				e.WriteString(s[start:i])
  			}
  			switch b {
  			case '\\', '"':
  				e.WriteByte('\\')
  				e.WriteByte(b)
  			case '\n':
  				e.WriteByte('\\')
  				e.WriteByte('n')
  			case '\r':
  				e.WriteByte('\\')
  				e.WriteByte('r')
  			case '\t':
  				e.WriteByte('\\')
  				e.WriteByte('t')
  			default:
  				// This encodes bytes < 0x20 except for \t, \n and \r.
  				// If escapeHTML is set, it also escapes <, >, and &
  				// because they can lead to security holes when
  				// user-controlled strings are rendered into JSON
  				// and served to some browsers.
  				e.WriteString(`\u00`)
  				e.WriteByte(hex[b>>4])
  				e.WriteByte(hex[b&0xF])
  			}
  			i++
  			start = i
  			continue
  		}
  		c, size := utf8.DecodeRuneInString(s[i:])
  		if c == utf8.RuneError && size == 1 {
  			if start < i {
  				e.WriteString(s[start:i])
  			}
  			e.WriteString(`\ufffd`)
  			i += size
  			start = i
  			continue
  		}
  		// U+2028 is LINE SEPARATOR.
  		// U+2029 is PARAGRAPH SEPARATOR.
  		// They are both technically valid characters in JSON strings,
  		// but don't work in JSONP, which has to be evaluated as JavaScript,
  		// and can lead to security holes there. It is valid JSON to
  		// escape them, so we do so unconditionally.
  		// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
  		if c == '\u2028' || c == '\u2029' {
  			if start < i {
  				e.WriteString(s[start:i])
  			}
  			e.WriteString(`\u202`)
  			e.WriteByte(hex[c&0xF])
  			i += size
  			start = i
  			continue
  		}
  		i += size
  	}
  	if start < len(s) {
  		e.WriteString(s[start:])
  	}
  	e.WriteByte('"')
  	return e.Len() - len0
  }
  
  // NOTE: keep in sync with string above.
  func (e *encodeState) stringBytes(s []byte, escapeHTML bool) int {
  	len0 := e.Len()
  	e.WriteByte('"')
  	start := 0
  	for i := 0; i < len(s); {
  		if b := s[i]; b < utf8.RuneSelf {
  			if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
  				i++
  				continue
  			}
  			if start < i {
  				e.Write(s[start:i])
  			}
  			switch b {
  			case '\\', '"':
  				e.WriteByte('\\')
  				e.WriteByte(b)
  			case '\n':
  				e.WriteByte('\\')
  				e.WriteByte('n')
  			case '\r':
  				e.WriteByte('\\')
  				e.WriteByte('r')
  			case '\t':
  				e.WriteByte('\\')
  				e.WriteByte('t')
  			default:
  				// This encodes bytes < 0x20 except for \t, \n and \r.
  				// If escapeHTML is set, it also escapes <, >, and &
  				// because they can lead to security holes when
  				// user-controlled strings are rendered into JSON
  				// and served to some browsers.
  				e.WriteString(`\u00`)
  				e.WriteByte(hex[b>>4])
  				e.WriteByte(hex[b&0xF])
  			}
  			i++
  			start = i
  			continue
  		}
  		c, size := utf8.DecodeRune(s[i:])
  		if c == utf8.RuneError && size == 1 {
  			if start < i {
  				e.Write(s[start:i])
  			}
  			e.WriteString(`\ufffd`)
  			i += size
  			start = i
  			continue
  		}
  		// U+2028 is LINE SEPARATOR.
  		// U+2029 is PARAGRAPH SEPARATOR.
  		// They are both technically valid characters in JSON strings,
  		// but don't work in JSONP, which has to be evaluated as JavaScript,
  		// and can lead to security holes there. It is valid JSON to
  		// escape them, so we do so unconditionally.
  		// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
  		if c == '\u2028' || c == '\u2029' {
  			if start < i {
  				e.Write(s[start:i])
  			}
  			e.WriteString(`\u202`)
  			e.WriteByte(hex[c&0xF])
  			i += size
  			start = i
  			continue
  		}
  		i += size
  	}
  	if start < len(s) {
  		e.Write(s[start:])
  	}
  	e.WriteByte('"')
  	return e.Len() - len0
  }
  
  // A field represents a single field found in a struct.
  type field struct {
  	name      string
  	nameBytes []byte                 // []byte(name)
  	equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent
  
  	tag       bool
  	index     []int
  	typ       reflect.Type
  	omitEmpty bool
  	quoted    bool
  }
  
  func fillField(f field) field {
  	f.nameBytes = []byte(f.name)
  	f.equalFold = foldFunc(f.nameBytes)
  	return f
  }
  
  // byIndex sorts field by index sequence.
  type byIndex []field
  
  func (x byIndex) Len() int { return len(x) }
  
  func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
  
  func (x byIndex) Less(i, j int) bool {
  	for k, xik := range x[i].index {
  		if k >= len(x[j].index) {
  			return false
  		}
  		if xik != x[j].index[k] {
  			return xik < x[j].index[k]
  		}
  	}
  	return len(x[i].index) < len(x[j].index)
  }
  
  // typeFields returns a list of fields that JSON should recognize for the given type.
  // The algorithm is breadth-first search over the set of structs to include - the top struct
  // and then any reachable anonymous structs.
  func typeFields(t reflect.Type) []field {
  	// Anonymous fields to explore at the current level and the next.
  	current := []field{}
  	next := []field{{typ: t}}
  
  	// Count of queued names for current level and the next.
  	count := map[reflect.Type]int{}
  	nextCount := map[reflect.Type]int{}
  
  	// Types already visited at an earlier level.
  	visited := map[reflect.Type]bool{}
  
  	// Fields found.
  	var fields []field
  
  	for len(next) > 0 {
  		current, next = next, current[:0]
  		count, nextCount = nextCount, map[reflect.Type]int{}
  
  		for _, f := range current {
  			if visited[f.typ] {
  				continue
  			}
  			visited[f.typ] = true
  
  			// Scan f.typ for fields to include.
  			for i := 0; i < f.typ.NumField(); i++ {
  				sf := f.typ.Field(i)
  				if sf.PkgPath != "" && !sf.Anonymous { // unexported
  					continue
  				}
  				tag := sf.Tag.Get("json")
  				if tag == "-" {
  					continue
  				}
  				name, opts := parseTag(tag)
  				if !isValidTag(name) {
  					name = ""
  				}
  				index := make([]int, len(f.index)+1)
  				copy(index, f.index)
  				index[len(f.index)] = i
  
  				ft := sf.Type
  				if ft.Name() == "" && ft.Kind() == reflect.Ptr {
  					// Follow pointer.
  					ft = ft.Elem()
  				}
  
  				// Only strings, floats, integers, and booleans can be quoted.
  				quoted := false
  				if opts.Contains("string") {
  					switch ft.Kind() {
  					case reflect.Bool,
  						reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  						reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
  						reflect.Float32, reflect.Float64,
  						reflect.String:
  						quoted = true
  					}
  				}
  
  				// Record found field and index sequence.
  				if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
  					tagged := name != ""
  					if name == "" {
  						name = sf.Name
  					}
  					fields = append(fields, fillField(field{
  						name:      name,
  						tag:       tagged,
  						index:     index,
  						typ:       ft,
  						omitEmpty: opts.Contains("omitempty"),
  						quoted:    quoted,
  					}))
  					if count[f.typ] > 1 {
  						// If there were multiple instances, add a second,
  						// so that the annihilation code will see a duplicate.
  						// It only cares about the distinction between 1 or 2,
  						// so don't bother generating any more copies.
  						fields = append(fields, fields[len(fields)-1])
  					}
  					continue
  				}
  
  				// Record new anonymous struct to explore in next round.
  				nextCount[ft]++
  				if nextCount[ft] == 1 {
  					next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft}))
  				}
  			}
  		}
  	}
  
  	sort.Slice(fields, func(i, j int) bool {
  		x := fields
  		// sort field by name, breaking ties with depth, then
  		// breaking ties with "name came from json tag", then
  		// breaking ties with index sequence.
  		if x[i].name != x[j].name {
  			return x[i].name < x[j].name
  		}
  		if len(x[i].index) != len(x[j].index) {
  			return len(x[i].index) < len(x[j].index)
  		}
  		if x[i].tag != x[j].tag {
  			return x[i].tag
  		}
  		return byIndex(x).Less(i, j)
  	})
  
  	// Delete all fields that are hidden by the Go rules for embedded fields,
  	// except that fields with JSON tags are promoted.
  
  	// The fields are sorted in primary order of name, secondary order
  	// of field index length. Loop over names; for each name, delete
  	// hidden fields by choosing the one dominant field that survives.
  	out := fields[:0]
  	for advance, i := 0, 0; i < len(fields); i += advance {
  		// One iteration per name.
  		// Find the sequence of fields with the name of this first field.
  		fi := fields[i]
  		name := fi.name
  		for advance = 1; i+advance < len(fields); advance++ {
  			fj := fields[i+advance]
  			if fj.name != name {
  				break
  			}
  		}
  		if advance == 1 { // Only one field with this name
  			out = append(out, fi)
  			continue
  		}
  		dominant, ok := dominantField(fields[i : i+advance])
  		if ok {
  			out = append(out, dominant)
  		}
  	}
  
  	fields = out
  	sort.Sort(byIndex(fields))
  
  	return fields
  }
  
  // dominantField looks through the fields, all of which are known to
  // have the same name, to find the single field that dominates the
  // others using Go's embedding rules, modified by the presence of
  // JSON tags. If there are multiple top-level fields, the boolean
  // will be false: This condition is an error in Go and we skip all
  // the fields.
  func dominantField(fields []field) (field, bool) {
  	// The fields are sorted in increasing index-length order. The winner
  	// must therefore be one with the shortest index length. Drop all
  	// longer entries, which is easy: just truncate the slice.
  	length := len(fields[0].index)
  	tagged := -1 // Index of first tagged field.
  	for i, f := range fields {
  		if len(f.index) > length {
  			fields = fields[:i]
  			break
  		}
  		if f.tag {
  			if tagged >= 0 {
  				// Multiple tagged fields at the same level: conflict.
  				// Return no field.
  				return field{}, false
  			}
  			tagged = i
  		}
  	}
  	if tagged >= 0 {
  		return fields[tagged], true
  	}
  	// All remaining fields have the same length. If there's more than one,
  	// we have a conflict (two fields named "X" at the same level) and we
  	// return no field.
  	if len(fields) > 1 {
  		return field{}, false
  	}
  	return fields[0], true
  }
  
  var fieldCache struct {
  	value atomic.Value // map[reflect.Type][]field
  	mu    sync.Mutex   // used only by writers
  }
  
  // cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
  func cachedTypeFields(t reflect.Type) []field {
  	m, _ := fieldCache.value.Load().(map[reflect.Type][]field)
  	f := m[t]
  	if f != nil {
  		return f
  	}
  
  	// Compute fields without lock.
  	// Might duplicate effort but won't hold other computations back.
  	f = typeFields(t)
  	if f == nil {
  		f = []field{}
  	}
  
  	fieldCache.mu.Lock()
  	m, _ = fieldCache.value.Load().(map[reflect.Type][]field)
  	newM := make(map[reflect.Type][]field, len(m)+1)
  	for k, v := range m {
  		newM[k] = v
  	}
  	newM[t] = f
  	fieldCache.value.Store(newM)
  	fieldCache.mu.Unlock()
  	return f
  }
  

View as plain text