80 lines
1.5 KiB
Go
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
|
|
}
|