github.com/wI2L/jettison@v0.7.5-0.20230106001914-c70014c6417a/encode.go (about)

     1  package jettison
     2  
     3  import (
     4  	"bytes"
     5  	"encoding"
     6  	"encoding/base64"
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"math"
    11  	"reflect"
    12  	"runtime"
    13  	"sort"
    14  	"strconv"
    15  	"sync"
    16  	"time"
    17  	"unicode/utf8"
    18  	"unsafe"
    19  )
    20  
    21  const hex = "0123456789abcdef"
    22  
    23  //nolint:unparam
    24  func encodeBool(p unsafe.Pointer, dst []byte, _ encOpts) ([]byte, error) {
    25  	if *(*bool)(p) {
    26  		return append(dst, "true"...), nil
    27  	}
    28  	return append(dst, "false"...), nil
    29  }
    30  
    31  // encodeString appends the escaped bytes of the string
    32  // pointed by p to dst. If quoted is true, escaped double
    33  // quote characters are added at the beginning and the
    34  // end of the JSON string.
    35  // nolint:unparam
    36  func encodeString(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) {
    37  	dst = append(dst, '"')
    38  	dst = appendEscapedBytes(dst, sp2b(p), opts)
    39  	dst = append(dst, '"')
    40  
    41  	return dst, nil
    42  }
    43  
    44  //nolint:unparam
    45  func encodeQuotedString(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) {
    46  	dst = append(dst, `"\"`...)
    47  	dst = appendEscapedBytes(dst, sp2b(p), opts)
    48  	dst = append(dst, `\""`...)
    49  
    50  	return dst, nil
    51  }
    52  
    53  // encodeFloat32 appends the textual representation of
    54  // the 32-bits floating point number pointed by p to dst.
    55  func encodeFloat32(p unsafe.Pointer, dst []byte, _ encOpts) ([]byte, error) {
    56  	return appendFloat(dst, float64(*(*float32)(p)), 32)
    57  }
    58  
    59  // encodeFloat64 appends the textual representation of
    60  // the 64-bits floating point number pointed by p to dst.
    61  func encodeFloat64(p unsafe.Pointer, dst []byte, _ encOpts) ([]byte, error) {
    62  	return appendFloat(dst, *(*float64)(p), 64)
    63  }
    64  
    65  func encodeInterface(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) {
    66  	v := *(*interface{})(p)
    67  	if v == nil {
    68  		return append(dst, "null"...), nil
    69  	}
    70  	typ := reflect.TypeOf(v)
    71  	ins := cachedInstr(typ)
    72  
    73  	return ins(unpackEface(v).word, dst, opts)
    74  }
    75  
    76  func encodeNumber(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) {
    77  	// Cast pointer to string directly to avoid
    78  	// a useless conversion.
    79  	num := *(*string)(p)
    80  
    81  	// In Go1.5 the empty string encodes to "0".
    82  	// While this is not a valid number literal,
    83  	// we keep compatibility, so check validity
    84  	// after this.
    85  	if num == "" {
    86  		num = "0" // Number's zero-val
    87  	}
    88  	if !opts.flags.has(noNumberValidation) && !isValidNumber(num) {
    89  		return dst, fmt.Errorf("json: invalid number literal %q", num)
    90  	}
    91  	return append(dst, num...), nil
    92  }
    93  
    94  func encodeRawMessage(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) {
    95  	v := *(*json.RawMessage)(p)
    96  	if v == nil {
    97  		return append(dst, "null"...), nil
    98  	}
    99  	if opts.flags.has(noCompact) {
   100  		return append(dst, v...), nil
   101  	}
   102  	return appendCompactJSON(dst, v, !opts.flags.has(noHTMLEscaping))
   103  }
   104  
   105  // encodeTime appends the time.Time value pointed by
   106  // p to dst based on the format configured in opts.
   107  func encodeTime(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) {
   108  	t := *(*time.Time)(p)
   109  	y := t.Year()
   110  
   111  	if y < 0 || y >= 10000 {
   112  		// See comment golang.org/issue/4556#c15.
   113  		return dst, errors.New("time: year outside of range [0,9999]")
   114  	}
   115  	if opts.flags.has(unixTime) {
   116  		return strconv.AppendInt(dst, t.Unix(), 10), nil
   117  	}
   118  	switch opts.timeLayout {
   119  	case time.RFC3339:
   120  		return appendRFC3339Time(t, dst, false), nil
   121  	case time.RFC3339Nano:
   122  		return appendRFC3339Time(t, dst, true), nil
   123  	default:
   124  		dst = append(dst, '"')
   125  		dst = t.AppendFormat(dst, opts.timeLayout)
   126  		dst = append(dst, '"')
   127  		return dst, nil
   128  	}
   129  }
   130  
   131  // encodeDuration appends the time.Duration value pointed
   132  // by p to dst based on the format configured in opts.
   133  func encodeDuration(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) {
   134  	d := *(*time.Duration)(p)
   135  
   136  	switch opts.durationFmt {
   137  	default: // DurationNanoseconds
   138  		return strconv.AppendInt(dst, d.Nanoseconds(), 10), nil
   139  	case DurationMinutes:
   140  		return appendFloat(dst, d.Minutes(), 64)
   141  	case DurationSeconds:
   142  		return appendFloat(dst, d.Seconds(), 64)
   143  	case DurationMicroseconds:
   144  		return strconv.AppendInt(dst, int64(d)/1e3, 10), nil
   145  	case DurationMilliseconds:
   146  		return strconv.AppendInt(dst, int64(d)/1e6, 10), nil
   147  	case DurationString:
   148  		dst = append(dst, '"')
   149  		dst = appendDuration(dst, d)
   150  		dst = append(dst, '"')
   151  		return dst, nil
   152  	}
   153  }
   154  
   155  func appendFloat(dst []byte, f float64, bs int) ([]byte, error) {
   156  	if math.IsInf(f, 0) || math.IsNaN(f) {
   157  		return dst, &UnsupportedValueError{
   158  			reflect.ValueOf(f),
   159  			strconv.FormatFloat(f, 'g', -1, bs),
   160  		}
   161  	}
   162  	// Convert as it was an ES6 number to string conversion.
   163  	// This matches most other JSON generators. The following
   164  	// code is taken from the floatEncoder implementation of
   165  	// the encoding/json package of the Go standard library.
   166  	abs := math.Abs(f)
   167  	format := byte('f')
   168  	if abs != 0 {
   169  		if bs == 64 && (abs < 1e-6 || abs >= 1e21) ||
   170  			bs == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
   171  			format = 'e'
   172  		}
   173  	}
   174  	dst = strconv.AppendFloat(dst, f, format, -1, bs)
   175  	if format == 'e' {
   176  		n := len(dst)
   177  		if n >= 4 && dst[n-4] == 'e' && dst[n-3] == '-' && dst[n-2] == '0' {
   178  			dst[n-2] = dst[n-1]
   179  			dst = dst[:n-1]
   180  		}
   181  	}
   182  	return dst, nil
   183  }
   184  
   185  func encodePointer(p unsafe.Pointer, dst []byte, opts encOpts, ins instruction) ([]byte, error) {
   186  	if p = *(*unsafe.Pointer)(p); p != nil {
   187  		return ins(p, dst, opts)
   188  	}
   189  	return append(dst, "null"...), nil
   190  }
   191  
   192  func encodeStruct(
   193  	p unsafe.Pointer, dst []byte, opts encOpts, flds []field,
   194  ) ([]byte, error) {
   195  	var (
   196  		nxt = byte('{')
   197  		key []byte // key of the field
   198  	)
   199  	noHTMLEscape := opts.flags.has(noHTMLEscaping)
   200  
   201  fieldLoop:
   202  	for i := 0; i < len(flds); i++ {
   203  		f := &flds[i] // get pointer to prevent copy
   204  		if opts.isDeniedField(f.name) {
   205  			continue
   206  		}
   207  		fp := p
   208  
   209  		// Find the nested struct field by following
   210  		// the offset sequence, indirecting encountered
   211  		// pointers as needed.
   212  		for i := 0; i < len(f.embedSeq); i++ {
   213  			s := &f.embedSeq[i]
   214  			fp = unsafe.Pointer(uintptr(fp) + s.offset)
   215  			if s.indir {
   216  				if fp = *(*unsafe.Pointer)(fp); fp == nil {
   217  					// When we encounter a nil pointer
   218  					// in the chain, we have no choice
   219  					// but to ignore the field.
   220  					continue fieldLoop
   221  				}
   222  			}
   223  		}
   224  		// Ignore the field if it is a nil pointer and has
   225  		// the omitnil option in his tag.
   226  		if f.omitNil && *(*unsafe.Pointer)(fp) == nil {
   227  			continue
   228  		}
   229  		// Ignore the field if it represents the zero-value
   230  		// of its type and has the omitempty option in his tag.
   231  		// Empty func is non-nil only if the field has the
   232  		// omitempty option in its tag.
   233  		if f.omitEmpty && f.empty(fp) {
   234  			continue
   235  		}
   236  		key = f.keyEscHTML
   237  		if noHTMLEscape {
   238  			key = f.keyNonEsc
   239  		}
   240  		lastKeyOffset := len(dst)
   241  		dst = append(dst, nxt)
   242  		if nxt == '{' {
   243  			lastKeyOffset++
   244  		}
   245  		nxt = ','
   246  		dst = append(dst, key...)
   247  
   248  		var err error
   249  		if dst, err = f.instr(fp, dst, opts); err != nil {
   250  			return dst, err
   251  		}
   252  		if f.omitNullMarshaler && len(dst) > 4 && bytes.Compare(dst[len(dst)-4:], []byte("null")) == 0 {
   253  			dst = dst[:lastKeyOffset]
   254  		}
   255  	}
   256  	if nxt == '{' {
   257  		return append(dst, "{}"...), nil
   258  	}
   259  	return append(dst, '}'), nil
   260  }
   261  
   262  func encodeSlice(
   263  	p unsafe.Pointer, dst []byte, opts encOpts, ins instruction, es uintptr,
   264  ) ([]byte, error) {
   265  	shdr := (*sliceHeader)(p)
   266  	if shdr.Data == nil {
   267  		if opts.flags.has(nilSliceEmpty) {
   268  			return append(dst, "[]"...), nil
   269  		}
   270  		return append(dst, "null"...), nil
   271  	}
   272  	if shdr.Len == 0 {
   273  		return append(dst, "[]"...), nil
   274  	}
   275  	return encodeArray(shdr.Data, dst, opts, ins, es, shdr.Len, false)
   276  }
   277  
   278  // encodeByteSlice appends a byte slice to dst as
   279  // a JSON string. If the options flag rawByteSlice
   280  // is set, the escaped bytes are appended to the
   281  // buffer directly, otherwise in base64 form.
   282  // nolint:unparam
   283  func encodeByteSlice(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) {
   284  	b := *(*[]byte)(p)
   285  	if b == nil {
   286  		return append(dst, "null"...), nil
   287  	}
   288  	dst = append(dst, '"')
   289  
   290  	if opts.flags.has(rawByteSlice) {
   291  		dst = appendEscapedBytes(dst, b, opts)
   292  	} else {
   293  		n := base64.StdEncoding.EncodedLen(len(b))
   294  		if a := cap(dst) - len(dst); a < n {
   295  			new := make([]byte, cap(dst)+(n-a))
   296  			copy(new, dst)
   297  			dst = new[:len(dst)]
   298  		}
   299  		end := len(dst) + n
   300  		base64.StdEncoding.Encode(dst[len(dst):end], b)
   301  
   302  		dst = dst[:end]
   303  	}
   304  	return append(dst, '"'), nil
   305  }
   306  
   307  func encodeArray(
   308  	p unsafe.Pointer, dst []byte, opts encOpts, ins instruction, es uintptr, len int, isByteArray bool,
   309  ) ([]byte, error) {
   310  	if isByteArray && opts.flags.has(byteArrayAsString) {
   311  		return encodeByteArrayAsString(p, dst, opts, len), nil
   312  	}
   313  	var err error
   314  	nxt := byte('[')
   315  
   316  	for i := 0; i < len; i++ {
   317  		dst = append(dst, nxt)
   318  		nxt = ','
   319  		v := unsafe.Pointer(uintptr(p) + (uintptr(i) * es))
   320  		if dst, err = ins(v, dst, opts); err != nil {
   321  			return dst, err
   322  		}
   323  	}
   324  	if nxt == '[' {
   325  		return append(dst, "[]"...), nil
   326  	}
   327  	return append(dst, ']'), nil
   328  }
   329  
   330  // encodeByteArrayAsString appends the escaped
   331  // bytes of the byte array pointed by p to dst
   332  // as a JSON string.
   333  func encodeByteArrayAsString(p unsafe.Pointer, dst []byte, opts encOpts, len int) []byte {
   334  	// For byte type, size is guaranteed to be 1,
   335  	// so the slice length is the same as the array's.
   336  	// see golang.org/ref/spec#Size_and_alignment_guarantees
   337  	b := *(*[]byte)(unsafe.Pointer(&sliceHeader{
   338  		Data: p,
   339  		Len:  len,
   340  		Cap:  len,
   341  	}))
   342  	dst = append(dst, '"')
   343  	dst = appendEscapedBytes(dst, b, opts)
   344  	dst = append(dst, '"')
   345  
   346  	return dst
   347  }
   348  
   349  func encodeMap(
   350  	p unsafe.Pointer, dst []byte, opts encOpts, t reflect.Type, ki, vi instruction,
   351  ) ([]byte, error) {
   352  	m := *(*unsafe.Pointer)(p)
   353  	if m == nil {
   354  		if opts.flags.has(nilMapEmpty) {
   355  			return append(dst, "{}"...), nil
   356  		}
   357  		return append(dst, "null"...), nil
   358  	}
   359  	ml := maplen(m)
   360  	if ml == 0 {
   361  		return append(dst, "{}"...), nil
   362  	}
   363  	dst = append(dst, '{')
   364  
   365  	rt := unpackEface(t).word
   366  	it := newHiter(rt, m)
   367  
   368  	var err error
   369  	if opts.flags.has(unsortedMap) {
   370  		dst, err = encodeUnsortedMap(it, dst, opts, ki, vi)
   371  	} else {
   372  		dst, err = encodeSortedMap(it, dst, opts, ki, vi, ml)
   373  	}
   374  	hiterPool.Put(it)
   375  
   376  	if err != nil {
   377  		return dst, err
   378  	}
   379  	return append(dst, '}'), err
   380  }
   381  
   382  // encodeUnsortedMap appends the elements of the map
   383  // pointed by p as comma-separated k/v pairs to dst,
   384  // in unspecified order.
   385  func encodeUnsortedMap(
   386  	it *hiter, dst []byte, opts encOpts, ki, vi instruction,
   387  ) ([]byte, error) {
   388  	var (
   389  		n   int
   390  		err error
   391  	)
   392  	for ; it.key != nil; mapiternext(it) {
   393  		if n != 0 {
   394  			dst = append(dst, ',')
   395  		}
   396  		// Encode entry's key.
   397  		if dst, err = ki(it.key, dst, opts); err != nil {
   398  			return dst, err
   399  		}
   400  		dst = append(dst, ':')
   401  
   402  		// Encode entry's value.
   403  		if dst, err = vi(it.val, dst, opts); err != nil {
   404  			return dst, err
   405  		}
   406  		n++
   407  	}
   408  	return dst, nil
   409  }
   410  
   411  // encodeUnsortedMap appends the elements of the map
   412  // pointed by p as comma-separated k/v pairs to dst,
   413  // sorted by key in lexicographical order.
   414  func encodeSortedMap(
   415  	it *hiter, dst []byte, opts encOpts, ki, vi instruction, ml int,
   416  ) ([]byte, error) {
   417  	var (
   418  		off int
   419  		err error
   420  		buf = cachedBuffer()
   421  		mel *mapElems
   422  	)
   423  	if v := mapElemsPool.Get(); v != nil {
   424  		mel = v.(*mapElems)
   425  	} else {
   426  		mel = &mapElems{s: make([]kv, 0, ml)}
   427  	}
   428  	for ; it.key != nil; mapiternext(it) {
   429  		kv := kv{}
   430  
   431  		// Encode the key and store the buffer
   432  		// portion to use during sort.
   433  		if buf.B, err = ki(it.key, buf.B, opts); err != nil {
   434  			break
   435  		}
   436  		// Omit quotes of keys.
   437  		kv.key = buf.B[off+1 : len(buf.B)-1]
   438  
   439  		// Add separator after key.
   440  		buf.B = append(buf.B, ':')
   441  
   442  		// Encode the value and store the buffer
   443  		// portion corresponding to the semicolon
   444  		// delimited key/value pair.
   445  		if buf.B, err = vi(it.val, buf.B, opts); err != nil {
   446  			break
   447  		}
   448  		kv.keyval = buf.B[off:len(buf.B)]
   449  		mel.s = append(mel.s, kv)
   450  		off = len(buf.B)
   451  	}
   452  	if err == nil {
   453  		// Sort map entries by key in
   454  		// lexicographical order.
   455  		sort.Sort(mel)
   456  
   457  		// Append sorted comma-delimited k/v
   458  		// pairs to the given buffer.
   459  		for i, kv := range mel.s {
   460  			if i != 0 {
   461  				dst = append(dst, ',')
   462  			}
   463  			dst = append(dst, kv.keyval...)
   464  		}
   465  	}
   466  	// The map elements must be released before
   467  	// the buffer, because each k/v pair holds
   468  	// two sublices that points to the buffer's
   469  	// backing array.
   470  	releaseMapElems(mel)
   471  	bufferPool.Put(buf)
   472  
   473  	return dst, err
   474  }
   475  
   476  // encodeSyncMap appends the elements of a sync.Map pointed
   477  // to by p to dst and returns the extended buffer.
   478  // This function replicates the behavior of encoding Go maps,
   479  // by returning an error for keys that are not of type string
   480  // or int, or that does not implement encoding.TextMarshaler.
   481  func encodeSyncMap(p unsafe.Pointer, dst []byte, opts encOpts) ([]byte, error) {
   482  	sm := (*sync.Map)(p)
   483  	dst = append(dst, '{')
   484  
   485  	// The sync.Map type does not have a Len() method to
   486  	// determine if it has no entries, to bail out early,
   487  	// so we just range over it to encode all available
   488  	// entries.
   489  	// If an error arises while encoding a key or a value,
   490  	// the error is stored and the method used by Range()
   491  	// returns false to stop the map's iteration.
   492  	var err error
   493  	if opts.flags.has(unsortedMap) {
   494  		dst, err = encodeUnsortedSyncMap(sm, dst, opts)
   495  	} else {
   496  		dst, err = encodeSortedSyncMap(sm, dst, opts)
   497  	}
   498  	if err != nil {
   499  		return dst, err
   500  	}
   501  	return append(dst, '}'), nil
   502  }
   503  
   504  // encodeUnsortedSyncMap is similar to encodeUnsortedMap
   505  // but operates on a sync.Map type instead of a Go map.
   506  func encodeUnsortedSyncMap(sm *sync.Map, dst []byte, opts encOpts) ([]byte, error) {
   507  	var (
   508  		n   int
   509  		err error
   510  	)
   511  	sm.Range(func(key, value interface{}) bool {
   512  		if n != 0 {
   513  			dst = append(dst, ',')
   514  		}
   515  		// Encode the key.
   516  		if dst, err = appendSyncMapKey(dst, key, opts); err != nil {
   517  			return false
   518  		}
   519  		dst = append(dst, ':')
   520  
   521  		// Encode the value.
   522  		if dst, err = appendJSON(dst, value, opts); err != nil {
   523  			return false
   524  		}
   525  		n++
   526  		return true
   527  	})
   528  	return dst, err
   529  }
   530  
   531  // encodeSortedSyncMap is similar to encodeSortedMap
   532  // but operates on a sync.Map type instead of a Go map.
   533  func encodeSortedSyncMap(sm *sync.Map, dst []byte, opts encOpts) ([]byte, error) {
   534  	var (
   535  		off int
   536  		err error
   537  		buf = cachedBuffer()
   538  		mel *mapElems
   539  	)
   540  	if v := mapElemsPool.Get(); v != nil {
   541  		mel = v.(*mapElems)
   542  	} else {
   543  		mel = &mapElems{s: make([]kv, 0)}
   544  	}
   545  	sm.Range(func(key, value interface{}) bool {
   546  		kv := kv{}
   547  
   548  		// Encode the key and store the buffer
   549  		// portion to use during the later sort.
   550  		if buf.B, err = appendSyncMapKey(buf.B, key, opts); err != nil {
   551  			return false
   552  		}
   553  		// Omit quotes of keys.
   554  		kv.key = buf.B[off+1 : len(buf.B)-1]
   555  
   556  		// Add separator after key.
   557  		buf.B = append(buf.B, ':')
   558  
   559  		// Encode the value and store the buffer
   560  		// portion corresponding to the semicolon
   561  		// delimited key/value pair.
   562  		if buf.B, err = appendJSON(buf.B, value, opts); err != nil {
   563  			return false
   564  		}
   565  		kv.keyval = buf.B[off:len(buf.B)]
   566  		mel.s = append(mel.s, kv)
   567  		off = len(buf.B)
   568  
   569  		return true
   570  	})
   571  	if err == nil {
   572  		// Sort map entries by key in
   573  		// lexicographical order.
   574  		sort.Sort(mel)
   575  
   576  		// Append sorted comma-delimited k/v
   577  		// pairs to the given buffer.
   578  		for i, kv := range mel.s {
   579  			if i != 0 {
   580  				dst = append(dst, ',')
   581  			}
   582  			dst = append(dst, kv.keyval...)
   583  		}
   584  	}
   585  	releaseMapElems(mel)
   586  	bufferPool.Put(buf)
   587  
   588  	return dst, err
   589  }
   590  
   591  func appendSyncMapKey(dst []byte, key interface{}, opts encOpts) ([]byte, error) {
   592  	if key == nil {
   593  		return dst, errors.New("unsupported nil key in sync.Map")
   594  	}
   595  	kt := reflect.TypeOf(key)
   596  	var (
   597  		isStr = isString(kt)
   598  		isInt = isInteger(kt)
   599  		isTxt = kt.Implements(textMarshalerType)
   600  	)
   601  	if !isStr && !isInt && !isTxt {
   602  		return dst, fmt.Errorf("unsupported key of type %s in sync.Map", kt)
   603  	}
   604  	var err error
   605  
   606  	// Quotes the key if the type is not
   607  	// encoded with quotes by default.
   608  	quoted := !isStr && !isTxt
   609  
   610  	// Ensure map key precedence for keys of type
   611  	// string by using the encodeString function
   612  	// directly instead of the generic appendJSON.
   613  	if isStr {
   614  		dst, err = encodeString(unpackEface(key).word, dst, opts)
   615  		runtime.KeepAlive(key)
   616  	} else {
   617  		if quoted {
   618  			dst = append(dst, '"')
   619  		}
   620  		dst, err = appendJSON(dst, key, opts)
   621  	}
   622  	if err != nil {
   623  		return dst, err
   624  	}
   625  	if quoted {
   626  		dst = append(dst, '"')
   627  	}
   628  	return dst, nil
   629  }
   630  
   631  func encodeMarshaler(
   632  	p unsafe.Pointer, dst []byte, opts encOpts, t reflect.Type, canAddr bool, fn marshalerEncodeFunc,
   633  ) ([]byte, error) {
   634  	// The content of this function and packEface
   635  	// is similar to the following code using the
   636  	// reflect package.
   637  	//
   638  	// v := reflect.NewAt(t, p)
   639  	// if !canAddr {
   640  	// 	v = v.Elem()
   641  	// 	k := v.Kind()
   642  	// 	if (k == reflect.Ptr || k == reflect.Interface) && v.IsNil() {
   643  	// 		return append(dst, "null"...), nil
   644  	// 	}
   645  	// } else if v.IsNil() {
   646  	// 	return append(dst, "null"...), nil
   647  	// }
   648  	// return fn(v.Interface(), dst, opts, t)
   649  	//
   650  	if !canAddr {
   651  		if t.Kind() == reflect.Ptr || t.Kind() == reflect.Interface {
   652  			if *(*unsafe.Pointer)(p) == nil {
   653  				return append(dst, "null"...), nil
   654  			}
   655  		}
   656  	} else {
   657  		if p == nil {
   658  			return append(dst, "null"...), nil
   659  		}
   660  		t = reflect.PtrTo(t)
   661  	}
   662  	var i interface{}
   663  
   664  	if t.Kind() == reflect.Interface {
   665  		// Special case: return the element inside the
   666  		// interface. The empty interface has one layout,
   667  		// all interfaces with methods have another one.
   668  		if t.NumMethod() == 0 {
   669  			i = *(*interface{})(p)
   670  		} else {
   671  			i = *(*interface{ M() })(p)
   672  		}
   673  	} else {
   674  		i = packEface(p, t, t.Kind() == reflect.Ptr && !canAddr)
   675  	}
   676  	return fn(i, dst, opts, t)
   677  }
   678  
   679  func encodeAppendMarshalerCtx(
   680  	i interface{}, dst []byte, opts encOpts, t reflect.Type,
   681  ) ([]byte, error) {
   682  	dst2, err := i.(AppendMarshalerCtx).AppendJSONContext(opts.ctx, dst)
   683  	if err != nil {
   684  		return dst, &MarshalerError{t, err, marshalerAppendJSONCtx}
   685  	}
   686  	return dst2, nil
   687  }
   688  
   689  func encodeAppendMarshaler(
   690  	i interface{}, dst []byte, _ encOpts, t reflect.Type,
   691  ) ([]byte, error) {
   692  	dst2, err := i.(AppendMarshaler).AppendJSON(dst)
   693  	if err != nil {
   694  		return dst, &MarshalerError{t, err, marshalerAppendJSON}
   695  	}
   696  	return dst2, nil
   697  }
   698  
   699  func encodeJSONMarshaler(i interface{}, dst []byte, opts encOpts, t reflect.Type) ([]byte, error) {
   700  	b, err := i.(json.Marshaler).MarshalJSON()
   701  	if err != nil {
   702  		return dst, &MarshalerError{t, err, marshalerJSON}
   703  	}
   704  	if opts.flags.has(noCompact) {
   705  		return append(dst, b...), nil
   706  	}
   707  	// This is redundant with the parsing done
   708  	// by appendCompactJSON, but for the time
   709  	// being, we can't use the scanner of the
   710  	// standard library.
   711  	if !json.Valid(b) {
   712  		return dst, &MarshalerError{t, &SyntaxError{
   713  			msg: "json: invalid value",
   714  		}, marshalerJSON}
   715  	}
   716  	return appendCompactJSON(dst, b, !opts.flags.has(noHTMLEscaping))
   717  }
   718  
   719  func encodeTextMarshaler(i interface{}, dst []byte, _ encOpts, t reflect.Type) ([]byte, error) {
   720  	b, err := i.(encoding.TextMarshaler).MarshalText()
   721  	if err != nil {
   722  		return dst, &MarshalerError{t, err, marshalerText}
   723  	}
   724  	dst = append(dst, '"')
   725  	dst = append(dst, b...)
   726  	dst = append(dst, '"')
   727  
   728  	return dst, nil
   729  }
   730  
   731  // appendCompactJSON appends to dst the JSON-encoded src
   732  // with insignificant space characters elided. If escHTML
   733  // is true, HTML-characters are also escaped.
   734  func appendCompactJSON(dst, src []byte, escHTML bool) ([]byte, error) {
   735  	var (
   736  		inString bool
   737  		skipNext bool
   738  	)
   739  	at := 0 // accumulated bytes start index
   740  
   741  	for i, c := range src {
   742  		if escHTML {
   743  			// Escape HTML characters.
   744  			if c == '<' || c == '>' || c == '&' {
   745  				if at < i {
   746  					dst = append(dst, src[at:i]...)
   747  				}
   748  				dst = append(dst, `\u00`...)
   749  				dst = append(dst, hex[c>>4], hex[c&0xF])
   750  				at = i + 1
   751  				continue
   752  			}
   753  		}
   754  		// Convert U+2028 and U+2029.
   755  		// (E2 80 A8 and E2 80 A9).
   756  		if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
   757  			if at < i {
   758  				dst = append(dst, src[at:i]...)
   759  			}
   760  			dst = append(dst, `\u202`...)
   761  			dst = append(dst, hex[src[i+2]&0xF])
   762  			at = i + 3
   763  			continue
   764  		}
   765  		if !inString {
   766  			switch c {
   767  			case '"':
   768  				// Within a string, we don't elide
   769  				// insignificant space characters.
   770  				inString = true
   771  			case ' ', '\n', '\r', '\t':
   772  				// Append the accumulated bytes,
   773  				// and skip the current character.
   774  				if at < i {
   775  					dst = append(dst, src[at:i]...)
   776  				}
   777  				at = i + 1
   778  			}
   779  			continue
   780  		}
   781  		// Next character is escaped, and must
   782  		// not be interpreted as the end of a
   783  		// string by mistake.
   784  		if skipNext {
   785  			skipNext = false
   786  			continue
   787  		}
   788  		// Next character must be skipped.
   789  		if c == '\\' {
   790  			skipNext = true
   791  			continue
   792  		}
   793  		// Leaving a string value.
   794  		if c == '"' {
   795  			inString = false
   796  		}
   797  	}
   798  	if at < len(src) {
   799  		dst = append(dst, src[at:]...)
   800  	}
   801  	return dst, nil
   802  }
   803  
   804  func appendEscapedBytes(dst []byte, b []byte, opts encOpts) []byte {
   805  	if opts.flags.has(noStringEscaping) {
   806  		return append(dst, b...)
   807  	}
   808  	var (
   809  		i  = 0
   810  		at = 0
   811  	)
   812  	noCoerce := opts.flags.has(noUTF8Coercion)
   813  	noEscape := opts.flags.has(noHTMLEscaping)
   814  
   815  	for i < len(b) {
   816  		if c := b[i]; c < utf8.RuneSelf {
   817  			// Check whether c can be used in a JSON string
   818  			// without escaping, or it is a problematic HTML
   819  			// character.
   820  			if c >= ' ' && c != '\\' && c != '"' && (noEscape || (c != '<' && c != '>' && c != '&')) {
   821  				// If the current character doesn't need
   822  				// to be escaped, accumulate the bytes to
   823  				// save some operations.
   824  				i++
   825  				continue
   826  			}
   827  			// Write accumulated single-byte characters.
   828  			if at < i {
   829  				dst = append(dst, b[at:i]...)
   830  			}
   831  			// The encoding/json package implements only
   832  			// a few of the special two-character escape
   833  			// sequence described in the RFC 8259, Section 7.
   834  			// \b and \f were ignored on purpose, see
   835  			// https://codereview.appspot.com/4678046.
   836  			switch c {
   837  			case '"', '\\':
   838  				dst = append(dst, '\\', c)
   839  			case '\n': // 0xA, line feed
   840  				dst = append(dst, '\\', 'n')
   841  			case '\r': // 0xD, carriage return
   842  				dst = append(dst, '\\', 'r')
   843  			case '\t': // 0x9, horizontal tab
   844  				dst = append(dst, '\\', 't')
   845  			default:
   846  				dst = append(dst, `\u00`...)
   847  				dst = append(dst, hex[c>>4])
   848  				dst = append(dst, hex[c&0xF])
   849  			}
   850  			i++
   851  			at = i
   852  			continue
   853  		}
   854  		r, size := utf8.DecodeRune(b[i:])
   855  
   856  		if !noCoerce {
   857  			// Coerce to valid UTF-8, by replacing invalid
   858  			// bytes with the Unicode replacement rune.
   859  			if r == utf8.RuneError && size == 1 {
   860  				if at < i {
   861  					dst = append(dst, b[at:i]...)
   862  				}
   863  				dst = append(dst, `\ufffd`...)
   864  				i += size
   865  				at = i
   866  				continue
   867  			}
   868  			// U+2028 is LINE SEPARATOR.
   869  			// U+2029 is PARAGRAPH SEPARATOR.
   870  			// They are both technically valid characters in
   871  			// JSON strings, but don't work in JSONP, which has
   872  			// to be evaluated as JavaScript, and can lead to
   873  			// security holes there. It is valid JSON to escape
   874  			// them, so we do so unconditionally.
   875  			// See http://timelessrepo.com/json-isnt-a-javascript-subset.
   876  			if r == '\u2028' || r == '\u2029' {
   877  				if at < i {
   878  					dst = append(dst, b[at:i]...)
   879  				}
   880  				dst = append(dst, `\u202`...)
   881  				dst = append(dst, hex[r&0xF])
   882  				i += size
   883  				at = i
   884  				continue
   885  			}
   886  			i += size
   887  			continue
   888  		}
   889  		i += size
   890  	}
   891  	if at < len(b) {
   892  		dst = append(dst, b[at:]...)
   893  	}
   894  	return dst
   895  }