github.com/3JoB/go-json@v0.10.4/internal/encoder/code.go (about)

     1  package encoder
     2  
     3  import (
     4  	"fmt"
     5  	"unsafe"
     6  
     7  	"github.com/3JoB/go-reflect"
     8  	"github.com/3JoB/unsafeConvert"
     9  
    10  	"github.com/3JoB/go-json/internal/runtime"
    11  )
    12  
    13  type Code interface {
    14  	Kind() CodeKind
    15  	ToOpcode(*compileContext) Opcodes
    16  	Filter(*FieldQuery) Code
    17  }
    18  
    19  type AnonymousCode interface {
    20  	ToAnonymousOpcode(*compileContext) Opcodes
    21  }
    22  
    23  type Opcodes []*Opcode
    24  
    25  func (o Opcodes) First() *Opcode {
    26  	if len(o) == 0 {
    27  		return nil
    28  	}
    29  	return o[0]
    30  }
    31  
    32  func (o Opcodes) Last() *Opcode {
    33  	if len(o) == 0 {
    34  		return nil
    35  	}
    36  	return o[len(o)-1]
    37  }
    38  
    39  func (o Opcodes) Add(codes ...*Opcode) Opcodes {
    40  	return append(o, codes...)
    41  }
    42  
    43  type CodeKind int
    44  
    45  const (
    46  	CodeKindInterface CodeKind = iota
    47  	CodeKindPtr
    48  	CodeKindInt
    49  	CodeKindUint
    50  	CodeKindFloat
    51  	CodeKindString
    52  	CodeKindBool
    53  	CodeKindStruct
    54  	CodeKindMap
    55  	CodeKindSlice
    56  	CodeKindArray
    57  	CodeKindBytes
    58  	CodeKindMarshalJSON
    59  	CodeKindMarshalText
    60  	CodeKindRecursive
    61  )
    62  
    63  type IntCode struct {
    64  	typ      *runtime.Type
    65  	bitSize  uint8
    66  	isString bool
    67  	isPtr    bool
    68  }
    69  
    70  func (c *IntCode) Kind() CodeKind {
    71  	return CodeKindInt
    72  }
    73  
    74  func (c *IntCode) ToOpcode(ctx *compileContext) Opcodes {
    75  	var code *Opcode
    76  	switch {
    77  	case c.isPtr:
    78  		code = newOpCode(ctx, c.typ, OpIntPtr)
    79  	case c.isString:
    80  		code = newOpCode(ctx, c.typ, OpIntString)
    81  	default:
    82  		code = newOpCode(ctx, c.typ, OpInt)
    83  	}
    84  	code.NumBitSize = c.bitSize
    85  	ctx.incIndex()
    86  	return Opcodes{code}
    87  }
    88  
    89  func (c *IntCode) Filter(_ *FieldQuery) Code {
    90  	return c
    91  }
    92  
    93  type UintCode struct {
    94  	typ      *runtime.Type
    95  	bitSize  uint8
    96  	isString bool
    97  	isPtr    bool
    98  }
    99  
   100  func (c *UintCode) Kind() CodeKind {
   101  	return CodeKindUint
   102  }
   103  
   104  func (c *UintCode) ToOpcode(ctx *compileContext) Opcodes {
   105  	var code *Opcode
   106  	switch {
   107  	case c.isPtr:
   108  		code = newOpCode(ctx, c.typ, OpUintPtr)
   109  	case c.isString:
   110  		code = newOpCode(ctx, c.typ, OpUintString)
   111  	default:
   112  		code = newOpCode(ctx, c.typ, OpUint)
   113  	}
   114  	code.NumBitSize = c.bitSize
   115  	ctx.incIndex()
   116  	return Opcodes{code}
   117  }
   118  
   119  func (c *UintCode) Filter(_ *FieldQuery) Code {
   120  	return c
   121  }
   122  
   123  type FloatCode struct {
   124  	typ     *runtime.Type
   125  	bitSize uint8
   126  	isPtr   bool
   127  }
   128  
   129  func (c *FloatCode) Kind() CodeKind {
   130  	return CodeKindFloat
   131  }
   132  
   133  func (c *FloatCode) ToOpcode(ctx *compileContext) Opcodes {
   134  	var code *Opcode
   135  	switch {
   136  	case c.isPtr:
   137  		switch c.bitSize {
   138  		case 32:
   139  			code = newOpCode(ctx, c.typ, OpFloat32Ptr)
   140  		default:
   141  			code = newOpCode(ctx, c.typ, OpFloat64Ptr)
   142  		}
   143  	default:
   144  		switch c.bitSize {
   145  		case 32:
   146  			code = newOpCode(ctx, c.typ, OpFloat32)
   147  		default:
   148  			code = newOpCode(ctx, c.typ, OpFloat64)
   149  		}
   150  	}
   151  	ctx.incIndex()
   152  	return Opcodes{code}
   153  }
   154  
   155  func (c *FloatCode) Filter(_ *FieldQuery) Code {
   156  	return c
   157  }
   158  
   159  type StringCode struct {
   160  	typ   *runtime.Type
   161  	isPtr bool
   162  }
   163  
   164  func (c *StringCode) Kind() CodeKind {
   165  	return CodeKindString
   166  }
   167  
   168  func (c *StringCode) ToOpcode(ctx *compileContext) Opcodes {
   169  	isJSONNumberType := c.typ == runtime.Type2RType(reflect.ToRT(jsonNumberType))
   170  	var code *Opcode
   171  	if c.isPtr {
   172  		if isJSONNumberType {
   173  			code = newOpCode(ctx, c.typ, OpNumberPtr)
   174  		} else {
   175  			code = newOpCode(ctx, c.typ, OpStringPtr)
   176  		}
   177  	} else {
   178  		if isJSONNumberType {
   179  			code = newOpCode(ctx, c.typ, OpNumber)
   180  		} else {
   181  			code = newOpCode(ctx, c.typ, OpString)
   182  		}
   183  	}
   184  	ctx.incIndex()
   185  	return Opcodes{code}
   186  }
   187  
   188  func (c *StringCode) Filter(_ *FieldQuery) Code {
   189  	return c
   190  }
   191  
   192  type BoolCode struct {
   193  	typ   *runtime.Type
   194  	isPtr bool
   195  }
   196  
   197  func (c *BoolCode) Kind() CodeKind {
   198  	return CodeKindBool
   199  }
   200  
   201  func (c *BoolCode) ToOpcode(ctx *compileContext) Opcodes {
   202  	var code *Opcode
   203  	switch {
   204  	case c.isPtr:
   205  		code = newOpCode(ctx, c.typ, OpBoolPtr)
   206  	default:
   207  		code = newOpCode(ctx, c.typ, OpBool)
   208  	}
   209  	ctx.incIndex()
   210  	return Opcodes{code}
   211  }
   212  
   213  func (c *BoolCode) Filter(_ *FieldQuery) Code {
   214  	return c
   215  }
   216  
   217  type BytesCode struct {
   218  	typ   *runtime.Type
   219  	isPtr bool
   220  }
   221  
   222  func (c *BytesCode) Kind() CodeKind {
   223  	return CodeKindBytes
   224  }
   225  
   226  func (c *BytesCode) ToOpcode(ctx *compileContext) Opcodes {
   227  	var code *Opcode
   228  	switch {
   229  	case c.isPtr:
   230  		code = newOpCode(ctx, c.typ, OpBytesPtr)
   231  	default:
   232  		code = newOpCode(ctx, c.typ, OpBytes)
   233  	}
   234  	ctx.incIndex()
   235  	return Opcodes{code}
   236  }
   237  
   238  func (c *BytesCode) Filter(_ *FieldQuery) Code {
   239  	return c
   240  }
   241  
   242  type SliceCode struct {
   243  	typ   *runtime.Type
   244  	value Code
   245  }
   246  
   247  func (c *SliceCode) Kind() CodeKind {
   248  	return CodeKindSlice
   249  }
   250  
   251  func (c *SliceCode) ToOpcode(ctx *compileContext) Opcodes {
   252  	// header => opcode => elem => end
   253  	//             ^        |
   254  	//             |________|
   255  	size := c.typ.Elem().Size()
   256  	header := newSliceHeaderCode(ctx, c.typ)
   257  	ctx.incIndex()
   258  
   259  	ctx.incIndent()
   260  	codes := c.value.ToOpcode(ctx)
   261  	ctx.decIndent()
   262  
   263  	codes.First().Flags |= IndirectFlags
   264  	elemCode := newSliceElemCode(ctx, c.typ.Elem(), header, size)
   265  	ctx.incIndex()
   266  	end := newOpCode(ctx, c.typ, OpSliceEnd)
   267  	ctx.incIndex()
   268  	header.End = end
   269  	header.Next = codes.First()
   270  	codes.Last().Next = elemCode
   271  	elemCode.Next = codes.First()
   272  	elemCode.End = end
   273  	return Opcodes{header}.Add(codes...).Add(elemCode).Add(end)
   274  }
   275  
   276  func (c *SliceCode) Filter(_ *FieldQuery) Code {
   277  	return c
   278  }
   279  
   280  type ArrayCode struct {
   281  	typ   *runtime.Type
   282  	value Code
   283  }
   284  
   285  func (c *ArrayCode) Kind() CodeKind {
   286  	return CodeKindArray
   287  }
   288  
   289  func (c *ArrayCode) ToOpcode(ctx *compileContext) Opcodes {
   290  	// header => opcode => elem => end
   291  	//             ^        |
   292  	//             |________|
   293  	elem := c.typ.Elem()
   294  	alen := c.typ.Len()
   295  	size := elem.Size()
   296  
   297  	header := newArrayHeaderCode(ctx, c.typ, alen)
   298  	ctx.incIndex()
   299  
   300  	ctx.incIndent()
   301  	codes := c.value.ToOpcode(ctx)
   302  	ctx.decIndent()
   303  
   304  	codes.First().Flags |= IndirectFlags
   305  
   306  	elemCode := newArrayElemCode(ctx, elem, header, alen, size)
   307  	ctx.incIndex()
   308  
   309  	end := newOpCode(ctx, c.typ, OpArrayEnd)
   310  	ctx.incIndex()
   311  
   312  	header.End = end
   313  	header.Next = codes.First()
   314  	codes.Last().Next = elemCode
   315  	elemCode.Next = codes.First()
   316  	elemCode.End = end
   317  
   318  	return Opcodes{header}.Add(codes...).Add(elemCode).Add(end)
   319  }
   320  
   321  func (c *ArrayCode) Filter(_ *FieldQuery) Code {
   322  	return c
   323  }
   324  
   325  type MapCode struct {
   326  	typ   *runtime.Type
   327  	key   Code
   328  	value Code
   329  }
   330  
   331  func (c *MapCode) Kind() CodeKind {
   332  	return CodeKindMap
   333  }
   334  
   335  func (c *MapCode) ToOpcode(ctx *compileContext) Opcodes {
   336  	// header => code => value => code => key => code => value => code => end
   337  	//                                     ^                       |
   338  	//                                     |_______________________|
   339  	header := newMapHeaderCode(ctx, c.typ)
   340  	ctx.incIndex()
   341  
   342  	keyCodes := c.key.ToOpcode(ctx)
   343  
   344  	value := newMapValueCode(ctx, c.typ.Elem(), header)
   345  	ctx.incIndex()
   346  
   347  	ctx.incIndent()
   348  	valueCodes := c.value.ToOpcode(ctx)
   349  	ctx.decIndent()
   350  
   351  	valueCodes.First().Flags |= IndirectFlags
   352  
   353  	key := newMapKeyCode(ctx, c.typ.Key(), header)
   354  	ctx.incIndex()
   355  
   356  	end := newMapEndCode(ctx, c.typ, header)
   357  	ctx.incIndex()
   358  
   359  	header.Next = keyCodes.First()
   360  	keyCodes.Last().Next = value
   361  	value.Next = valueCodes.First()
   362  	valueCodes.Last().Next = key
   363  	key.Next = keyCodes.First()
   364  
   365  	header.End = end
   366  	key.End = end
   367  	value.End = end
   368  	return Opcodes{header}.Add(keyCodes...).Add(value).Add(valueCodes...).Add(key).Add(end)
   369  }
   370  
   371  func (c *MapCode) Filter(_ *FieldQuery) Code {
   372  	return c
   373  }
   374  
   375  type StructCode struct {
   376  	typ                       *runtime.Type
   377  	fields                    []*StructFieldCode
   378  	isPtr                     bool
   379  	disableIndirectConversion bool
   380  	isIndirect                bool
   381  	isRecursive               bool
   382  }
   383  
   384  func (c *StructCode) Kind() CodeKind {
   385  	return CodeKindStruct
   386  }
   387  
   388  func (c *StructCode) lastFieldCode(field *StructFieldCode, firstField *Opcode) *Opcode {
   389  	if isEmbeddedStruct(field) {
   390  		return c.lastAnonymousFieldCode(firstField)
   391  	}
   392  	lastField := firstField
   393  	for lastField.NextField != nil {
   394  		lastField = lastField.NextField
   395  	}
   396  	return lastField
   397  }
   398  
   399  func (c *StructCode) lastAnonymousFieldCode(firstField *Opcode) *Opcode {
   400  	// firstField is special StructHead operation for anonymous structure.
   401  	// So, StructHead's next operation is truly struct head operation.
   402  	for firstField.Op == OpStructHead || firstField.Op == OpStructField {
   403  		firstField = firstField.Next
   404  	}
   405  	lastField := firstField
   406  	for lastField.NextField != nil {
   407  		lastField = lastField.NextField
   408  	}
   409  	return lastField
   410  }
   411  
   412  func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes {
   413  	// header => code => structField => code => end
   414  	//                        ^          |
   415  	//                        |__________|
   416  	if c.isRecursive {
   417  		recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{})
   418  		recursive.Type = c.typ
   419  		ctx.incIndex()
   420  		*ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive)
   421  		return Opcodes{recursive}
   422  	}
   423  	codes := Opcodes{}
   424  	var prevField *Opcode
   425  	ctx.incIndent()
   426  	for idx, field := range c.fields {
   427  		isFirstField := idx == 0
   428  		isEndField := idx == len(c.fields)-1
   429  		fieldCodes := field.ToOpcode(ctx, isFirstField, isEndField)
   430  		for _, code := range fieldCodes {
   431  			if c.isIndirect {
   432  				code.Flags |= IndirectFlags
   433  			}
   434  		}
   435  		firstField := fieldCodes.First()
   436  		if len(codes) > 0 {
   437  			codes.Last().Next = firstField
   438  			firstField.Idx = codes.First().Idx
   439  		}
   440  		if prevField != nil {
   441  			prevField.NextField = firstField
   442  		}
   443  		if isEndField {
   444  			endField := fieldCodes.Last()
   445  			if len(codes) > 0 {
   446  				codes.First().End = endField
   447  			} else {
   448  				firstField.End = endField
   449  			}
   450  			codes = codes.Add(fieldCodes...)
   451  			break
   452  		}
   453  		prevField = c.lastFieldCode(field, firstField)
   454  		codes = codes.Add(fieldCodes...)
   455  	}
   456  	if len(codes) == 0 {
   457  		head := &Opcode{
   458  			Op:         OpStructHead,
   459  			Idx:        opcodeOffset(ctx.ptrIndex),
   460  			Type:       c.typ,
   461  			DisplayIdx: ctx.opcodeIndex,
   462  			Indent:     ctx.indent,
   463  		}
   464  		ctx.incOpcodeIndex()
   465  		end := &Opcode{
   466  			Op:         OpStructEnd,
   467  			Idx:        opcodeOffset(ctx.ptrIndex),
   468  			DisplayIdx: ctx.opcodeIndex,
   469  			Indent:     ctx.indent,
   470  		}
   471  		head.NextField = end
   472  		head.Next = end
   473  		head.End = end
   474  		codes = codes.Add(head, end)
   475  		ctx.incIndex()
   476  	}
   477  	ctx.decIndent()
   478  	ctx.structTypeToCodes[uintptr(unsafe.Pointer(c.typ))] = codes
   479  	return codes
   480  }
   481  
   482  func (c *StructCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
   483  	// header => code => structField => code => end
   484  	//                        ^          |
   485  	//                        |__________|
   486  	if c.isRecursive {
   487  		recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{})
   488  		recursive.Type = c.typ
   489  		ctx.incIndex()
   490  		*ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive)
   491  		return Opcodes{recursive}
   492  	}
   493  	codes := Opcodes{}
   494  	var prevField *Opcode
   495  	for idx, field := range c.fields {
   496  		isFirstField := idx == 0
   497  		isEndField := idx == len(c.fields)-1
   498  		fieldCodes := field.ToAnonymousOpcode(ctx, isFirstField, isEndField)
   499  		for _, code := range fieldCodes {
   500  			if c.isIndirect {
   501  				code.Flags |= IndirectFlags
   502  			}
   503  		}
   504  		firstField := fieldCodes.First()
   505  		if len(codes) > 0 {
   506  			codes.Last().Next = firstField
   507  			firstField.Idx = codes.First().Idx
   508  		}
   509  		if prevField != nil {
   510  			prevField.NextField = firstField
   511  		}
   512  		if isEndField {
   513  			lastField := fieldCodes.Last()
   514  			if len(codes) > 0 {
   515  				codes.First().End = lastField
   516  			} else {
   517  				firstField.End = lastField
   518  			}
   519  		}
   520  		prevField = firstField
   521  		codes = codes.Add(fieldCodes...)
   522  	}
   523  	return codes
   524  }
   525  
   526  func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) {
   527  	fields := make([]*StructFieldCode, 0, len(c.fields))
   528  	for _, field := range c.fields {
   529  		if field.isAnonymous {
   530  			structCode := field.getAnonymousStruct()
   531  			if structCode != nil && !structCode.isRecursive {
   532  				structCode.removeFieldsByTags(tags)
   533  				if len(structCode.fields) > 0 {
   534  					fields = append(fields, field)
   535  				}
   536  				continue
   537  			}
   538  		}
   539  		if tags.ExistsKey(field.key) {
   540  			continue
   541  		}
   542  		fields = append(fields, field)
   543  	}
   544  	c.fields = fields
   545  }
   546  
   547  func (c *StructCode) enableIndirect() {
   548  	if c.isIndirect {
   549  		return
   550  	}
   551  	c.isIndirect = true
   552  	if len(c.fields) == 0 {
   553  		return
   554  	}
   555  	structCode := c.fields[0].getStruct()
   556  	if structCode == nil {
   557  		return
   558  	}
   559  	structCode.enableIndirect()
   560  }
   561  
   562  func (c *StructCode) Filter(query *FieldQuery) Code {
   563  	fieldMap := map[string]*FieldQuery{}
   564  	for _, field := range query.Fields {
   565  		fieldMap[field.Name] = field
   566  	}
   567  	fields := make([]*StructFieldCode, 0, len(c.fields))
   568  	for _, field := range c.fields {
   569  		query, exists := fieldMap[field.key]
   570  		if !exists {
   571  			continue
   572  		}
   573  		fieldCode := &StructFieldCode{
   574  			typ:                field.typ,
   575  			key:                field.key,
   576  			tag:                field.tag,
   577  			value:              field.value,
   578  			offset:             field.offset,
   579  			isAnonymous:        field.isAnonymous,
   580  			isTaggedKey:        field.isTaggedKey,
   581  			isNilableType:      field.isNilableType,
   582  			isNilCheck:         field.isNilCheck,
   583  			isAddrForMarshaler: field.isAddrForMarshaler,
   584  			isNextOpPtrType:    field.isNextOpPtrType,
   585  		}
   586  		if len(query.Fields) > 0 {
   587  			fieldCode.value = fieldCode.value.Filter(query)
   588  		}
   589  		fields = append(fields, fieldCode)
   590  	}
   591  	return &StructCode{
   592  		typ:                       c.typ,
   593  		fields:                    fields,
   594  		isPtr:                     c.isPtr,
   595  		disableIndirectConversion: c.disableIndirectConversion,
   596  		isIndirect:                c.isIndirect,
   597  		isRecursive:               c.isRecursive,
   598  	}
   599  }
   600  
   601  type StructFieldCode struct {
   602  	typ                *runtime.Type
   603  	key                string
   604  	tag                *runtime.StructTag
   605  	value              Code
   606  	offset             uintptr
   607  	isAnonymous        bool
   608  	isTaggedKey        bool
   609  	isNilableType      bool
   610  	isNilCheck         bool
   611  	isAddrForMarshaler bool
   612  	isNextOpPtrType    bool
   613  	isMarshalerContext bool
   614  }
   615  
   616  func (c *StructFieldCode) getStruct() *StructCode {
   617  	value := c.value
   618  	ptr, ok := value.(*PtrCode)
   619  	if ok {
   620  		value = ptr.value
   621  	}
   622  	structCode, ok := value.(*StructCode)
   623  	if ok {
   624  		return structCode
   625  	}
   626  	return nil
   627  }
   628  
   629  func (c *StructFieldCode) getAnonymousStruct() *StructCode {
   630  	if !c.isAnonymous {
   631  		return nil
   632  	}
   633  	return c.getStruct()
   634  }
   635  
   636  func optimizeStructHeader(code *Opcode, tag *runtime.StructTag) OpType {
   637  	headType := code.ToHeaderType(tag.IsString)
   638  	if tag.IsOmitEmpty {
   639  		headType = headType.HeadToOmitEmptyHead()
   640  	}
   641  	return headType
   642  }
   643  
   644  func optimizeStructField(code *Opcode, tag *runtime.StructTag) OpType {
   645  	fieldType := code.ToFieldType(tag.IsString)
   646  	if tag.IsOmitEmpty {
   647  		fieldType = fieldType.FieldToOmitEmptyField()
   648  	}
   649  	return fieldType
   650  }
   651  
   652  func (c *StructFieldCode) headerOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes {
   653  	value := valueCodes.First()
   654  	op := optimizeStructHeader(value, c.tag)
   655  	field.Op = op
   656  	if value.Flags&MarshalerContextFlags != 0 {
   657  		field.Flags |= MarshalerContextFlags
   658  	}
   659  	field.NumBitSize = value.NumBitSize
   660  	field.PtrNum = value.PtrNum
   661  	field.FieldQuery = value.FieldQuery
   662  	fieldCodes := Opcodes{field}
   663  	if op.IsMultipleOpHead() {
   664  		field.Next = value
   665  		fieldCodes = fieldCodes.Add(valueCodes...)
   666  	} else {
   667  		ctx.decIndex()
   668  	}
   669  	return fieldCodes
   670  }
   671  
   672  func (c *StructFieldCode) fieldOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes {
   673  	value := valueCodes.First()
   674  	op := optimizeStructField(value, c.tag)
   675  	field.Op = op
   676  	if value.Flags&MarshalerContextFlags != 0 {
   677  		field.Flags |= MarshalerContextFlags
   678  	}
   679  	field.NumBitSize = value.NumBitSize
   680  	field.PtrNum = value.PtrNum
   681  	field.FieldQuery = value.FieldQuery
   682  
   683  	fieldCodes := Opcodes{field}
   684  	if op.IsMultipleOpField() {
   685  		field.Next = value
   686  		fieldCodes = fieldCodes.Add(valueCodes...)
   687  	} else {
   688  		ctx.decIndex()
   689  	}
   690  	return fieldCodes
   691  }
   692  
   693  func (c *StructFieldCode) addStructEndCode(ctx *compileContext, codes Opcodes) Opcodes {
   694  	end := &Opcode{
   695  		Op:         OpStructEnd,
   696  		Idx:        opcodeOffset(ctx.ptrIndex),
   697  		DisplayIdx: ctx.opcodeIndex,
   698  		Indent:     ctx.indent,
   699  	}
   700  	codes.Last().Next = end
   701  	code := codes.First()
   702  	for code.Op == OpStructField || code.Op == OpStructHead {
   703  		code = code.Next
   704  	}
   705  	for code.NextField != nil {
   706  		code = code.NextField
   707  	}
   708  	code.NextField = end
   709  
   710  	codes = codes.Add(end)
   711  	ctx.incOpcodeIndex()
   712  	return codes
   713  }
   714  
   715  func (c *StructFieldCode) structKey(ctx *compileContext) string {
   716  	if ctx.escapeKey {
   717  		rctx := &RuntimeContext{Option: &Option{Flag: HTMLEscapeOption}}
   718  		return fmt.Sprintf(`%s:`, unsafeConvert.StringReflect(AppendString(rctx, []byte{}, c.key)))
   719  	}
   720  	return fmt.Sprintf(`"%s":`, c.key)
   721  }
   722  
   723  func (c *StructFieldCode) flags() OpFlags {
   724  	var flags OpFlags
   725  	if c.isTaggedKey {
   726  		flags |= IsTaggedKeyFlags
   727  	}
   728  	if c.isNilableType {
   729  		flags |= IsNilableTypeFlags
   730  	}
   731  	if c.isNilCheck {
   732  		flags |= NilCheckFlags
   733  	}
   734  	if c.isAddrForMarshaler {
   735  		flags |= AddrForMarshalerFlags
   736  	}
   737  	if c.isNextOpPtrType {
   738  		flags |= IsNextOpPtrTypeFlags
   739  	}
   740  	if c.isAnonymous {
   741  		flags |= AnonymousKeyFlags
   742  	}
   743  	if c.isMarshalerContext {
   744  		flags |= MarshalerContextFlags
   745  	}
   746  	return flags
   747  }
   748  
   749  func (c *StructFieldCode) toValueOpcodes(ctx *compileContext) Opcodes {
   750  	if c.isAnonymous {
   751  		anonymCode, ok := c.value.(AnonymousCode)
   752  		if ok {
   753  			return anonymCode.ToAnonymousOpcode(ctx)
   754  		}
   755  	}
   756  	return c.value.ToOpcode(ctx)
   757  }
   758  
   759  func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes {
   760  	field := &Opcode{
   761  		Idx:        opcodeOffset(ctx.ptrIndex),
   762  		Flags:      c.flags(),
   763  		Key:        c.structKey(ctx),
   764  		Offset:     uint32(c.offset),
   765  		Type:       c.typ,
   766  		DisplayIdx: ctx.opcodeIndex,
   767  		Indent:     ctx.indent,
   768  		DisplayKey: c.key,
   769  	}
   770  	ctx.incIndex()
   771  	valueCodes := c.toValueOpcodes(ctx)
   772  	if isFirstField {
   773  		codes := c.headerOpcodes(ctx, field, valueCodes)
   774  		if isEndField {
   775  			codes = c.addStructEndCode(ctx, codes)
   776  		}
   777  		return codes
   778  	}
   779  	codes := c.fieldOpcodes(ctx, field, valueCodes)
   780  	if isEndField {
   781  		if isEnableStructEndOptimization(c.value) {
   782  			field.Op = field.Op.FieldToEnd()
   783  		} else {
   784  			codes = c.addStructEndCode(ctx, codes)
   785  		}
   786  	}
   787  	return codes
   788  }
   789  
   790  func (c *StructFieldCode) ToAnonymousOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes {
   791  	field := &Opcode{
   792  		Idx:        opcodeOffset(ctx.ptrIndex),
   793  		Flags:      c.flags() | AnonymousHeadFlags,
   794  		Key:        c.structKey(ctx),
   795  		Offset:     uint32(c.offset),
   796  		Type:       c.typ,
   797  		DisplayIdx: ctx.opcodeIndex,
   798  		Indent:     ctx.indent,
   799  		DisplayKey: c.key,
   800  	}
   801  	ctx.incIndex()
   802  	valueCodes := c.toValueOpcodes(ctx)
   803  	if isFirstField {
   804  		return c.headerOpcodes(ctx, field, valueCodes)
   805  	}
   806  	return c.fieldOpcodes(ctx, field, valueCodes)
   807  }
   808  
   809  func isEnableStructEndOptimization(value Code) bool {
   810  	switch value.Kind() {
   811  	case CodeKindInt,
   812  		CodeKindUint,
   813  		CodeKindFloat,
   814  		CodeKindString,
   815  		CodeKindBool,
   816  		CodeKindBytes:
   817  		return true
   818  	case CodeKindPtr:
   819  		return isEnableStructEndOptimization(value.(*PtrCode).value)
   820  	default:
   821  		return false
   822  	}
   823  }
   824  
   825  type InterfaceCode struct {
   826  	typ        *runtime.Type
   827  	fieldQuery *FieldQuery
   828  	isPtr      bool
   829  }
   830  
   831  func (c *InterfaceCode) Kind() CodeKind {
   832  	return CodeKindInterface
   833  }
   834  
   835  func (c *InterfaceCode) ToOpcode(ctx *compileContext) Opcodes {
   836  	var code *Opcode
   837  	switch {
   838  	case c.isPtr:
   839  		code = newOpCode(ctx, c.typ, OpInterfacePtr)
   840  	default:
   841  		code = newOpCode(ctx, c.typ, OpInterface)
   842  	}
   843  	code.FieldQuery = c.fieldQuery
   844  	if c.typ.NumMethod() > 0 {
   845  		code.Flags |= NonEmptyInterfaceFlags
   846  	}
   847  	ctx.incIndex()
   848  	return Opcodes{code}
   849  }
   850  
   851  func (c *InterfaceCode) Filter(query *FieldQuery) Code {
   852  	return &InterfaceCode{
   853  		typ:        c.typ,
   854  		fieldQuery: query,
   855  		isPtr:      c.isPtr,
   856  	}
   857  }
   858  
   859  type MarshalJSONCode struct {
   860  	typ                *runtime.Type
   861  	fieldQuery         *FieldQuery
   862  	isAddrForMarshaler bool
   863  	isNilableType      bool
   864  	isMarshalerContext bool
   865  }
   866  
   867  func (c *MarshalJSONCode) Kind() CodeKind {
   868  	return CodeKindMarshalJSON
   869  }
   870  
   871  func (c *MarshalJSONCode) ToOpcode(ctx *compileContext) Opcodes {
   872  	code := newOpCode(ctx, c.typ, OpMarshalJSON)
   873  	code.FieldQuery = c.fieldQuery
   874  	if c.isAddrForMarshaler {
   875  		code.Flags |= AddrForMarshalerFlags
   876  	}
   877  	if c.isMarshalerContext {
   878  		code.Flags |= MarshalerContextFlags
   879  	}
   880  	if c.isNilableType {
   881  		code.Flags |= IsNilableTypeFlags
   882  	} else {
   883  		code.Flags &= ^IsNilableTypeFlags
   884  	}
   885  	ctx.incIndex()
   886  	return Opcodes{code}
   887  }
   888  
   889  func (c *MarshalJSONCode) Filter(query *FieldQuery) Code {
   890  	return &MarshalJSONCode{
   891  		typ:                c.typ,
   892  		fieldQuery:         query,
   893  		isAddrForMarshaler: c.isAddrForMarshaler,
   894  		isNilableType:      c.isNilableType,
   895  		isMarshalerContext: c.isMarshalerContext,
   896  	}
   897  }
   898  
   899  type MarshalTextCode struct {
   900  	typ                *runtime.Type
   901  	fieldQuery         *FieldQuery
   902  	isAddrForMarshaler bool
   903  	isNilableType      bool
   904  }
   905  
   906  func (c *MarshalTextCode) Kind() CodeKind {
   907  	return CodeKindMarshalText
   908  }
   909  
   910  func (c *MarshalTextCode) ToOpcode(ctx *compileContext) Opcodes {
   911  	code := newOpCode(ctx, c.typ, OpMarshalText)
   912  	code.FieldQuery = c.fieldQuery
   913  	if c.isAddrForMarshaler {
   914  		code.Flags |= AddrForMarshalerFlags
   915  	}
   916  	if c.isNilableType {
   917  		code.Flags |= IsNilableTypeFlags
   918  	} else {
   919  		code.Flags &= ^IsNilableTypeFlags
   920  	}
   921  	ctx.incIndex()
   922  	return Opcodes{code}
   923  }
   924  
   925  func (c *MarshalTextCode) Filter(query *FieldQuery) Code {
   926  	return &MarshalTextCode{
   927  		typ:                c.typ,
   928  		fieldQuery:         query,
   929  		isAddrForMarshaler: c.isAddrForMarshaler,
   930  		isNilableType:      c.isNilableType,
   931  	}
   932  }
   933  
   934  type PtrCode struct {
   935  	typ    *runtime.Type
   936  	value  Code
   937  	ptrNum uint8
   938  }
   939  
   940  func (c *PtrCode) Kind() CodeKind {
   941  	return CodeKindPtr
   942  }
   943  
   944  func (c *PtrCode) ToOpcode(ctx *compileContext) Opcodes {
   945  	codes := c.value.ToOpcode(ctx)
   946  	codes.First().Op = convertPtrOp(codes.First())
   947  	codes.First().PtrNum = c.ptrNum
   948  	return codes
   949  }
   950  
   951  func (c *PtrCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
   952  	var codes Opcodes
   953  	anonymCode, ok := c.value.(AnonymousCode)
   954  	if ok {
   955  		codes = anonymCode.ToAnonymousOpcode(ctx)
   956  	} else {
   957  		codes = c.value.ToOpcode(ctx)
   958  	}
   959  	codes.First().Op = convertPtrOp(codes.First())
   960  	codes.First().PtrNum = c.ptrNum
   961  	return codes
   962  }
   963  
   964  func (c *PtrCode) Filter(query *FieldQuery) Code {
   965  	return &PtrCode{
   966  		typ:    c.typ,
   967  		value:  c.value.Filter(query),
   968  		ptrNum: c.ptrNum,
   969  	}
   970  }
   971  
   972  func convertPtrOp(code *Opcode) OpType {
   973  	ptrHeadOp := code.Op.HeadToPtrHead()
   974  	if code.Op != ptrHeadOp {
   975  		if code.PtrNum > 0 {
   976  			// ptr field and ptr head
   977  			code.PtrNum--
   978  		}
   979  		return ptrHeadOp
   980  	}
   981  	switch code.Op {
   982  	case OpInt:
   983  		return OpIntPtr
   984  	case OpUint:
   985  		return OpUintPtr
   986  	case OpFloat32:
   987  		return OpFloat32Ptr
   988  	case OpFloat64:
   989  		return OpFloat64Ptr
   990  	case OpString:
   991  		return OpStringPtr
   992  	case OpBool:
   993  		return OpBoolPtr
   994  	case OpBytes:
   995  		return OpBytesPtr
   996  	case OpNumber:
   997  		return OpNumberPtr
   998  	case OpArray:
   999  		return OpArrayPtr
  1000  	case OpSlice:
  1001  		return OpSlicePtr
  1002  	case OpMap:
  1003  		return OpMapPtr
  1004  	case OpMarshalJSON:
  1005  		return OpMarshalJSONPtr
  1006  	case OpMarshalText:
  1007  		return OpMarshalTextPtr
  1008  	case OpInterface:
  1009  		return OpInterfacePtr
  1010  	case OpRecursive:
  1011  		return OpRecursivePtr
  1012  	}
  1013  	return code.Op
  1014  }
  1015  
  1016  func isEmbeddedStruct(field *StructFieldCode) bool {
  1017  	if !field.isAnonymous {
  1018  		return false
  1019  	}
  1020  	t := field.typ
  1021  	if t.Kind() == reflect.Ptr {
  1022  		t = t.Elem()
  1023  	}
  1024  	return t.Kind() == reflect.Struct
  1025  }