github.com/neilotoole/jsoncolor@v0.6.0/encode.go (about)

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