github.com/segmentio/encoding@v0.4.0/json/encode.go (about)

     1  package json
     2  
     3  import (
     4  	"encoding"
     5  	"fmt"
     6  	"math"
     7  	"reflect"
     8  	"sort"
     9  	"strconv"
    10  	"sync"
    11  	"time"
    12  	"unicode/utf8"
    13  	"unsafe"
    14  
    15  	"github.com/segmentio/asm/base64"
    16  )
    17  
    18  const hex = "0123456789abcdef"
    19  
    20  func (e encoder) encodeNull(b []byte, p unsafe.Pointer) ([]byte, error) {
    21  	return append(b, "null"...), nil
    22  }
    23  
    24  func (e encoder) encodeBool(b []byte, p unsafe.Pointer) ([]byte, error) {
    25  	if *(*bool)(p) {
    26  		return append(b, "true"...), nil
    27  	}
    28  	return append(b, "false"...), nil
    29  }
    30  
    31  func (e encoder) encodeInt(b []byte, p unsafe.Pointer) ([]byte, error) {
    32  	return appendInt(b, int64(*(*int)(p))), nil
    33  }
    34  
    35  func (e encoder) encodeInt8(b []byte, p unsafe.Pointer) ([]byte, error) {
    36  	return appendInt(b, int64(*(*int8)(p))), nil
    37  }
    38  
    39  func (e encoder) encodeInt16(b []byte, p unsafe.Pointer) ([]byte, error) {
    40  	return appendInt(b, int64(*(*int16)(p))), nil
    41  }
    42  
    43  func (e encoder) encodeInt32(b []byte, p unsafe.Pointer) ([]byte, error) {
    44  	return appendInt(b, int64(*(*int32)(p))), nil
    45  }
    46  
    47  func (e encoder) encodeInt64(b []byte, p unsafe.Pointer) ([]byte, error) {
    48  	return appendInt(b, *(*int64)(p)), nil
    49  }
    50  
    51  func (e encoder) encodeUint(b []byte, p unsafe.Pointer) ([]byte, error) {
    52  	return appendUint(b, uint64(*(*uint)(p))), nil
    53  }
    54  
    55  func (e encoder) encodeUintptr(b []byte, p unsafe.Pointer) ([]byte, error) {
    56  	return appendUint(b, uint64(*(*uintptr)(p))), nil
    57  }
    58  
    59  func (e encoder) encodeUint8(b []byte, p unsafe.Pointer) ([]byte, error) {
    60  	return appendUint(b, uint64(*(*uint8)(p))), nil
    61  }
    62  
    63  func (e encoder) encodeUint16(b []byte, p unsafe.Pointer) ([]byte, error) {
    64  	return appendUint(b, uint64(*(*uint16)(p))), nil
    65  }
    66  
    67  func (e encoder) encodeUint32(b []byte, p unsafe.Pointer) ([]byte, error) {
    68  	return appendUint(b, uint64(*(*uint32)(p))), nil
    69  }
    70  
    71  func (e encoder) encodeUint64(b []byte, p unsafe.Pointer) ([]byte, error) {
    72  	return appendUint(b, *(*uint64)(p)), nil
    73  }
    74  
    75  func (e encoder) encodeFloat32(b []byte, p unsafe.Pointer) ([]byte, error) {
    76  	return e.encodeFloat(b, float64(*(*float32)(p)), 32)
    77  }
    78  
    79  func (e encoder) encodeFloat64(b []byte, p unsafe.Pointer) ([]byte, error) {
    80  	return e.encodeFloat(b, *(*float64)(p), 64)
    81  }
    82  
    83  func (e encoder) encodeFloat(b []byte, f float64, bits int) ([]byte, error) {
    84  	switch {
    85  	case math.IsNaN(f):
    86  		return b, &UnsupportedValueError{Value: reflect.ValueOf(f), Str: "NaN"}
    87  	case math.IsInf(f, 0):
    88  		return b, &UnsupportedValueError{Value: reflect.ValueOf(f), Str: "inf"}
    89  	}
    90  
    91  	// Convert as if by ES6 number to string conversion.
    92  	// This matches most other JSON generators.
    93  	// See golang.org/issue/6384 and golang.org/issue/14135.
    94  	// Like fmt %g, but the exponent cutoffs are different
    95  	// and exponents themselves are not padded to two digits.
    96  	abs := math.Abs(f)
    97  	fmt := byte('f')
    98  	// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
    99  	if abs != 0 {
   100  		if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
   101  			fmt = 'e'
   102  		}
   103  	}
   104  
   105  	b = strconv.AppendFloat(b, f, fmt, -1, int(bits))
   106  
   107  	if fmt == 'e' {
   108  		// clean up e-09 to e-9
   109  		n := len(b)
   110  		if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' {
   111  			b[n-2] = b[n-1]
   112  			b = b[:n-1]
   113  		}
   114  	}
   115  
   116  	return b, nil
   117  }
   118  
   119  func (e encoder) encodeNumber(b []byte, p unsafe.Pointer) ([]byte, error) {
   120  	n := *(*Number)(p)
   121  	if n == "" {
   122  		n = "0"
   123  	}
   124  
   125  	d := decoder{}
   126  	_, _, _, err := d.parseNumber(stringToBytes(string(n)))
   127  	if err != nil {
   128  		return b, err
   129  	}
   130  
   131  	return append(b, n...), nil
   132  }
   133  
   134  func (e encoder) encodeString(b []byte, p unsafe.Pointer) ([]byte, error) {
   135  	s := *(*string)(p)
   136  	if len(s) == 0 {
   137  		return append(b, `""`...), nil
   138  	}
   139  	i := 0
   140  	j := 0
   141  	escapeHTML := (e.flags & EscapeHTML) != 0
   142  
   143  	b = append(b, '"')
   144  
   145  	if len(s) >= 8 {
   146  		if j = escapeIndex(s, escapeHTML); j < 0 {
   147  			return append(append(b, s...), '"'), nil
   148  		}
   149  	}
   150  
   151  	for j < len(s) {
   152  		c := s[j]
   153  
   154  		if c >= 0x20 && c <= 0x7f && c != '\\' && c != '"' && (!escapeHTML || (c != '<' && c != '>' && c != '&')) {
   155  			// fast path: most of the time, printable ascii characters are used
   156  			j++
   157  			continue
   158  		}
   159  
   160  		switch c {
   161  		case '\\', '"':
   162  			b = append(b, s[i:j]...)
   163  			b = append(b, '\\', c)
   164  			i = j + 1
   165  			j = j + 1
   166  			continue
   167  
   168  		case '\n':
   169  			b = append(b, s[i:j]...)
   170  			b = append(b, '\\', 'n')
   171  			i = j + 1
   172  			j = j + 1
   173  			continue
   174  
   175  		case '\r':
   176  			b = append(b, s[i:j]...)
   177  			b = append(b, '\\', 'r')
   178  			i = j + 1
   179  			j = j + 1
   180  			continue
   181  
   182  		case '\t':
   183  			b = append(b, s[i:j]...)
   184  			b = append(b, '\\', 't')
   185  			i = j + 1
   186  			j = j + 1
   187  			continue
   188  
   189  		case '<', '>', '&':
   190  			b = append(b, s[i:j]...)
   191  			b = append(b, `\u00`...)
   192  			b = append(b, hex[c>>4], hex[c&0xF])
   193  			i = j + 1
   194  			j = j + 1
   195  			continue
   196  		}
   197  
   198  		// This encodes bytes < 0x20 except for \t, \n and \r.
   199  		if c < 0x20 {
   200  			b = append(b, s[i:j]...)
   201  			b = append(b, `\u00`...)
   202  			b = append(b, hex[c>>4], hex[c&0xF])
   203  			i = j + 1
   204  			j = j + 1
   205  			continue
   206  		}
   207  
   208  		r, size := utf8.DecodeRuneInString(s[j:])
   209  
   210  		if r == utf8.RuneError && size == 1 {
   211  			b = append(b, s[i:j]...)
   212  			b = append(b, `\ufffd`...)
   213  			i = j + size
   214  			j = j + size
   215  			continue
   216  		}
   217  
   218  		switch r {
   219  		case '\u2028', '\u2029':
   220  			// U+2028 is LINE SEPARATOR.
   221  			// U+2029 is PARAGRAPH SEPARATOR.
   222  			// They are both technically valid characters in JSON strings,
   223  			// but don't work in JSONP, which has to be evaluated as JavaScript,
   224  			// and can lead to security holes there. It is valid JSON to
   225  			// escape them, so we do so unconditionally.
   226  			// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
   227  			b = append(b, s[i:j]...)
   228  			b = append(b, `\u202`...)
   229  			b = append(b, hex[r&0xF])
   230  			i = j + size
   231  			j = j + size
   232  			continue
   233  		}
   234  
   235  		j += size
   236  	}
   237  
   238  	b = append(b, s[i:]...)
   239  	b = append(b, '"')
   240  	return b, nil
   241  }
   242  
   243  func (e encoder) encodeToString(b []byte, p unsafe.Pointer, encode encodeFunc) ([]byte, error) {
   244  	i := len(b)
   245  
   246  	b, err := encode(e, b, p)
   247  	if err != nil {
   248  		return b, err
   249  	}
   250  
   251  	j := len(b)
   252  	s := b[i:]
   253  
   254  	if b, err = e.encodeString(b, unsafe.Pointer(&s)); err != nil {
   255  		return b, err
   256  	}
   257  
   258  	n := copy(b[i:], b[j:])
   259  	return b[:i+n], nil
   260  }
   261  
   262  func (e encoder) encodeBytes(b []byte, p unsafe.Pointer) ([]byte, error) {
   263  	v := *(*[]byte)(p)
   264  	if v == nil {
   265  		return append(b, "null"...), nil
   266  	}
   267  
   268  	n := base64.StdEncoding.EncodedLen(len(v)) + 2
   269  
   270  	if avail := cap(b) - len(b); avail < n {
   271  		newB := make([]byte, cap(b)+(n-avail))
   272  		copy(newB, b)
   273  		b = newB[:len(b)]
   274  	}
   275  
   276  	i := len(b)
   277  	j := len(b) + n
   278  
   279  	b = b[:j]
   280  	b[i] = '"'
   281  	base64.StdEncoding.Encode(b[i+1:j-1], v)
   282  	b[j-1] = '"'
   283  	return b, nil
   284  }
   285  
   286  func (e encoder) encodeDuration(b []byte, p unsafe.Pointer) ([]byte, error) {
   287  	b = append(b, '"')
   288  	b = appendDuration(b, *(*time.Duration)(p))
   289  	b = append(b, '"')
   290  	return b, nil
   291  }
   292  
   293  func (e encoder) encodeTime(b []byte, p unsafe.Pointer) ([]byte, error) {
   294  	t := *(*time.Time)(p)
   295  	b = append(b, '"')
   296  	b = t.AppendFormat(b, time.RFC3339Nano)
   297  	b = append(b, '"')
   298  	return b, nil
   299  }
   300  
   301  func (e encoder) encodeArray(b []byte, p unsafe.Pointer, n int, size uintptr, t reflect.Type, encode encodeFunc) ([]byte, error) {
   302  	var start = len(b)
   303  	var err error
   304  	b = append(b, '[')
   305  
   306  	for i := 0; i < n; i++ {
   307  		if i != 0 {
   308  			b = append(b, ',')
   309  		}
   310  		if b, err = encode(e, b, unsafe.Pointer(uintptr(p)+(uintptr(i)*size))); err != nil {
   311  			return b[:start], err
   312  		}
   313  	}
   314  
   315  	b = append(b, ']')
   316  	return b, nil
   317  }
   318  
   319  func (e encoder) encodeSlice(b []byte, p unsafe.Pointer, size uintptr, t reflect.Type, encode encodeFunc) ([]byte, error) {
   320  	s := (*slice)(p)
   321  
   322  	if s.data == nil && s.len == 0 && s.cap == 0 {
   323  		return append(b, "null"...), nil
   324  	}
   325  
   326  	return e.encodeArray(b, s.data, s.len, size, t, encode)
   327  }
   328  
   329  func (e encoder) encodeMap(b []byte, p unsafe.Pointer, t reflect.Type, encodeKey, encodeValue encodeFunc, sortKeys sortFunc) ([]byte, error) {
   330  	m := reflect.NewAt(t, p).Elem()
   331  	if m.IsNil() {
   332  		return append(b, "null"...), nil
   333  	}
   334  
   335  	keys := m.MapKeys()
   336  	if sortKeys != nil && (e.flags&SortMapKeys) != 0 {
   337  		sortKeys(keys)
   338  	}
   339  
   340  	var start = len(b)
   341  	var err error
   342  	b = append(b, '{')
   343  
   344  	for i, k := range keys {
   345  		v := m.MapIndex(k)
   346  
   347  		if i != 0 {
   348  			b = append(b, ',')
   349  		}
   350  
   351  		if b, err = encodeKey(e, b, (*iface)(unsafe.Pointer(&k)).ptr); err != nil {
   352  			return b[:start], err
   353  		}
   354  
   355  		b = append(b, ':')
   356  
   357  		if b, err = encodeValue(e, b, (*iface)(unsafe.Pointer(&v)).ptr); err != nil {
   358  			return b[:start], err
   359  		}
   360  	}
   361  
   362  	b = append(b, '}')
   363  	return b, nil
   364  }
   365  
   366  type element struct {
   367  	key string
   368  	val interface{}
   369  	raw RawMessage
   370  }
   371  
   372  type mapslice struct {
   373  	elements []element
   374  }
   375  
   376  func (m *mapslice) Len() int           { return len(m.elements) }
   377  func (m *mapslice) Less(i, j int) bool { return m.elements[i].key < m.elements[j].key }
   378  func (m *mapslice) Swap(i, j int)      { m.elements[i], m.elements[j] = m.elements[j], m.elements[i] }
   379  
   380  var mapslicePool = sync.Pool{
   381  	New: func() interface{} { return new(mapslice) },
   382  }
   383  
   384  func (e encoder) encodeMapStringInterface(b []byte, p unsafe.Pointer) ([]byte, error) {
   385  	m := *(*map[string]interface{})(p)
   386  	if m == nil {
   387  		return append(b, "null"...), nil
   388  	}
   389  
   390  	if (e.flags & SortMapKeys) == 0 {
   391  		// Optimized code path when the program does not need the map keys to be
   392  		// sorted.
   393  		b = append(b, '{')
   394  
   395  		if len(m) != 0 {
   396  			var err error
   397  			var i = 0
   398  
   399  			for k, v := range m {
   400  				if i != 0 {
   401  					b = append(b, ',')
   402  				}
   403  
   404  				b, _ = e.encodeString(b, unsafe.Pointer(&k))
   405  				b = append(b, ':')
   406  
   407  				b, err = Append(b, v, e.flags)
   408  				if err != nil {
   409  					return b, err
   410  				}
   411  
   412  				i++
   413  			}
   414  		}
   415  
   416  		b = append(b, '}')
   417  		return b, nil
   418  	}
   419  
   420  	s := mapslicePool.Get().(*mapslice)
   421  	if cap(s.elements) < len(m) {
   422  		s.elements = make([]element, 0, align(10, uintptr(len(m))))
   423  	}
   424  	for key, val := range m {
   425  		s.elements = append(s.elements, element{key: key, val: val})
   426  	}
   427  	sort.Sort(s)
   428  
   429  	var start = len(b)
   430  	var err error
   431  	b = append(b, '{')
   432  
   433  	for i, elem := range s.elements {
   434  		if i != 0 {
   435  			b = append(b, ',')
   436  		}
   437  
   438  		b, _ = e.encodeString(b, unsafe.Pointer(&elem.key))
   439  		b = append(b, ':')
   440  
   441  		b, err = Append(b, elem.val, e.flags)
   442  		if err != nil {
   443  			break
   444  		}
   445  	}
   446  
   447  	for i := range s.elements {
   448  		s.elements[i] = element{}
   449  	}
   450  
   451  	s.elements = s.elements[:0]
   452  	mapslicePool.Put(s)
   453  
   454  	if err != nil {
   455  		return b[:start], err
   456  	}
   457  
   458  	b = append(b, '}')
   459  	return b, nil
   460  }
   461  
   462  func (e encoder) encodeMapStringRawMessage(b []byte, p unsafe.Pointer) ([]byte, error) {
   463  	m := *(*map[string]RawMessage)(p)
   464  	if m == nil {
   465  		return append(b, "null"...), nil
   466  	}
   467  
   468  	if (e.flags & SortMapKeys) == 0 {
   469  		// Optimized code path when the program does not need the map keys to be
   470  		// sorted.
   471  		b = append(b, '{')
   472  
   473  		if len(m) != 0 {
   474  			var err error
   475  			var i = 0
   476  
   477  			for k, v := range m {
   478  				if i != 0 {
   479  					b = append(b, ',')
   480  				}
   481  
   482  				// encodeString doesn't return errors so we ignore it here
   483  				b, _ = e.encodeString(b, unsafe.Pointer(&k))
   484  				b = append(b, ':')
   485  
   486  				b, err = e.encodeRawMessage(b, unsafe.Pointer(&v))
   487  				if err != nil {
   488  					break
   489  				}
   490  
   491  				i++
   492  			}
   493  		}
   494  
   495  		b = append(b, '}')
   496  		return b, nil
   497  	}
   498  
   499  	s := mapslicePool.Get().(*mapslice)
   500  	if cap(s.elements) < len(m) {
   501  		s.elements = make([]element, 0, align(10, uintptr(len(m))))
   502  	}
   503  	for key, raw := range m {
   504  		s.elements = append(s.elements, element{key: key, raw: raw})
   505  	}
   506  	sort.Sort(s)
   507  
   508  	var start = len(b)
   509  	var err error
   510  	b = append(b, '{')
   511  
   512  	for i, elem := range s.elements {
   513  		if i != 0 {
   514  			b = append(b, ',')
   515  		}
   516  
   517  		b, _ = e.encodeString(b, unsafe.Pointer(&elem.key))
   518  		b = append(b, ':')
   519  
   520  		b, err = e.encodeRawMessage(b, unsafe.Pointer(&elem.raw))
   521  		if err != nil {
   522  			break
   523  		}
   524  	}
   525  
   526  	for i := range s.elements {
   527  		s.elements[i] = element{}
   528  	}
   529  
   530  	s.elements = s.elements[:0]
   531  	mapslicePool.Put(s)
   532  
   533  	if err != nil {
   534  		return b[:start], err
   535  	}
   536  
   537  	b = append(b, '}')
   538  	return b, nil
   539  }
   540  
   541  func (e encoder) encodeMapStringString(b []byte, p unsafe.Pointer) ([]byte, error) {
   542  	m := *(*map[string]string)(p)
   543  	if m == nil {
   544  		return append(b, "null"...), nil
   545  	}
   546  
   547  	if (e.flags & SortMapKeys) == 0 {
   548  		// Optimized code path when the program does not need the map keys to be
   549  		// sorted.
   550  		b = append(b, '{')
   551  
   552  		if len(m) != 0 {
   553  			var i = 0
   554  
   555  			for k, v := range m {
   556  				if i != 0 {
   557  					b = append(b, ',')
   558  				}
   559  
   560  				// encodeString never returns an error so we ignore it here
   561  				b, _ = e.encodeString(b, unsafe.Pointer(&k))
   562  				b = append(b, ':')
   563  				b, _ = e.encodeString(b, unsafe.Pointer(&v))
   564  
   565  				i++
   566  			}
   567  		}
   568  
   569  		b = append(b, '}')
   570  		return b, nil
   571  	}
   572  
   573  	s := mapslicePool.Get().(*mapslice)
   574  	if cap(s.elements) < len(m) {
   575  		s.elements = make([]element, 0, align(10, uintptr(len(m))))
   576  	}
   577  	for key, val := range m {
   578  		v := val
   579  		s.elements = append(s.elements, element{key: key, val: &v})
   580  	}
   581  	sort.Sort(s)
   582  
   583  	b = append(b, '{')
   584  
   585  	for i, elem := range s.elements {
   586  		if i != 0 {
   587  			b = append(b, ',')
   588  		}
   589  
   590  		// encodeString never returns an error so we ignore it here
   591  		b, _ = e.encodeString(b, unsafe.Pointer(&elem.key))
   592  		b = append(b, ':')
   593  		b, _ = e.encodeString(b, unsafe.Pointer(elem.val.(*string)))
   594  	}
   595  
   596  	for i := range s.elements {
   597  		s.elements[i] = element{}
   598  	}
   599  
   600  	s.elements = s.elements[:0]
   601  	mapslicePool.Put(s)
   602  
   603  	b = append(b, '}')
   604  	return b, nil
   605  }
   606  
   607  func (e encoder) encodeMapStringStringSlice(b []byte, p unsafe.Pointer) ([]byte, error) {
   608  	m := *(*map[string][]string)(p)
   609  	if m == nil {
   610  		return append(b, "null"...), nil
   611  	}
   612  
   613  	var stringSize = unsafe.Sizeof("")
   614  
   615  	if (e.flags & SortMapKeys) == 0 {
   616  		// Optimized code path when the program does not need the map keys to be
   617  		// sorted.
   618  		b = append(b, '{')
   619  
   620  		if len(m) != 0 {
   621  			var err error
   622  			var i = 0
   623  
   624  			for k, v := range m {
   625  				if i != 0 {
   626  					b = append(b, ',')
   627  				}
   628  
   629  				b, _ = e.encodeString(b, unsafe.Pointer(&k))
   630  				b = append(b, ':')
   631  
   632  				b, err = e.encodeSlice(b, unsafe.Pointer(&v), stringSize, sliceStringType, encoder.encodeString)
   633  				if err != nil {
   634  					return b, err
   635  				}
   636  
   637  				i++
   638  			}
   639  		}
   640  
   641  		b = append(b, '}')
   642  		return b, nil
   643  	}
   644  
   645  	s := mapslicePool.Get().(*mapslice)
   646  	if cap(s.elements) < len(m) {
   647  		s.elements = make([]element, 0, align(10, uintptr(len(m))))
   648  	}
   649  	for key, val := range m {
   650  		v := val
   651  		s.elements = append(s.elements, element{key: key, val: &v})
   652  	}
   653  	sort.Sort(s)
   654  
   655  	var start = len(b)
   656  	var err error
   657  	b = append(b, '{')
   658  
   659  	for i, elem := range s.elements {
   660  		if i != 0 {
   661  			b = append(b, ',')
   662  		}
   663  
   664  		b, _ = e.encodeString(b, unsafe.Pointer(&elem.key))
   665  		b = append(b, ':')
   666  
   667  		b, err = e.encodeSlice(b, unsafe.Pointer(elem.val.(*[]string)), stringSize, sliceStringType, encoder.encodeString)
   668  		if err != nil {
   669  			break
   670  		}
   671  	}
   672  
   673  	for i := range s.elements {
   674  		s.elements[i] = element{}
   675  	}
   676  
   677  	s.elements = s.elements[:0]
   678  	mapslicePool.Put(s)
   679  
   680  	if err != nil {
   681  		return b[:start], err
   682  	}
   683  
   684  	b = append(b, '}')
   685  	return b, nil
   686  }
   687  
   688  func (e encoder) encodeMapStringBool(b []byte, p unsafe.Pointer) ([]byte, error) {
   689  	m := *(*map[string]bool)(p)
   690  	if m == nil {
   691  		return append(b, "null"...), nil
   692  	}
   693  
   694  	if (e.flags & SortMapKeys) == 0 {
   695  		// Optimized code path when the program does not need the map keys to be
   696  		// sorted.
   697  		b = append(b, '{')
   698  
   699  		if len(m) != 0 {
   700  			var i = 0
   701  
   702  			for k, v := range m {
   703  				if i != 0 {
   704  					b = append(b, ',')
   705  				}
   706  
   707  				// encodeString never returns an error so we ignore it here
   708  				b, _ = e.encodeString(b, unsafe.Pointer(&k))
   709  				if v {
   710  					b = append(b, ":true"...)
   711  				} else {
   712  					b = append(b, ":false"...)
   713  				}
   714  
   715  				i++
   716  			}
   717  		}
   718  
   719  		b = append(b, '}')
   720  		return b, nil
   721  	}
   722  
   723  	s := mapslicePool.Get().(*mapslice)
   724  	if cap(s.elements) < len(m) {
   725  		s.elements = make([]element, 0, align(10, uintptr(len(m))))
   726  	}
   727  	for key, val := range m {
   728  		s.elements = append(s.elements, element{key: key, val: val})
   729  	}
   730  	sort.Sort(s)
   731  
   732  	b = append(b, '{')
   733  
   734  	for i, elem := range s.elements {
   735  		if i != 0 {
   736  			b = append(b, ',')
   737  		}
   738  
   739  		// encodeString never returns an error so we ignore it here
   740  		b, _ = e.encodeString(b, unsafe.Pointer(&elem.key))
   741  		if elem.val.(bool) {
   742  			b = append(b, ":true"...)
   743  		} else {
   744  			b = append(b, ":false"...)
   745  		}
   746  	}
   747  
   748  	for i := range s.elements {
   749  		s.elements[i] = element{}
   750  	}
   751  
   752  	s.elements = s.elements[:0]
   753  	mapslicePool.Put(s)
   754  
   755  	b = append(b, '}')
   756  	return b, nil
   757  }
   758  
   759  func (e encoder) encodeStruct(b []byte, p unsafe.Pointer, st *structType) ([]byte, error) {
   760  	var start = len(b)
   761  	var err error
   762  	var k string
   763  	var n int
   764  	b = append(b, '{')
   765  
   766  	escapeHTML := (e.flags & EscapeHTML) != 0
   767  
   768  	for i := range st.fields {
   769  		f := &st.fields[i]
   770  		v := unsafe.Pointer(uintptr(p) + f.offset)
   771  
   772  		if f.omitempty && f.empty(v) {
   773  			continue
   774  		}
   775  
   776  		if escapeHTML {
   777  			k = f.html
   778  		} else {
   779  			k = f.json
   780  		}
   781  
   782  		lengthBeforeKey := len(b)
   783  
   784  		if n != 0 {
   785  			b = append(b, k...)
   786  		} else {
   787  			b = append(b, k[1:]...)
   788  		}
   789  
   790  		if b, err = f.codec.encode(e, b, v); err != nil {
   791  			if err == (rollback{}) {
   792  				b = b[:lengthBeforeKey]
   793  				continue
   794  			}
   795  			return b[:start], err
   796  		}
   797  
   798  		n++
   799  	}
   800  
   801  	b = append(b, '}')
   802  	return b, nil
   803  }
   804  
   805  type rollback struct{}
   806  
   807  func (rollback) Error() string { return "rollback" }
   808  
   809  func (e encoder) encodeEmbeddedStructPointer(b []byte, p unsafe.Pointer, t reflect.Type, unexported bool, offset uintptr, encode encodeFunc) ([]byte, error) {
   810  	p = *(*unsafe.Pointer)(p)
   811  	if p == nil {
   812  		return b, rollback{}
   813  	}
   814  	return encode(e, b, unsafe.Pointer(uintptr(p)+offset))
   815  }
   816  
   817  func (e encoder) encodePointer(b []byte, p unsafe.Pointer, t reflect.Type, encode encodeFunc) ([]byte, error) {
   818  	if p = *(*unsafe.Pointer)(p); p != nil {
   819  		if e.ptrDepth++; e.ptrDepth >= startDetectingCyclesAfter {
   820  			if _, seen := e.ptrSeen[p]; seen {
   821  				// TODO: reconstruct the reflect.Value from p + t so we can set
   822  				// the erorr's Value field?
   823  				return b, &UnsupportedValueError{Str: fmt.Sprintf("encountered a cycle via %s", t)}
   824  			}
   825  			if e.ptrSeen == nil {
   826  				e.ptrSeen = make(map[unsafe.Pointer]struct{})
   827  			}
   828  			e.ptrSeen[p] = struct{}{}
   829  			defer delete(e.ptrSeen, p)
   830  		}
   831  		return encode(e, b, p)
   832  	}
   833  	return e.encodeNull(b, nil)
   834  }
   835  
   836  func (e encoder) encodeInterface(b []byte, p unsafe.Pointer) ([]byte, error) {
   837  	return Append(b, *(*interface{})(p), e.flags)
   838  }
   839  
   840  func (e encoder) encodeMaybeEmptyInterface(b []byte, p unsafe.Pointer, t reflect.Type) ([]byte, error) {
   841  	return Append(b, reflect.NewAt(t, p).Elem().Interface(), e.flags)
   842  }
   843  
   844  func (e encoder) encodeUnsupportedTypeError(b []byte, p unsafe.Pointer, t reflect.Type) ([]byte, error) {
   845  	return b, &UnsupportedTypeError{Type: t}
   846  }
   847  
   848  func (e encoder) encodeRawMessage(b []byte, p unsafe.Pointer) ([]byte, error) {
   849  	v := *(*RawMessage)(p)
   850  
   851  	if v == nil {
   852  		return append(b, "null"...), nil
   853  	}
   854  
   855  	var s []byte
   856  
   857  	if (e.flags & TrustRawMessage) != 0 {
   858  		s = v
   859  	} else {
   860  		var err error
   861  		v = skipSpaces(v) // don't assume that a RawMessage starts with a token.
   862  		d := decoder{}
   863  		s, _, _, err = d.parseValue(v)
   864  		if err != nil {
   865  			return b, &UnsupportedValueError{Value: reflect.ValueOf(v), Str: err.Error()}
   866  		}
   867  	}
   868  
   869  	if (e.flags & EscapeHTML) != 0 {
   870  		return appendCompactEscapeHTML(b, s), nil
   871  	}
   872  
   873  	return append(b, s...), nil
   874  }
   875  
   876  func (e encoder) encodeJSONMarshaler(b []byte, p unsafe.Pointer, t reflect.Type, pointer bool) ([]byte, error) {
   877  	v := reflect.NewAt(t, p)
   878  
   879  	if !pointer {
   880  		v = v.Elem()
   881  	}
   882  
   883  	switch v.Kind() {
   884  	case reflect.Ptr, reflect.Interface:
   885  		if v.IsNil() {
   886  			return append(b, "null"...), nil
   887  		}
   888  	}
   889  
   890  	j, err := v.Interface().(Marshaler).MarshalJSON()
   891  	if err != nil {
   892  		return b, err
   893  	}
   894  
   895  	d := decoder{}
   896  	s, _, _, err := d.parseValue(j)
   897  	if err != nil {
   898  		return b, &MarshalerError{Type: t, Err: err}
   899  	}
   900  
   901  	if (e.flags & EscapeHTML) != 0 {
   902  		return appendCompactEscapeHTML(b, s), nil
   903  	}
   904  
   905  	return append(b, s...), nil
   906  }
   907  
   908  func (e encoder) encodeTextMarshaler(b []byte, p unsafe.Pointer, t reflect.Type, pointer bool) ([]byte, error) {
   909  	v := reflect.NewAt(t, p)
   910  
   911  	if !pointer {
   912  		v = v.Elem()
   913  	}
   914  
   915  	switch v.Kind() {
   916  	case reflect.Ptr, reflect.Interface:
   917  		if v.IsNil() {
   918  			return append(b, `null`...), nil
   919  		}
   920  	}
   921  
   922  	s, err := v.Interface().(encoding.TextMarshaler).MarshalText()
   923  	if err != nil {
   924  		return b, err
   925  	}
   926  
   927  	return e.encodeString(b, unsafe.Pointer(&s))
   928  }
   929  
   930  func appendCompactEscapeHTML(dst []byte, src []byte) []byte {
   931  	start := 0
   932  	escape := false
   933  	inString := false
   934  
   935  	for i, c := range src {
   936  		if !inString {
   937  			switch c {
   938  			case '"': // enter string
   939  				inString = true
   940  			case ' ', '\n', '\r', '\t': // skip space
   941  				if start < i {
   942  					dst = append(dst, src[start:i]...)
   943  				}
   944  				start = i + 1
   945  			}
   946  			continue
   947  		}
   948  
   949  		if escape {
   950  			escape = false
   951  			continue
   952  		}
   953  
   954  		if c == '\\' {
   955  			escape = true
   956  			continue
   957  		}
   958  
   959  		if c == '"' {
   960  			inString = false
   961  			continue
   962  		}
   963  
   964  		if c == '<' || c == '>' || c == '&' {
   965  			if start < i {
   966  				dst = append(dst, src[start:i]...)
   967  			}
   968  			dst = append(dst, `\u00`...)
   969  			dst = append(dst, hex[c>>4], hex[c&0xF])
   970  			start = i + 1
   971  			continue
   972  		}
   973  
   974  		// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
   975  		if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
   976  			if start < i {
   977  				dst = append(dst, src[start:i]...)
   978  			}
   979  			dst = append(dst, `\u202`...)
   980  			dst = append(dst, hex[src[i+2]&0xF])
   981  			start = i + 3
   982  			continue
   983  		}
   984  	}
   985  
   986  	if start < len(src) {
   987  		dst = append(dst, src[start:]...)
   988  	}
   989  
   990  	return dst
   991  }