github.com/neilotoole/jsoncolor@v0.7.2-0.20231115150201-1637fae69be1/encode.go (about)

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