github.com/wI2L/jettison@v0.7.4/encode.go (about)

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