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