github.com/night-codes/go-json@v0.9.15/internal/encoder/encoder.go (about)

     1  package encoder
     2  
     3  import (
     4  	"bytes"
     5  	"encoding"
     6  	"encoding/base64"
     7  	"encoding/json"
     8  	"fmt"
     9  	"math"
    10  	"reflect"
    11  	"strconv"
    12  	"strings"
    13  	"sync"
    14  	"unsafe"
    15  
    16  	"github.com/night-codes/go-json/internal/errors"
    17  	"github.com/night-codes/go-json/internal/runtime"
    18  )
    19  
    20  func (t OpType) IsMultipleOpHead() bool {
    21  	switch t {
    22  	case OpStructHead:
    23  		return true
    24  	case OpStructHeadSlice:
    25  		return true
    26  	case OpStructHeadArray:
    27  		return true
    28  	case OpStructHeadMap:
    29  		return true
    30  	case OpStructHeadStruct:
    31  		return true
    32  	case OpStructHeadOmitEmpty:
    33  		return true
    34  	case OpStructHeadOmitEmptySlice:
    35  		return true
    36  	case OpStructHeadOmitEmptyArray:
    37  		return true
    38  	case OpStructHeadOmitEmptyMap:
    39  		return true
    40  	case OpStructHeadOmitEmptyStruct:
    41  		return true
    42  	case OpStructHeadSlicePtr:
    43  		return true
    44  	case OpStructHeadOmitEmptySlicePtr:
    45  		return true
    46  	case OpStructHeadArrayPtr:
    47  		return true
    48  	case OpStructHeadOmitEmptyArrayPtr:
    49  		return true
    50  	case OpStructHeadMapPtr:
    51  		return true
    52  	case OpStructHeadOmitEmptyMapPtr:
    53  		return true
    54  	}
    55  	return false
    56  }
    57  
    58  func (t OpType) IsMultipleOpField() bool {
    59  	switch t {
    60  	case OpStructField:
    61  		return true
    62  	case OpStructFieldSlice:
    63  		return true
    64  	case OpStructFieldArray:
    65  		return true
    66  	case OpStructFieldMap:
    67  		return true
    68  	case OpStructFieldStruct:
    69  		return true
    70  	case OpStructFieldOmitEmpty:
    71  		return true
    72  	case OpStructFieldOmitEmptySlice:
    73  		return true
    74  	case OpStructFieldOmitEmptyArray:
    75  		return true
    76  	case OpStructFieldOmitEmptyMap:
    77  		return true
    78  	case OpStructFieldOmitEmptyStruct:
    79  		return true
    80  	case OpStructFieldSlicePtr:
    81  		return true
    82  	case OpStructFieldOmitEmptySlicePtr:
    83  		return true
    84  	case OpStructFieldArrayPtr:
    85  		return true
    86  	case OpStructFieldOmitEmptyArrayPtr:
    87  		return true
    88  	case OpStructFieldMapPtr:
    89  		return true
    90  	case OpStructFieldOmitEmptyMapPtr:
    91  		return true
    92  	}
    93  	return false
    94  }
    95  
    96  type OpcodeSet struct {
    97  	Type                     *runtime.Type
    98  	NoescapeKeyCode          *Opcode
    99  	EscapeKeyCode            *Opcode
   100  	InterfaceNoescapeKeyCode *Opcode
   101  	InterfaceEscapeKeyCode   *Opcode
   102  	CodeLength               int
   103  	EndCode                  *Opcode
   104  	Code                     Code
   105  	QueryCache               map[string]*OpcodeSet
   106  	cacheMu                  sync.RWMutex
   107  }
   108  
   109  func (s *OpcodeSet) getQueryCache(hash string) *OpcodeSet {
   110  	s.cacheMu.RLock()
   111  	codeSet := s.QueryCache[hash]
   112  	s.cacheMu.RUnlock()
   113  	return codeSet
   114  }
   115  
   116  func (s *OpcodeSet) setQueryCache(hash string, codeSet *OpcodeSet) {
   117  	s.cacheMu.Lock()
   118  	s.QueryCache[hash] = codeSet
   119  	s.cacheMu.Unlock()
   120  }
   121  
   122  type CompiledCode struct {
   123  	Code    *Opcode
   124  	Linked  bool // whether recursive code already have linked
   125  	CurLen  uintptr
   126  	NextLen uintptr
   127  }
   128  
   129  const StartDetectingCyclesAfter = 1000
   130  
   131  func Load(base uintptr, idx uintptr) uintptr {
   132  	addr := base + idx
   133  	return **(**uintptr)(unsafe.Pointer(&addr))
   134  }
   135  
   136  func Store(base uintptr, idx uintptr, p uintptr) {
   137  	addr := base + idx
   138  	**(**uintptr)(unsafe.Pointer(&addr)) = p
   139  }
   140  
   141  func LoadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr {
   142  	addr := base + idx
   143  	p := **(**uintptr)(unsafe.Pointer(&addr))
   144  	if p == 0 {
   145  		return 0
   146  	}
   147  	return PtrToPtr(p)
   148  	/*
   149  		for i := 0; i < ptrNum; i++ {
   150  			if p == 0 {
   151  				return p
   152  			}
   153  			p = PtrToPtr(p)
   154  		}
   155  		return p
   156  	*/
   157  }
   158  
   159  func PtrToUint64(p uintptr) uint64              { return **(**uint64)(unsafe.Pointer(&p)) }
   160  func PtrToFloat32(p uintptr) float32            { return **(**float32)(unsafe.Pointer(&p)) }
   161  func PtrToFloat64(p uintptr) float64            { return **(**float64)(unsafe.Pointer(&p)) }
   162  func PtrToBool(p uintptr) bool                  { return **(**bool)(unsafe.Pointer(&p)) }
   163  func PtrToBytes(p uintptr) []byte               { return **(**[]byte)(unsafe.Pointer(&p)) }
   164  func PtrToNumber(p uintptr) json.Number         { return **(**json.Number)(unsafe.Pointer(&p)) }
   165  func PtrToString(p uintptr) string              { return **(**string)(unsafe.Pointer(&p)) }
   166  func PtrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) }
   167  func PtrToPtr(p uintptr) uintptr {
   168  	return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p)))
   169  }
   170  func PtrToNPtr(p uintptr, ptrNum int) uintptr {
   171  	for i := 0; i < ptrNum; i++ {
   172  		if p == 0 {
   173  			return 0
   174  		}
   175  		p = PtrToPtr(p)
   176  	}
   177  	return p
   178  }
   179  
   180  func PtrToUnsafePtr(p uintptr) unsafe.Pointer {
   181  	return *(*unsafe.Pointer)(unsafe.Pointer(&p))
   182  }
   183  func PtrToInterface(code *Opcode, p uintptr) interface{} {
   184  	return *(*interface{})(unsafe.Pointer(&emptyInterface{
   185  		typ: code.Type,
   186  		ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
   187  	}))
   188  }
   189  
   190  func ErrUnsupportedValue(code *Opcode, ptr uintptr) *errors.UnsupportedValueError {
   191  	v := *(*interface{})(unsafe.Pointer(&emptyInterface{
   192  		typ: code.Type,
   193  		ptr: *(*unsafe.Pointer)(unsafe.Pointer(&ptr)),
   194  	}))
   195  	return &errors.UnsupportedValueError{
   196  		Value: reflect.ValueOf(v),
   197  		Str:   fmt.Sprintf("encountered a cycle via %s", code.Type),
   198  	}
   199  }
   200  
   201  func ErrUnsupportedFloat(v float64) *errors.UnsupportedValueError {
   202  	return &errors.UnsupportedValueError{
   203  		Value: reflect.ValueOf(v),
   204  		Str:   strconv.FormatFloat(v, 'g', -1, 64),
   205  	}
   206  }
   207  
   208  func ErrMarshalerWithCode(code *Opcode, err error) *errors.MarshalerError {
   209  	return &errors.MarshalerError{
   210  		Type: runtime.RType2Type(code.Type),
   211  		Err:  err,
   212  	}
   213  }
   214  
   215  type emptyInterface struct {
   216  	typ *runtime.Type
   217  	ptr unsafe.Pointer
   218  }
   219  
   220  type MapItem struct {
   221  	Key   []byte
   222  	Value []byte
   223  }
   224  
   225  type Mapslice struct {
   226  	Items []MapItem
   227  }
   228  
   229  func (m *Mapslice) Len() int {
   230  	return len(m.Items)
   231  }
   232  
   233  func (m *Mapslice) Less(i, j int) bool {
   234  	return bytes.Compare(m.Items[i].Key, m.Items[j].Key) < 0
   235  }
   236  
   237  func (m *Mapslice) Swap(i, j int) {
   238  	m.Items[i], m.Items[j] = m.Items[j], m.Items[i]
   239  }
   240  
   241  //nolint:structcheck,unused
   242  type mapIter struct {
   243  	key         unsafe.Pointer
   244  	elem        unsafe.Pointer
   245  	t           unsafe.Pointer
   246  	h           unsafe.Pointer
   247  	buckets     unsafe.Pointer
   248  	bptr        unsafe.Pointer
   249  	overflow    unsafe.Pointer
   250  	oldoverflow unsafe.Pointer
   251  	startBucket uintptr
   252  	offset      uint8
   253  	wrapped     bool
   254  	B           uint8
   255  	i           uint8
   256  	bucket      uintptr
   257  	checkBucket uintptr
   258  }
   259  
   260  type MapContext struct {
   261  	Start int
   262  	First int
   263  	Idx   int
   264  	Slice *Mapslice
   265  	Buf   []byte
   266  	Len   int
   267  	Iter  mapIter
   268  }
   269  
   270  var mapContextPool = sync.Pool{
   271  	New: func() interface{} {
   272  		return &MapContext{
   273  			Slice: &Mapslice{},
   274  		}
   275  	},
   276  }
   277  
   278  func NewMapContext(mapLen int, unorderedMap bool) *MapContext {
   279  	ctx := mapContextPool.Get().(*MapContext)
   280  	if !unorderedMap {
   281  		if len(ctx.Slice.Items) < mapLen {
   282  			ctx.Slice.Items = make([]MapItem, mapLen)
   283  		} else {
   284  			ctx.Slice.Items = ctx.Slice.Items[:mapLen]
   285  		}
   286  	}
   287  	ctx.Buf = ctx.Buf[:0]
   288  	ctx.Iter = mapIter{}
   289  	ctx.Idx = 0
   290  	ctx.Len = mapLen
   291  	return ctx
   292  }
   293  
   294  func ReleaseMapContext(c *MapContext) {
   295  	mapContextPool.Put(c)
   296  }
   297  
   298  //go:linkname MapIterInit runtime.mapiterinit
   299  //go:noescape
   300  func MapIterInit(mapType *runtime.Type, m unsafe.Pointer, it *mapIter)
   301  
   302  //go:linkname MapIterKey reflect.mapiterkey
   303  //go:noescape
   304  func MapIterKey(it *mapIter) unsafe.Pointer
   305  
   306  //go:linkname MapIterNext reflect.mapiternext
   307  //go:noescape
   308  func MapIterNext(it *mapIter)
   309  
   310  //go:linkname MapLen reflect.maplen
   311  //go:noescape
   312  func MapLen(m unsafe.Pointer) int
   313  
   314  func AppendByteSlice(_ *RuntimeContext, b []byte, src []byte) []byte {
   315  	if src == nil {
   316  		return append(b, `null`...)
   317  	}
   318  	encodedLen := base64.StdEncoding.EncodedLen(len(src))
   319  	b = append(b, '"')
   320  	pos := len(b)
   321  	remainLen := cap(b[pos:])
   322  	var buf []byte
   323  	if remainLen > encodedLen {
   324  		buf = b[pos : pos+encodedLen]
   325  	} else {
   326  		buf = make([]byte, encodedLen)
   327  	}
   328  	base64.StdEncoding.Encode(buf, src)
   329  	return append(append(b, buf...), '"')
   330  }
   331  
   332  func AppendFloat32(_ *RuntimeContext, b []byte, v float32) []byte {
   333  	f64 := float64(v)
   334  	abs := math.Abs(f64)
   335  	fmt := byte('f')
   336  	// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
   337  	if abs != 0 {
   338  		f32 := float32(abs)
   339  		if f32 < 1e-6 || f32 >= 1e21 {
   340  			fmt = 'e'
   341  		}
   342  	}
   343  	return strconv.AppendFloat(b, f64, fmt, -1, 32)
   344  }
   345  
   346  func AppendFloat64(_ *RuntimeContext, b []byte, v float64) []byte {
   347  	abs := math.Abs(v)
   348  	fmt := byte('f')
   349  	// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
   350  	if abs != 0 {
   351  		if abs < 1e-6 || abs >= 1e21 {
   352  			fmt = 'e'
   353  		}
   354  	}
   355  	return strconv.AppendFloat(b, v, fmt, -1, 64)
   356  }
   357  
   358  func AppendBool(_ *RuntimeContext, b []byte, v bool) []byte {
   359  	if v {
   360  		return append(b, "true"...)
   361  	}
   362  	return append(b, "false"...)
   363  }
   364  
   365  var (
   366  	floatTable = [256]bool{
   367  		'0': true,
   368  		'1': true,
   369  		'2': true,
   370  		'3': true,
   371  		'4': true,
   372  		'5': true,
   373  		'6': true,
   374  		'7': true,
   375  		'8': true,
   376  		'9': true,
   377  		'.': true,
   378  		'e': true,
   379  		'E': true,
   380  		'+': true,
   381  		'-': true,
   382  	}
   383  )
   384  
   385  func AppendNumber(_ *RuntimeContext, b []byte, n json.Number) ([]byte, error) {
   386  	if len(n) == 0 {
   387  		return append(b, '0'), nil
   388  	}
   389  	for i := 0; i < len(n); i++ {
   390  		if !floatTable[n[i]] {
   391  			return nil, fmt.Errorf("json: invalid number literal %q", n)
   392  		}
   393  	}
   394  	b = append(b, n...)
   395  	return b, nil
   396  }
   397  
   398  func AppendMarshalJSON(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
   399  	rv := reflect.ValueOf(v) // convert by dynamic interface type
   400  	if (code.Flags & AddrForMarshalerFlags) != 0 {
   401  		if rv.CanAddr() {
   402  			rv = rv.Addr()
   403  		} else {
   404  			newV := reflect.New(rv.Type())
   405  			newV.Elem().Set(rv)
   406  			rv = newV
   407  		}
   408  	}
   409  	v = rv.Interface()
   410  	var bb []byte
   411  	if (code.Flags & MarshalerContextFlags) != 0 {
   412  		marshaler, ok := v.(marshalerContext)
   413  		if !ok {
   414  			return AppendNull(ctx, b), nil
   415  		}
   416  		stdctx := ctx.Option.Context
   417  		if ctx.Option.Flag&FieldQueryOption != 0 {
   418  			stdctx = SetFieldQueryToContext(stdctx, code.FieldQuery)
   419  		}
   420  		b, err := marshaler.MarshalJSON(stdctx)
   421  		if err != nil {
   422  			return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
   423  		}
   424  		bb = b
   425  	} else {
   426  		marshaler, ok := v.(json.Marshaler)
   427  		if !ok {
   428  			return AppendNull(ctx, b), nil
   429  		}
   430  		b, err := marshaler.MarshalJSON()
   431  		if err != nil {
   432  			return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
   433  		}
   434  		bb = b
   435  	}
   436  	marshalBuf := ctx.MarshalBuf[:0]
   437  	marshalBuf = append(append(marshalBuf, bb...), nul)
   438  	compactedBuf, err := compact(b, marshalBuf, (ctx.Option.Flag&HTMLEscapeOption) != 0)
   439  	if err != nil {
   440  		return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
   441  	}
   442  	ctx.MarshalBuf = marshalBuf
   443  	return compactedBuf, nil
   444  }
   445  
   446  func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
   447  	rv := reflect.ValueOf(v) // convert by dynamic interface type
   448  	if (code.Flags & AddrForMarshalerFlags) != 0 {
   449  		if rv.CanAddr() {
   450  			rv = rv.Addr()
   451  		} else {
   452  			newV := reflect.New(rv.Type())
   453  			newV.Elem().Set(rv)
   454  			rv = newV
   455  		}
   456  	}
   457  	v = rv.Interface()
   458  	var bb []byte
   459  	if (code.Flags & MarshalerContextFlags) != 0 {
   460  		marshaler, ok := v.(marshalerContext)
   461  		if !ok {
   462  			return AppendNull(ctx, b), nil
   463  		}
   464  		b, err := marshaler.MarshalJSON(ctx.Option.Context)
   465  		if err != nil {
   466  			return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
   467  		}
   468  		bb = b
   469  	} else {
   470  		marshaler, ok := v.(json.Marshaler)
   471  		if !ok {
   472  			return AppendNull(ctx, b), nil
   473  		}
   474  		b, err := marshaler.MarshalJSON()
   475  		if err != nil {
   476  			return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
   477  		}
   478  		bb = b
   479  	}
   480  	marshalBuf := ctx.MarshalBuf[:0]
   481  	marshalBuf = append(append(marshalBuf, bb...), nul)
   482  	indentedBuf, err := doIndent(
   483  		b,
   484  		marshalBuf,
   485  		string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), int(ctx.BaseIndent+code.Indent)),
   486  		string(ctx.IndentStr),
   487  		(ctx.Option.Flag&HTMLEscapeOption) != 0,
   488  	)
   489  	if err != nil {
   490  		return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
   491  	}
   492  	ctx.MarshalBuf = marshalBuf
   493  	return indentedBuf, nil
   494  }
   495  
   496  func AppendMarshalText(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
   497  	rv := reflect.ValueOf(v) // convert by dynamic interface type
   498  	if (code.Flags & AddrForMarshalerFlags) != 0 {
   499  		if rv.CanAddr() {
   500  			rv = rv.Addr()
   501  		} else {
   502  			newV := reflect.New(rv.Type())
   503  			newV.Elem().Set(rv)
   504  			rv = newV
   505  		}
   506  	}
   507  	v = rv.Interface()
   508  	marshaler, ok := v.(encoding.TextMarshaler)
   509  	if !ok {
   510  		return AppendNull(ctx, b), nil
   511  	}
   512  	bytes, err := marshaler.MarshalText()
   513  	if err != nil {
   514  		return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
   515  	}
   516  	return AppendString(ctx, b, *(*string)(unsafe.Pointer(&bytes))), nil
   517  }
   518  
   519  func AppendMarshalTextIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
   520  	rv := reflect.ValueOf(v) // convert by dynamic interface type
   521  	if (code.Flags & AddrForMarshalerFlags) != 0 {
   522  		if rv.CanAddr() {
   523  			rv = rv.Addr()
   524  		} else {
   525  			newV := reflect.New(rv.Type())
   526  			newV.Elem().Set(rv)
   527  			rv = newV
   528  		}
   529  	}
   530  	v = rv.Interface()
   531  	marshaler, ok := v.(encoding.TextMarshaler)
   532  	if !ok {
   533  		return AppendNull(ctx, b), nil
   534  	}
   535  	bytes, err := marshaler.MarshalText()
   536  	if err != nil {
   537  		return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
   538  	}
   539  	return AppendString(ctx, b, *(*string)(unsafe.Pointer(&bytes))), nil
   540  }
   541  
   542  func AppendNull(_ *RuntimeContext, b []byte) []byte {
   543  	return append(b, "null"...)
   544  }
   545  
   546  func AppendComma(_ *RuntimeContext, b []byte) []byte {
   547  	return append(b, ',')
   548  }
   549  
   550  func AppendCommaIndent(_ *RuntimeContext, b []byte) []byte {
   551  	return append(b, ',', '\n')
   552  }
   553  
   554  func AppendStructEnd(_ *RuntimeContext, b []byte) []byte {
   555  	return append(b, '}', ',')
   556  }
   557  
   558  func AppendStructEndIndent(ctx *RuntimeContext, code *Opcode, b []byte) []byte {
   559  	b = append(b, '\n')
   560  	b = append(b, ctx.Prefix...)
   561  	indentNum := ctx.BaseIndent + code.Indent - 1
   562  	for i := uint32(0); i < indentNum; i++ {
   563  		b = append(b, ctx.IndentStr...)
   564  	}
   565  	return append(b, '}', ',', '\n')
   566  }
   567  
   568  func AppendIndent(ctx *RuntimeContext, b []byte, indent uint32) []byte {
   569  	b = append(b, ctx.Prefix...)
   570  	indentNum := ctx.BaseIndent + indent
   571  	for i := uint32(0); i < indentNum; i++ {
   572  		b = append(b, ctx.IndentStr...)
   573  	}
   574  	return b
   575  }
   576  
   577  func IsNilForMarshaler(v interface{}) bool {
   578  	rv := reflect.ValueOf(v)
   579  	switch rv.Kind() {
   580  	case reflect.Bool:
   581  		return !rv.Bool()
   582  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   583  		return rv.Int() == 0
   584  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   585  		return rv.Uint() == 0
   586  	case reflect.Float32, reflect.Float64:
   587  		return math.Float64bits(rv.Float()) == 0
   588  	case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Func:
   589  		return rv.IsNil()
   590  	case reflect.Slice:
   591  		return rv.IsNil() || rv.Len() == 0
   592  	case reflect.String:
   593  		return rv.Len() == 0
   594  	}
   595  	return false
   596  }