add filter rule

This commit is contained in:
Masaaki Goshima 2021-11-20 17:00:52 +09:00
parent bcaf36681a
commit d11fc7fe6c
No known key found for this signature in database
GPG Key ID: 6A53785055537153
2 changed files with 89 additions and 25 deletions

View File

@ -168,6 +168,27 @@ func (c *StructCode) ToOpcode() []*Opcode {
return []*Opcode{}
}
func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) {
fields := make([]*StructFieldCode, 0, len(c.fields))
for _, field := range c.fields {
if field.isAnonymous {
structCode := field.getAnonymousStruct()
if structCode != nil {
structCode.removeFieldsByTags(tags)
if len(structCode.fields) > 0 {
fields = append(fields, field)
}
continue
}
}
if tags.ExistsKey(field.key) {
continue
}
fields = append(fields, field)
}
c.fields = fields
}
type StructFieldCode struct {
typ *runtime.Type
key string
@ -181,7 +202,14 @@ type StructFieldCode struct {
isNextOpPtrType bool
}
func (c *StructFieldCode) toInlineCode() []*StructFieldCode {
func (c *StructFieldCode) getAnonymousStruct() *StructCode {
if !c.isAnonymous {
return nil
}
code, ok := c.value.(*StructCode)
if ok {
return code
}
return nil
}
@ -486,50 +514,87 @@ func compileStruct2(ctx *compileContext, isPtr bool) (*StructCode, error) {
return nil, err
}
if field.isAnonymous {
structCode, ok := field.value.(*StructCode)
if ok {
for _, field := range structCode.fields {
if tags.ExistsKey(field.key) {
continue
}
fields = append(fields, field)
}
} else {
fields = append(fields, field)
structCode := field.getAnonymousStruct()
if structCode != nil {
structCode.removeFieldsByTags(tags)
}
} else {
fields = append(fields, field)
}
fields = append(fields, field)
}
fieldMap := getFieldMap(fields)
duplicatedFieldMap := getDuplicatedFieldMap(fieldMap)
code.fields = filteredDuplicatedFields(fields, duplicatedFieldMap)
return code, nil
}
func getFieldMap(fields []*StructFieldCode) map[string][]*StructFieldCode {
fieldMap := map[string][]*StructFieldCode{}
for _, field := range fields {
if field.isAnonymous {
structCode := field.getAnonymousStruct()
if structCode != nil {
for k, v := range getFieldMap(structCode.fields) {
fieldMap[k] = append(fieldMap[k], v...)
}
continue
}
}
fieldMap[field.key] = append(fieldMap[field.key], field)
}
removeFieldKey := map[string]struct{}{}
return fieldMap
}
func getDuplicatedFieldMap(fieldMap map[string][]*StructFieldCode) map[*StructFieldCode]struct{} {
duplicatedFieldMap := map[*StructFieldCode]struct{}{}
for _, fields := range fieldMap {
if len(fields) == 1 {
continue
}
var foundTaggedKey bool
for _, field := range fields {
if field.isTaggedKey {
if foundTaggedKey {
removeFieldKey[field.key] = struct{}{}
break
if isTaggedKeyOnly(fields) {
for _, field := range fields {
if field.isTaggedKey {
continue
}
foundTaggedKey = true
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 _, exists := removeFieldKey[field.key]; exists {
if field.isAnonymous {
structCode := field.getAnonymousStruct()
if structCode != nil {
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)
}
code.fields = filteredFields
return code, nil
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 {

View File

@ -1316,7 +1316,6 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
fieldPtrIndex := ctx.ptrIndex
ctx.incIndex()
fmt.Println("fieldOpcodeIndex = ", fieldOpcodeIndex)
nilcheck := true
addrForMarshaler := false
isIndirectSpecialCase := isPtr && i == 0 && fieldNum == 1