forked from mirror/go-json
rename compiler API
This commit is contained in:
parent
217d943188
commit
fee54d4873
|
@ -2,10 +2,8 @@ package encoder
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/errors"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
|
@ -470,35 +468,6 @@ func (c *StructCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
|
|||
return codes
|
||||
}
|
||||
|
||||
func linkRecursiveCode2(ctx *compileContext) {
|
||||
for _, recursive := range *ctx.recursiveCodes {
|
||||
typeptr := uintptr(unsafe.Pointer(recursive.Type))
|
||||
codes := ctx.structTypeToCodes[typeptr]
|
||||
compiled := recursive.Jmp
|
||||
compiled.Code = copyOpcode(codes.First())
|
||||
code := compiled.Code
|
||||
code.End.Next = newEndOp(&compileContext{})
|
||||
code.Op = code.Op.PtrHeadToHead()
|
||||
|
||||
beforeLastCode := code.End
|
||||
lastCode := beforeLastCode.Next
|
||||
|
||||
totalLength := code.TotalLength()
|
||||
lastCode.Idx = uint32((totalLength + 1) * uintptrSize)
|
||||
lastCode.ElemIdx = lastCode.Idx + uintptrSize
|
||||
lastCode.Length = lastCode.Idx + 2*uintptrSize
|
||||
code.End.Next.Op = OpRecursiveEnd
|
||||
|
||||
|
||||
// extend length to alloc slot for elemIdx + length
|
||||
curTotalLength := uintptr(recursive.TotalLength()) + 3
|
||||
nextTotalLength := uintptr(totalLength) + 3
|
||||
compiled.CurLen = curTotalLength
|
||||
compiled.NextLen = nextTotalLength
|
||||
compiled.Linked = true
|
||||
}
|
||||
}
|
||||
|
||||
func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) {
|
||||
fields := make([]*StructFieldCode, 0, len(c.fields))
|
||||
for _, field := range c.fields {
|
||||
|
@ -855,577 +824,6 @@ func (c *PtrCode) ToAnonymousOpcode(ctx *compileContext) Opcodes {
|
|||
return codes
|
||||
}
|
||||
|
||||
func type2code(ctx *compileContext) (Code, error) {
|
||||
typ := ctx.typ
|
||||
switch {
|
||||
case implementsMarshalJSON(typ):
|
||||
return compileMarshalJSON2(ctx)
|
||||
case implementsMarshalText(typ):
|
||||
return compileMarshalText2(ctx)
|
||||
}
|
||||
|
||||
isPtr := false
|
||||
orgType := typ
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
isPtr = true
|
||||
}
|
||||
switch {
|
||||
case implementsMarshalJSON(typ):
|
||||
return compileMarshalJSON2(ctx)
|
||||
case implementsMarshalText(typ):
|
||||
return compileMarshalText2(ctx)
|
||||
}
|
||||
switch typ.Kind() {
|
||||
case reflect.Slice:
|
||||
ctx := ctx.withType(typ)
|
||||
elem := typ.Elem()
|
||||
if elem.Kind() == reflect.Uint8 {
|
||||
p := runtime.PtrTo(elem)
|
||||
if !implementsMarshalJSONType(p) && !p.Implements(marshalTextType) {
|
||||
return compileBytes2(ctx, isPtr)
|
||||
}
|
||||
}
|
||||
return compileSlice2(ctx)
|
||||
case reflect.Map:
|
||||
if isPtr {
|
||||
return compilePtr2(ctx.withType(runtime.PtrTo(typ)))
|
||||
}
|
||||
return compileMap2(ctx.withType(typ))
|
||||
case reflect.Struct:
|
||||
return compileStruct2(ctx.withType(typ), isPtr)
|
||||
case reflect.Int:
|
||||
return compileInt2(ctx.withType(typ), isPtr)
|
||||
case reflect.Int8:
|
||||
return compileInt82(ctx.withType(typ), isPtr)
|
||||
case reflect.Int16:
|
||||
return compileInt162(ctx.withType(typ), isPtr)
|
||||
case reflect.Int32:
|
||||
return compileInt322(ctx.withType(typ), isPtr)
|
||||
case reflect.Int64:
|
||||
return compileInt642(ctx.withType(typ), isPtr)
|
||||
case reflect.Uint, reflect.Uintptr:
|
||||
return compileUint2(ctx.withType(typ), isPtr)
|
||||
case reflect.Uint8:
|
||||
return compileUint82(ctx.withType(typ), isPtr)
|
||||
case reflect.Uint16:
|
||||
return compileUint162(ctx.withType(typ), isPtr)
|
||||
case reflect.Uint32:
|
||||
return compileUint322(ctx.withType(typ), isPtr)
|
||||
case reflect.Uint64:
|
||||
return compileUint642(ctx.withType(typ), isPtr)
|
||||
case reflect.Float32:
|
||||
return compileFloat322(ctx.withType(typ), isPtr)
|
||||
case reflect.Float64:
|
||||
return compileFloat642(ctx.withType(typ), isPtr)
|
||||
case reflect.String:
|
||||
return compileString2(ctx.withType(typ), isPtr)
|
||||
case reflect.Bool:
|
||||
return compileBool2(ctx.withType(typ), isPtr)
|
||||
case reflect.Interface:
|
||||
return compileInterface2(ctx.withType(typ), isPtr)
|
||||
default:
|
||||
if isPtr && typ.Implements(marshalTextType) {
|
||||
typ = orgType
|
||||
}
|
||||
return type2codeWithPtr(ctx.withType(typ), isPtr)
|
||||
}
|
||||
}
|
||||
|
||||
func type2codeWithPtr(ctx *compileContext, isPtr bool) (Code, error) {
|
||||
typ := ctx.typ
|
||||
switch {
|
||||
case implementsMarshalJSON(typ):
|
||||
return compileMarshalJSON2(ctx)
|
||||
case implementsMarshalText(typ):
|
||||
return compileMarshalText2(ctx)
|
||||
}
|
||||
switch typ.Kind() {
|
||||
case reflect.Ptr:
|
||||
return compilePtr2(ctx)
|
||||
case reflect.Slice:
|
||||
elem := typ.Elem()
|
||||
if elem.Kind() == reflect.Uint8 {
|
||||
p := runtime.PtrTo(elem)
|
||||
if !implementsMarshalJSONType(p) && !p.Implements(marshalTextType) {
|
||||
return compileBytes2(ctx, false)
|
||||
}
|
||||
}
|
||||
return compileSlice2(ctx)
|
||||
case reflect.Array:
|
||||
return compileArray2(ctx)
|
||||
case reflect.Map:
|
||||
return compileMap2(ctx)
|
||||
case reflect.Struct:
|
||||
return compileStruct2(ctx, isPtr)
|
||||
case reflect.Interface:
|
||||
return compileInterface2(ctx, false)
|
||||
case reflect.Int:
|
||||
return compileInt2(ctx, false)
|
||||
case reflect.Int8:
|
||||
return compileInt82(ctx, false)
|
||||
case reflect.Int16:
|
||||
return compileInt162(ctx, false)
|
||||
case reflect.Int32:
|
||||
return compileInt322(ctx, false)
|
||||
case reflect.Int64:
|
||||
return compileInt642(ctx, false)
|
||||
case reflect.Uint:
|
||||
return compileUint2(ctx, false)
|
||||
case reflect.Uint8:
|
||||
return compileUint82(ctx, false)
|
||||
case reflect.Uint16:
|
||||
return compileUint162(ctx, false)
|
||||
case reflect.Uint32:
|
||||
return compileUint322(ctx, false)
|
||||
case reflect.Uint64:
|
||||
return compileUint642(ctx, false)
|
||||
case reflect.Uintptr:
|
||||
return compileUint2(ctx, false)
|
||||
case reflect.Float32:
|
||||
return compileFloat322(ctx, false)
|
||||
case reflect.Float64:
|
||||
return compileFloat642(ctx, false)
|
||||
case reflect.String:
|
||||
return compileString2(ctx, false)
|
||||
case reflect.Bool:
|
||||
return compileBool2(ctx, false)
|
||||
}
|
||||
return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)}
|
||||
}
|
||||
|
||||
func compileInt2(ctx *compileContext, isPtr bool) (*IntCode, error) {
|
||||
return &IntCode{typ: ctx.typ, bitSize: intSize, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileInt82(ctx *compileContext, isPtr bool) (*IntCode, error) {
|
||||
return &IntCode{typ: ctx.typ, bitSize: 8, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileInt162(ctx *compileContext, isPtr bool) (*IntCode, error) {
|
||||
return &IntCode{typ: ctx.typ, bitSize: 16, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileInt322(ctx *compileContext, isPtr bool) (*IntCode, error) {
|
||||
return &IntCode{typ: ctx.typ, bitSize: 32, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileInt642(ctx *compileContext, isPtr bool) (*IntCode, error) {
|
||||
return &IntCode{typ: ctx.typ, bitSize: 64, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileUint2(ctx *compileContext, isPtr bool) (*UintCode, error) {
|
||||
return &UintCode{typ: ctx.typ, bitSize: intSize, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileUint82(ctx *compileContext, isPtr bool) (*UintCode, error) {
|
||||
return &UintCode{typ: ctx.typ, bitSize: 8, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileUint162(ctx *compileContext, isPtr bool) (*UintCode, error) {
|
||||
return &UintCode{typ: ctx.typ, bitSize: 16, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileUint322(ctx *compileContext, isPtr bool) (*UintCode, error) {
|
||||
return &UintCode{typ: ctx.typ, bitSize: 32, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileUint642(ctx *compileContext, isPtr bool) (*UintCode, error) {
|
||||
return &UintCode{typ: ctx.typ, bitSize: 64, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileFloat322(ctx *compileContext, isPtr bool) (*FloatCode, error) {
|
||||
return &FloatCode{typ: ctx.typ, bitSize: 32, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileFloat642(ctx *compileContext, isPtr bool) (*FloatCode, error) {
|
||||
return &FloatCode{typ: ctx.typ, bitSize: 64, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileString2(ctx *compileContext, isPtr bool) (*StringCode, error) {
|
||||
return &StringCode{typ: ctx.typ, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileBool2(ctx *compileContext, isPtr bool) (*BoolCode, error) {
|
||||
return &BoolCode{typ: ctx.typ, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileIntString2(ctx *compileContext) (*IntCode, error) {
|
||||
return &IntCode{typ: ctx.typ, bitSize: intSize, isString: true}, nil
|
||||
}
|
||||
|
||||
func compileInt8String2(ctx *compileContext) (*IntCode, error) {
|
||||
return &IntCode{typ: ctx.typ, bitSize: 8, isString: true}, nil
|
||||
}
|
||||
|
||||
func compileInt16String2(ctx *compileContext) (*IntCode, error) {
|
||||
return &IntCode{typ: ctx.typ, bitSize: 16, isString: true}, nil
|
||||
}
|
||||
|
||||
func compileInt32String2(ctx *compileContext) (*IntCode, error) {
|
||||
return &IntCode{typ: ctx.typ, bitSize: 32, isString: true}, nil
|
||||
}
|
||||
|
||||
func compileInt64String2(ctx *compileContext) (*IntCode, error) {
|
||||
return &IntCode{typ: ctx.typ, bitSize: 64, isString: true}, nil
|
||||
}
|
||||
|
||||
func compileUintString2(ctx *compileContext) (*UintCode, error) {
|
||||
return &UintCode{typ: ctx.typ, bitSize: intSize, isString: true}, nil
|
||||
}
|
||||
|
||||
func compileUint8String2(ctx *compileContext) (*UintCode, error) {
|
||||
return &UintCode{typ: ctx.typ, bitSize: 8, isString: true}, nil
|
||||
}
|
||||
|
||||
func compileUint16String2(ctx *compileContext) (*UintCode, error) {
|
||||
return &UintCode{typ: ctx.typ, bitSize: 16, isString: true}, nil
|
||||
}
|
||||
|
||||
func compileUint32String2(ctx *compileContext) (*UintCode, error) {
|
||||
return &UintCode{typ: ctx.typ, bitSize: 32, isString: true}, nil
|
||||
}
|
||||
|
||||
func compileUint64String2(ctx *compileContext) (*UintCode, error) {
|
||||
return &UintCode{typ: ctx.typ, bitSize: 64, isString: true}, nil
|
||||
}
|
||||
|
||||
func compileSlice2(ctx *compileContext) (*SliceCode, error) {
|
||||
elem := ctx.typ.Elem()
|
||||
code, err := compileListElem2(ctx.withType(elem))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if code.Type() == CodeTypeStruct {
|
||||
structCode := code.(*StructCode)
|
||||
structCode.enableIndirect()
|
||||
}
|
||||
return &SliceCode{typ: ctx.typ, value: code}, nil
|
||||
}
|
||||
|
||||
func compileArray2(ctx *compileContext) (*ArrayCode, error) {
|
||||
typ := ctx.typ
|
||||
elem := typ.Elem()
|
||||
code, err := compileListElem2(ctx.withType(elem))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if code.Type() == CodeTypeStruct {
|
||||
structCode := code.(*StructCode)
|
||||
structCode.enableIndirect()
|
||||
}
|
||||
return &ArrayCode{typ: ctx.typ, value: code}, nil
|
||||
}
|
||||
|
||||
func compileMap2(ctx *compileContext) (*MapCode, error) {
|
||||
typ := ctx.typ
|
||||
keyCode, err := compileMapKey(ctx.withType(typ.Key()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valueCode, err := compileMapValue2(ctx.withType(typ.Elem()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if valueCode.Type() == CodeTypeStruct {
|
||||
structCode := valueCode.(*StructCode)
|
||||
structCode.enableIndirect()
|
||||
}
|
||||
return &MapCode{typ: ctx.typ, key: keyCode, value: valueCode}, nil
|
||||
}
|
||||
|
||||
func compileBytes2(ctx *compileContext, isPtr bool) (*BytesCode, error) {
|
||||
return &BytesCode{typ: ctx.typ, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileInterface2(ctx *compileContext, isPtr bool) (*InterfaceCode, error) {
|
||||
return &InterfaceCode{typ: ctx.typ, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
func compileMarshalJSON2(ctx *compileContext) (*MarshalJSONCode, error) {
|
||||
return &MarshalJSONCode{typ: ctx.typ}, nil
|
||||
}
|
||||
|
||||
func compileMarshalText2(ctx *compileContext) (*MarshalTextCode, error) {
|
||||
return &MarshalTextCode{typ: ctx.typ}, nil
|
||||
}
|
||||
|
||||
func compilePtr2(ctx *compileContext) (*PtrCode, error) {
|
||||
code, err := type2codeWithPtr(ctx.withType(ctx.typ.Elem()), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, ok := code.(*PtrCode)
|
||||
if ok {
|
||||
return &PtrCode{typ: ctx.typ, value: ptr.value, ptrNum: ptr.ptrNum + 1}, nil
|
||||
}
|
||||
return &PtrCode{typ: ctx.typ, value: code, ptrNum: 1}, nil
|
||||
}
|
||||
|
||||
func compileListElem2(ctx *compileContext) (Code, error) {
|
||||
typ := ctx.typ
|
||||
switch {
|
||||
case isPtrMarshalJSONType(typ):
|
||||
return compileMarshalJSON2(ctx)
|
||||
case !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType):
|
||||
return compileMarshalText2(ctx)
|
||||
case typ.Kind() == reflect.Map:
|
||||
return compilePtr2(ctx.withType(runtime.PtrTo(typ)))
|
||||
default:
|
||||
code, err := type2codeWithPtr(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, ok := code.(*PtrCode)
|
||||
if ok {
|
||||
if ptr.value.Type() == CodeTypeMap {
|
||||
ptr.ptrNum++
|
||||
}
|
||||
}
|
||||
return code, nil
|
||||
}
|
||||
}
|
||||
|
||||
func compileMapKey(ctx *compileContext) (Code, error) {
|
||||
typ := ctx.typ
|
||||
switch {
|
||||
case implementsMarshalJSON(typ):
|
||||
return compileMarshalJSON2(ctx)
|
||||
case implementsMarshalText(typ):
|
||||
return compileMarshalText2(ctx)
|
||||
}
|
||||
switch typ.Kind() {
|
||||
case reflect.Ptr:
|
||||
return compilePtr2(ctx)
|
||||
case reflect.String:
|
||||
return compileString2(ctx, false)
|
||||
case reflect.Int:
|
||||
return compileIntString2(ctx)
|
||||
case reflect.Int8:
|
||||
return compileInt8String2(ctx)
|
||||
case reflect.Int16:
|
||||
return compileInt16String2(ctx)
|
||||
case reflect.Int32:
|
||||
return compileInt32String2(ctx)
|
||||
case reflect.Int64:
|
||||
return compileInt64String2(ctx)
|
||||
case reflect.Uint:
|
||||
return compileUintString2(ctx)
|
||||
case reflect.Uint8:
|
||||
return compileUint8String2(ctx)
|
||||
case reflect.Uint16:
|
||||
return compileUint16String2(ctx)
|
||||
case reflect.Uint32:
|
||||
return compileUint32String2(ctx)
|
||||
case reflect.Uint64:
|
||||
return compileUint64String2(ctx)
|
||||
case reflect.Uintptr:
|
||||
return compileUintString2(ctx)
|
||||
}
|
||||
return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)}
|
||||
}
|
||||
|
||||
func compileMapValue2(ctx *compileContext) (Code, error) {
|
||||
switch ctx.typ.Kind() {
|
||||
case reflect.Map:
|
||||
return compilePtr2(ctx.withType(runtime.PtrTo(ctx.typ)))
|
||||
default:
|
||||
code, err := type2codeWithPtr(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, ok := code.(*PtrCode)
|
||||
if ok {
|
||||
if ptr.value.Type() == CodeTypeMap {
|
||||
ptr.ptrNum++
|
||||
}
|
||||
}
|
||||
return code, nil
|
||||
}
|
||||
}
|
||||
|
||||
func compileStruct2(ctx *compileContext, isPtr bool) (*StructCode, error) {
|
||||
typ := ctx.typ
|
||||
typeptr := uintptr(unsafe.Pointer(typ))
|
||||
if code, exists := ctx.structTypeToCode[typeptr]; exists {
|
||||
derefCode := *code
|
||||
derefCode.isRecursive = true
|
||||
return &derefCode, nil
|
||||
}
|
||||
indirect := runtime.IfaceIndir(typ)
|
||||
code := &StructCode{typ: typ, isPtr: isPtr, isIndirect: indirect}
|
||||
ctx.structTypeToCode[typeptr] = code
|
||||
|
||||
fieldNum := typ.NumField()
|
||||
tags := typeToStructTags(typ)
|
||||
fields := []*StructFieldCode{}
|
||||
for i, tag := range tags {
|
||||
isOnlyOneFirstField := i == 0 && fieldNum == 1
|
||||
field, err := code.compileStructField(ctx, tag, isPtr, isOnlyOneFirstField)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if field.isAnonymous {
|
||||
structCode := field.getAnonymousStruct()
|
||||
if structCode != nil {
|
||||
structCode.removeFieldsByTags(tags)
|
||||
if isAssignableIndirect(field, isPtr) {
|
||||
if indirect {
|
||||
structCode.isIndirect = true
|
||||
} else {
|
||||
structCode.isIndirect = false
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
structCode := field.getStruct()
|
||||
if structCode != nil {
|
||||
if indirect {
|
||||
// if parent is indirect type, set child indirect property to true
|
||||
structCode.isIndirect = true
|
||||
} else {
|
||||
// if parent is not indirect type, set child indirect property to false.
|
||||
// but if parent's indirect is false and isPtr is true, then indirect must be true.
|
||||
// Do this only if indirectConversion is enabled at the end of compileStruct.
|
||||
structCode.isIndirect = false
|
||||
}
|
||||
}
|
||||
}
|
||||
fields = append(fields, field)
|
||||
}
|
||||
fieldMap := getFieldMap(fields)
|
||||
duplicatedFieldMap := getDuplicatedFieldMap(fieldMap)
|
||||
code.fields = filteredDuplicatedFields(fields, duplicatedFieldMap)
|
||||
if !code.disableIndirectConversion && !indirect && isPtr {
|
||||
code.enableIndirect()
|
||||
}
|
||||
delete(ctx.structTypeToCode, typeptr)
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func getFieldMap(fields []*StructFieldCode) map[string][]*StructFieldCode {
|
||||
fieldMap := map[string][]*StructFieldCode{}
|
||||
for _, field := range fields {
|
||||
if field.isAnonymous {
|
||||
for k, v := range getAnonymousFieldMap(field) {
|
||||
fieldMap[k] = append(fieldMap[k], v...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
fieldMap[field.key] = append(fieldMap[field.key], field)
|
||||
}
|
||||
return fieldMap
|
||||
}
|
||||
|
||||
func getAnonymousFieldMap(field *StructFieldCode) map[string][]*StructFieldCode {
|
||||
fieldMap := map[string][]*StructFieldCode{}
|
||||
structCode := field.getAnonymousStruct()
|
||||
if structCode == nil || structCode.isRecursive {
|
||||
fieldMap[field.key] = append(fieldMap[field.key], field)
|
||||
return fieldMap
|
||||
}
|
||||
for k, v := range getFieldMapFromAnonymousParent(structCode.fields) {
|
||||
fieldMap[k] = append(fieldMap[k], v...)
|
||||
}
|
||||
return fieldMap
|
||||
}
|
||||
|
||||
func getFieldMapFromAnonymousParent(fields []*StructFieldCode) map[string][]*StructFieldCode {
|
||||
fieldMap := map[string][]*StructFieldCode{}
|
||||
for _, field := range fields {
|
||||
if field.isAnonymous {
|
||||
for k, v := range getAnonymousFieldMap(field) {
|
||||
// Do not handle tagged key when embedding more than once
|
||||
for _, vv := range v {
|
||||
vv.isTaggedKey = false
|
||||
}
|
||||
fieldMap[k] = append(fieldMap[k], v...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
fieldMap[field.key] = append(fieldMap[field.key], field)
|
||||
}
|
||||
return fieldMap
|
||||
}
|
||||
|
||||
func getDuplicatedFieldMap(fieldMap map[string][]*StructFieldCode) map[*StructFieldCode]struct{} {
|
||||
duplicatedFieldMap := map[*StructFieldCode]struct{}{}
|
||||
for _, fields := range fieldMap {
|
||||
if len(fields) == 1 {
|
||||
continue
|
||||
}
|
||||
if isTaggedKeyOnly(fields) {
|
||||
for _, field := range fields {
|
||||
if field.isTaggedKey {
|
||||
continue
|
||||
}
|
||||
duplicatedFieldMap[field] = struct{}{}
|
||||
}
|
||||
} else {
|
||||
for _, field := range fields {
|
||||
duplicatedFieldMap[field] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
return duplicatedFieldMap
|
||||
}
|
||||
|
||||
func filteredDuplicatedFields(fields []*StructFieldCode, duplicatedFieldMap map[*StructFieldCode]struct{}) []*StructFieldCode {
|
||||
filteredFields := make([]*StructFieldCode, 0, len(fields))
|
||||
for _, field := range fields {
|
||||
if field.isAnonymous {
|
||||
structCode := field.getAnonymousStruct()
|
||||
if structCode != nil && !structCode.isRecursive {
|
||||
structCode.fields = filteredDuplicatedFields(structCode.fields, duplicatedFieldMap)
|
||||
if len(structCode.fields) > 0 {
|
||||
filteredFields = append(filteredFields, field)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
if _, exists := duplicatedFieldMap[field]; exists {
|
||||
continue
|
||||
}
|
||||
filteredFields = append(filteredFields, field)
|
||||
}
|
||||
return filteredFields
|
||||
}
|
||||
|
||||
func isTaggedKeyOnly(fields []*StructFieldCode) bool {
|
||||
var taggedKeyFieldCount int
|
||||
for _, field := range fields {
|
||||
if field.isTaggedKey {
|
||||
taggedKeyFieldCount++
|
||||
}
|
||||
}
|
||||
return taggedKeyFieldCount == 1
|
||||
}
|
||||
|
||||
func typeToStructTags(typ *runtime.Type) runtime.StructTags {
|
||||
tags := runtime.StructTags{}
|
||||
fieldNum := typ.NumField()
|
||||
for i := 0; i < fieldNum; i++ {
|
||||
field := typ.Field(i)
|
||||
if runtime.IsIgnoredStructField(field) {
|
||||
continue
|
||||
}
|
||||
tags = append(tags, runtime.StructTagFromField(field))
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// *struct{ field T } => struct { field *T }
|
||||
// func (*T) MarshalJSON() ([]byte, error)
|
||||
func isMovePointerPositionFromHeadToFirstMarshalJSONFieldCase(typ *runtime.Type, isIndirectSpecialCase bool) bool {
|
||||
return isIndirectSpecialCase && !isNilableType(typ) && isPtrMarshalJSONType(typ)
|
||||
}
|
||||
|
||||
// *struct{ field T } => struct { field *T }
|
||||
// func (*T) MarshalText() ([]byte, error)
|
||||
func isMovePointerPositionFromHeadToFirstMarshalTextFieldCase(typ *runtime.Type, isIndirectSpecialCase bool) bool {
|
||||
return isIndirectSpecialCase && !isNilableType(typ) && isPtrMarshalTextType(typ)
|
||||
}
|
||||
|
||||
func (c *StructCode) compileStructField(ctx *compileContext, tag *runtime.StructTag, isPtr, isOnlyOneFirstField bool) (*StructFieldCode, error) {
|
||||
field := tag.Field
|
||||
fieldType := runtime.Type2RType(field.Type)
|
||||
|
@ -1442,7 +840,7 @@ func (c *StructCode) compileStructField(ctx *compileContext, tag *runtime.Struct
|
|||
}
|
||||
switch {
|
||||
case isMovePointerPositionFromHeadToFirstMarshalJSONFieldCase(fieldType, isIndirectSpecialCase):
|
||||
code, err := compileMarshalJSON2(ctx.withType(fieldType))
|
||||
code, err := compileMarshalJSON(ctx.withType(fieldType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1452,7 +850,7 @@ func (c *StructCode) compileStructField(ctx *compileContext, tag *runtime.Struct
|
|||
c.isIndirect = false
|
||||
c.disableIndirectConversion = true
|
||||
case isMovePointerPositionFromHeadToFirstMarshalTextFieldCase(fieldType, isIndirectSpecialCase):
|
||||
code, err := compileMarshalText2(ctx.withType(fieldType))
|
||||
code, err := compileMarshalText(ctx.withType(fieldType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1464,7 +862,7 @@ func (c *StructCode) compileStructField(ctx *compileContext, tag *runtime.Struct
|
|||
case isPtr && isPtrMarshalJSONType(fieldType):
|
||||
// *struct{ field T }
|
||||
// func (*T) MarshalJSON() ([]byte, error)
|
||||
code, err := compileMarshalJSON2(ctx.withType(fieldType))
|
||||
code, err := compileMarshalJSON(ctx.withType(fieldType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1474,7 +872,7 @@ func (c *StructCode) compileStructField(ctx *compileContext, tag *runtime.Struct
|
|||
case isPtr && isPtrMarshalTextType(fieldType):
|
||||
// *struct{ field T }
|
||||
// func (*T) MarshalText() ([]byte, error)
|
||||
code, err := compileMarshalText2(ctx.withType(fieldType))
|
||||
code, err := compileMarshalText(ctx.withType(fieldType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue