mirror of
https://github.com/hanzoai/orm.git
synced 2026-10-30 15:01:22 +00:00
Modules declare go 1.27.1 and the build images follow. go fix applied the modernizers: any, reflect.TypeFor, the atomic types, WaitGroup.Go, the reflect field iterators, CutPrefix, SplitSeq, strings.Builder and range over int. omitzero is not applied, since it changes what the JSON says. Co-authored-by: Hanzo Dev <[email protected]>
105 lines
2.1 KiB
Go
105 lines
2.1 KiB
Go
package reflect
|
|
|
|
import "reflect"
|
|
|
|
// Copy copies fields from src to dst using reflection.
|
|
// Supports struct-to-struct and slice-to-slice copying.
|
|
func Copy(src any, dst any) (err error) {
|
|
var (
|
|
isSlice bool
|
|
fromType reflect.Type
|
|
isFromPtr bool
|
|
toType reflect.Type
|
|
isToPtr bool
|
|
amount int
|
|
)
|
|
|
|
from := reflect.Indirect(reflect.ValueOf(src))
|
|
to := reflect.Indirect(reflect.ValueOf(dst))
|
|
|
|
if to.Kind() == reflect.Slice {
|
|
isSlice = true
|
|
if from.Kind() == reflect.Slice {
|
|
fromType = from.Type().Elem()
|
|
if fromType.Kind() == reflect.Pointer {
|
|
fromType = fromType.Elem()
|
|
isFromPtr = true
|
|
}
|
|
amount = from.Len()
|
|
} else {
|
|
fromType = from.Type()
|
|
amount = 1
|
|
}
|
|
|
|
toType = to.Type().Elem()
|
|
if toType.Kind() == reflect.Pointer {
|
|
toType = toType.Elem()
|
|
isToPtr = true
|
|
}
|
|
} else {
|
|
fromType = from.Type()
|
|
toType = to.Type()
|
|
amount = 1
|
|
}
|
|
|
|
for e := 0; e < amount; e++ {
|
|
var dest, source reflect.Value
|
|
if isSlice {
|
|
if from.Kind() == reflect.Slice {
|
|
source = from.Index(e)
|
|
if isFromPtr {
|
|
source = source.Elem()
|
|
}
|
|
} else {
|
|
source = from
|
|
}
|
|
} else {
|
|
source = from
|
|
}
|
|
|
|
if isSlice {
|
|
dest = reflect.New(toType).Elem()
|
|
} else {
|
|
dest = to
|
|
}
|
|
|
|
for field := range fromType.Fields() {
|
|
if !field.Anonymous {
|
|
name := field.Name
|
|
fromField := source.FieldByName(name)
|
|
toField := dest.FieldByName(name)
|
|
toMethod := dest.Addr().MethodByName(name)
|
|
if fromField.IsValid() && toField.IsValid() {
|
|
toField.Set(fromField)
|
|
}
|
|
if fromField.IsValid() && toMethod.IsValid() {
|
|
toMethod.Call([]reflect.Value{fromField})
|
|
}
|
|
}
|
|
}
|
|
|
|
for field := range toType.Fields() {
|
|
if !field.Anonymous {
|
|
name := field.Name
|
|
fromMethod := source.Addr().MethodByName(name)
|
|
toField := dest.FieldByName(name)
|
|
if fromMethod.IsValid() && toField.IsValid() {
|
|
values := fromMethod.Call([]reflect.Value{})
|
|
if len(values) >= 1 {
|
|
toField.Set(values[0])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if isSlice {
|
|
if isToPtr {
|
|
to.Set(reflect.Append(to, dest.Addr()))
|
|
} else {
|
|
to.Set(reflect.Append(to, dest))
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|