Files
copier/deep_field.go
2025-09-30 18:41:21 +08:00

80 lines
1.5 KiB
Go

package copier
import (
"reflect"
"sync"
)
type fieldsWrapper struct {
Fields []fieldWrapper
once sync.Once
}
type fieldWrapper struct {
Field reflect.StructField
Name string
Format string
Tag *tagOption
}
// type deepFieldCopier struct {
// srcFields []fieldWrapper
// dstFields []fieldWrapper
// }
var deepFieldsMap sync.Map
func (c *copier) deepFields(reflectType reflect.Type) []fieldWrapper {
if wrapper, ok := deepFieldsMap.Load(reflectType); ok {
w := wrapper.(*fieldsWrapper)
w.once.Do(func() {
w.Fields = c.calculateDeepFields(reflectType)
})
return w.Fields
}
wrapper, loaded := deepFieldsMap.LoadOrStore(reflectType, &fieldsWrapper{})
w := wrapper.(*fieldsWrapper)
if !loaded {
w.once.Do(func() {
w.Fields = c.calculateDeepFields(reflectType)
})
} else {
w.once.Do(func() {})
}
return w.Fields
}
func (c *copier) calculateDeepFields(reflectType reflect.Type) []fieldWrapper {
reflectType, _ = indirectType(reflectType)
num := reflectType.NumField()
res := make([]fieldWrapper, 0, num)
if reflectType.Kind() == reflect.Struct {
for i := range num {
sf := reflectType.Field(i)
if sf.PkgPath != "" && !sf.Anonymous {
continue
}
tag := parseTag(sf.Tag.Get(c.opt.tagName))
if tag.Contains(tagIgnore) {
continue
}
if sf.Anonymous {
res = append(res, c.deepFields(sf.Type)...)
} else {
name := sf.Name
if tag.Contains(tagName) {
name = tag.name
}
res = append(res, fieldWrapper{Field: sf, Tag: tag, Name: name})
}
}
}
return res
}