a6990aa4af
Split monolithic copier.go (1077 lines) into focused modules: - copier.go: Core framework (95 lines) - copy_value.go: Copy functions and type handling (858 lines) - reflect.go: Reflection utilities (100 lines) - converter.go: Type converter (38 lines) - options.go: Configuration (renamed from optiongs.go) Bug fixes: - Fixed string to *string copying (empty strings now work) - Fixed *time.Time to *time.Time copying - Fixed nil slice handling - Fixed copyStructToSlice pointer element handling Tests: Fixed critical data copy issues. Remaining method-mapping features require additional implementation.
101 lines
2.1 KiB
Go
101 lines
2.1 KiB
Go
package copier
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
func nestedAnonymousField(dst reflect.Value, fieldName string) bool {
|
|
if f, ok := dst.Type().FieldByName(fieldName); ok {
|
|
if len(f.Index) > 1 {
|
|
destField := dst.Field(f.Index[0])
|
|
|
|
if destField.Kind() != reflect.Pointer {
|
|
return false
|
|
}
|
|
|
|
if !destField.IsNil() {
|
|
return false
|
|
}
|
|
|
|
if destField.CanSet() {
|
|
destField.Set(reflect.New(destField.Type().Elem()))
|
|
} else {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (c *copier) getFieldName(name string, tag *tagOption) string {
|
|
if tag != nil && tag.Contains(tagName) {
|
|
return tag.name
|
|
}
|
|
|
|
return c.opt.NameConvert(name)
|
|
}
|
|
|
|
func (c *copier) getFieldName2(fieldName string, tag *tagOption) (srcFieldName string, dstFieldName string) {
|
|
return fieldName, c.getFieldName(fieldName, tag)
|
|
}
|
|
|
|
func (c *copier) fieldByName(v reflect.Value, name string) reflect.Value {
|
|
if c.opt != nil && c.opt.caseSensitive {
|
|
return v.FieldByName(name)
|
|
}
|
|
return v.FieldByNameFunc(func(s string) bool { return strings.EqualFold(s, name) })
|
|
}
|
|
|
|
func (c *copier) ExceedMaxDepth(depth int) bool {
|
|
return c.opt.maxDepth > 0 && depth >= c.opt.maxDepth
|
|
}
|
|
|
|
func (c *copier) isCircularRefs(v reflect.Value) bool {
|
|
if !c.opt.detectCircularRefs || !v.IsValid() || !v.CanAddr() {
|
|
return false
|
|
}
|
|
|
|
ptr := c.getValuePointer(v)
|
|
if _, exists := c.visited[ptr]; exists {
|
|
return true
|
|
}
|
|
|
|
c.visited[ptr] = struct{}{}
|
|
return false
|
|
}
|
|
|
|
func (c *copier) getValuePointer(v reflect.Value) uintptr {
|
|
switch v.Kind() {
|
|
case reflect.Pointer, reflect.Slice, reflect.Map, reflect.Func, reflect.Chan:
|
|
return v.Pointer()
|
|
case reflect.Struct:
|
|
if v.CanAddr() {
|
|
return v.Addr().Pointer()
|
|
}
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func indirect(v reflect.Value) reflect.Value {
|
|
for v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface {
|
|
if v.IsNil() {
|
|
break
|
|
}
|
|
v = v.Elem()
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func indirectType(reflectType reflect.Type) (_ reflect.Type, isPtr bool) {
|
|
for reflectType.Kind() == reflect.Pointer || reflectType.Kind() == reflect.Slice {
|
|
reflectType = reflectType.Elem()
|
|
isPtr = true
|
|
}
|
|
|
|
return reflectType, isPtr
|
|
}
|