|
|
|
@@ -6,16 +6,33 @@ import (
|
|
|
|
|
"strings"
|
|
|
|
|
"sync"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/modern-go/reflect2"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func Copy(dst, src any, opts ...option) error {
|
|
|
|
|
opt := getOpt(opts...)
|
|
|
|
|
return copy(dst, src, opt)
|
|
|
|
|
type copier struct {
|
|
|
|
|
opt *options
|
|
|
|
|
visited map[reflect.Value]struct{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func copy(dst, src any, opt *options) error {
|
|
|
|
|
func newCopier(opts ...option) *copier {
|
|
|
|
|
opt := getOpt(opts...)
|
|
|
|
|
var visited map[reflect.Value]struct{}
|
|
|
|
|
if opt.detectCircularRefs {
|
|
|
|
|
visited = make(map[reflect.Value]struct{})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &copier{
|
|
|
|
|
visited: visited,
|
|
|
|
|
opt: opt,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *copier) Copy(dst, src any) error {
|
|
|
|
|
defer c.reset()
|
|
|
|
|
|
|
|
|
|
if dst == nil || src == nil {
|
|
|
|
|
return ErrInvalidCopyDestination
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
srcValue = indirect(reflect.ValueOf(src))
|
|
|
|
|
dstValue = indirect(reflect.ValueOf(dst))
|
|
|
|
@@ -29,36 +46,46 @@ func copy(dst, src any, opt *options) error {
|
|
|
|
|
return ErrInvalidCopyDestination
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return deepCopy(dstValue, srcValue, 0, "", opt)
|
|
|
|
|
return c.deepCopy(dstValue, srcValue, 0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func deepCopy(dst, src reflect.Value, depth int, fieldName string, opt *options) error {
|
|
|
|
|
func (c *copier) reset() {
|
|
|
|
|
if c.opt.detectCircularRefs {
|
|
|
|
|
c.visited = make(map[reflect.Value]struct{})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *copier) deepCopy(dst, src reflect.Value, depth int) error {
|
|
|
|
|
if c.ExceedMaxDepth(depth) {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if src.IsZero() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if opt.ExceedMaxDepth(depth) {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fmt.Println("do deep copy src:", src.Kind().String(), "dst:", dst.Kind().String())
|
|
|
|
|
switch src.Kind() {
|
|
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
|
|
// slice -> slice
|
|
|
|
|
return copySlice(dst, src, depth, fieldName, opt)
|
|
|
|
|
switch dst.Kind() {
|
|
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
|
|
return c.copySlice(dst, src, depth)
|
|
|
|
|
default:
|
|
|
|
|
return ErrNotSupported
|
|
|
|
|
}
|
|
|
|
|
case reflect.Map:
|
|
|
|
|
switch dst.Kind() {
|
|
|
|
|
case reflect.Map:
|
|
|
|
|
// map -> map
|
|
|
|
|
return copyMap(dst, src, depth, fieldName, opt)
|
|
|
|
|
return c.copyMap(dst, src, depth)
|
|
|
|
|
case reflect.Struct:
|
|
|
|
|
// map -> struct
|
|
|
|
|
return copyMap2Struct(dst, src, depth, fieldName, opt)
|
|
|
|
|
return c.copyMap2Struct(dst, src, depth)
|
|
|
|
|
case reflect.Pointer:
|
|
|
|
|
elemType := dst.Type().Elem()
|
|
|
|
|
newPtr := reflect.New(elemType)
|
|
|
|
|
|
|
|
|
|
if err := deepCopy(newPtr.Elem(), src, depth+1, fieldName, opt); err != nil {
|
|
|
|
|
if err := c.deepCopy(newPtr.Elem(), src, depth+1); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -71,17 +98,17 @@ func deepCopy(dst, src reflect.Value, depth int, fieldName string, opt *options)
|
|
|
|
|
switch dst.Kind() {
|
|
|
|
|
case reflect.Map:
|
|
|
|
|
// struct -> map
|
|
|
|
|
return copyStruct2Map(dst, src, depth, fieldName, opt)
|
|
|
|
|
return c.copyStruct2Map(dst, src, depth)
|
|
|
|
|
case reflect.Struct:
|
|
|
|
|
// struct -> struct
|
|
|
|
|
return copyStruct(dst, src, depth, opt)
|
|
|
|
|
return c.copyStruct(dst, src, depth)
|
|
|
|
|
case reflect.Array, reflect.Slice:
|
|
|
|
|
if dst.IsNil() {
|
|
|
|
|
dstType := dst.Type().Elem()
|
|
|
|
|
newDst := reflect.MakeSlice(reflect.SliceOf(dstType), 1, 1)
|
|
|
|
|
dst.Set(newDst)
|
|
|
|
|
|
|
|
|
|
if err := deepCopy(dst.Index(0), src, depth+1, fieldName, opt); err != nil {
|
|
|
|
|
if err := c.deepCopy(dst.Index(0), src, depth+1); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -92,7 +119,7 @@ func deepCopy(dst, src reflect.Value, depth int, fieldName string, opt *options)
|
|
|
|
|
reflect.Copy(newSlice, dst)
|
|
|
|
|
|
|
|
|
|
newDst := newSlice.Index(len)
|
|
|
|
|
if err := deepCopy(newDst, src, depth+1, fieldName, opt); err != nil {
|
|
|
|
|
if err := c.deepCopy(newDst, src, depth+1); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
dst.Set(newSlice)
|
|
|
|
@@ -100,14 +127,9 @@ func deepCopy(dst, src reflect.Value, depth int, fieldName string, opt *options)
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
default:
|
|
|
|
|
return set(dst, src, fieldName, opt)
|
|
|
|
|
return c.set(dst, src)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case reflect.Func:
|
|
|
|
|
if dst.Kind() == reflect.Func && dst.IsNil() {
|
|
|
|
|
dst.Set(src)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
case reflect.Pointer:
|
|
|
|
|
if dst.Kind() == reflect.Pointer && dst.IsNil() {
|
|
|
|
|
if !dst.CanSet() {
|
|
|
|
@@ -125,7 +147,7 @@ func deepCopy(dst, src reflect.Value, depth int, fieldName string, opt *options)
|
|
|
|
|
dst = dst.Elem()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return deepCopy(dst, src, depth, fieldName, opt)
|
|
|
|
|
return c.deepCopy(dst, src, depth)
|
|
|
|
|
|
|
|
|
|
case reflect.Interface:
|
|
|
|
|
if src.IsNil() {
|
|
|
|
@@ -133,26 +155,26 @@ func deepCopy(dst, src reflect.Value, depth int, fieldName string, opt *options)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if src.Kind() != dst.Kind() {
|
|
|
|
|
return set(dst, src, fieldName, opt)
|
|
|
|
|
return c.set(dst, src)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
src = src.Elem()
|
|
|
|
|
newDst := reflect.New(src.Type().Elem())
|
|
|
|
|
|
|
|
|
|
if err := deepCopy(newDst, src, depth, fieldName, opt); err != nil {
|
|
|
|
|
if err := c.deepCopy(newDst, src, depth); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dst.Set(newDst)
|
|
|
|
|
return nil
|
|
|
|
|
case reflect.Chan:
|
|
|
|
|
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
|
|
|
|
|
return ErrNotSupported
|
|
|
|
|
default:
|
|
|
|
|
return set(dst, src, fieldName, opt)
|
|
|
|
|
return c.set(dst, src)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func copyStruct2Map(dst, src reflect.Value, depth int, fieldName string, opt *options) error {
|
|
|
|
|
func (c *copier) copyStruct2Map(dst, src reflect.Value, depth int) error {
|
|
|
|
|
for i, n := 0, src.NumField(); i < n; i++ {
|
|
|
|
|
sf := src.Type().Field(i)
|
|
|
|
|
if sf.PkgPath != "" && !sf.Anonymous {
|
|
|
|
@@ -162,7 +184,7 @@ func copyStruct2Map(dst, src reflect.Value, depth int, fieldName string, opt *op
|
|
|
|
|
if sf.Anonymous {
|
|
|
|
|
switch sf.Type.Kind() {
|
|
|
|
|
case reflect.Struct, reflect.Pointer:
|
|
|
|
|
if err := deepCopy(dst, src.Field(i), depth+1, fieldName, opt); err != nil {
|
|
|
|
|
if err := c.deepCopy(dst, src.Field(i), depth+1); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -170,16 +192,16 @@ func copyStruct2Map(dst, src reflect.Value, depth int, fieldName string, opt *op
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tag := parseTag(sf.Tag.Get(opt.tagName))
|
|
|
|
|
tag := parseTag(sf.Tag.Get(c.opt.tagName))
|
|
|
|
|
if tag.Contains(tagIgnore) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name := getFieldName(sf.Name, tag, opt)
|
|
|
|
|
name := c.getFieldName(sf.Name, tag)
|
|
|
|
|
|
|
|
|
|
sField := src.Field(i)
|
|
|
|
|
|
|
|
|
|
if opt.ignoreEmpty && sField.IsZero() {
|
|
|
|
|
if c.opt.ignoreEmpty && sField.IsZero() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -187,7 +209,7 @@ func copyStruct2Map(dst, src reflect.Value, depth int, fieldName string, opt *op
|
|
|
|
|
var newDst = reflect.ValueOf(make(map[string]any))
|
|
|
|
|
sField = indirect(sField)
|
|
|
|
|
|
|
|
|
|
if err := deepCopy(newDst, sField, depth+1, name, opt); err != nil {
|
|
|
|
|
if err := c.deepCopy(newDst, sField, depth+1); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -200,11 +222,9 @@ func copyStruct2Map(dst, src reflect.Value, depth int, fieldName string, opt *op
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func copyMap2Struct(dst, src reflect.Value, depth int, _ string, opt *options) error {
|
|
|
|
|
// 循环结构,然后从map取值
|
|
|
|
|
func (c *copier) copyMap2Struct(dst, src reflect.Value, depth int) error {
|
|
|
|
|
typ := dst.Type()
|
|
|
|
|
|
|
|
|
|
for i, n := 0, src.NumField(); i < n; i++ {
|
|
|
|
|
for i, n := 0, dst.NumField(); i < n; i++ {
|
|
|
|
|
field := dst.Field(i)
|
|
|
|
|
sf := typ.Field(i)
|
|
|
|
|
|
|
|
|
@@ -213,15 +233,12 @@ func copyMap2Struct(dst, src reflect.Value, depth int, _ string, opt *options) e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if sf.Anonymous {
|
|
|
|
|
if err := deepCopy(field, src, depth+1, sf.Name, opt); err != nil {
|
|
|
|
|
if err := c.deepCopy(field, src, depth+1); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name := getFieldNameFromJsonTag(sf)
|
|
|
|
|
if name == "-" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
name := sf.Name
|
|
|
|
|
|
|
|
|
|
mapValue := src.MapIndex(reflect.ValueOf(name))
|
|
|
|
|
if !mapValue.IsValid() {
|
|
|
|
@@ -233,11 +250,11 @@ func copyMap2Struct(dst, src reflect.Value, depth int, _ string, opt *options) e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if mapValue.Kind() == reflect.Map || mapValue.Kind() == reflect.Array || mapValue.Kind() == reflect.Slice {
|
|
|
|
|
if err := deepCopy(field, mapValue, depth+1, name, opt); err != nil {
|
|
|
|
|
if err := c.deepCopy(field, mapValue, depth+1); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if err := set(field, mapValue, name, opt); err != nil {
|
|
|
|
|
if err := c.set(field, mapValue); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -246,7 +263,7 @@ func copyMap2Struct(dst, src reflect.Value, depth int, _ string, opt *options) e
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func copyMap(dst, src reflect.Value, depth int, fieldName string, opt *options) error {
|
|
|
|
|
func (c *copier) copyMap(dst, src reflect.Value, depth int) error {
|
|
|
|
|
if dst.IsNil() {
|
|
|
|
|
dst.Set(reflect.MakeMapWithSize(dst.Type(), src.Len()))
|
|
|
|
|
}
|
|
|
|
@@ -259,11 +276,11 @@ func copyMap(dst, src reflect.Value, depth int, fieldName string, opt *options)
|
|
|
|
|
value := iter.Value()
|
|
|
|
|
|
|
|
|
|
if name, ok := key.Interface().(string); ok {
|
|
|
|
|
fieldName = opt.NameConvert(name)
|
|
|
|
|
fieldName := c.getFieldName(name, nil)
|
|
|
|
|
key = reflect.ValueOf(fieldName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if opt.ignoreEmpty && value.IsZero() {
|
|
|
|
|
if c.opt.ignoreEmpty && value.IsZero() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -277,12 +294,12 @@ func copyMap(dst, src reflect.Value, depth int, fieldName string, opt *options)
|
|
|
|
|
copitedValue = reflect.New(value.Type()).Elem()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set(copitedValue, value, fieldName, opt)
|
|
|
|
|
c.set(copitedValue, value)
|
|
|
|
|
default:
|
|
|
|
|
copitedValue = reflect.New(dstType.Elem()).Elem()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := deepCopy(copitedValue, value, depth+1, fieldName, opt); err != nil {
|
|
|
|
|
if err := c.deepCopy(copitedValue, value, depth+1); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -292,28 +309,40 @@ func copyMap(dst, src reflect.Value, depth int, fieldName string, opt *options)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func copySlice(dst, src reflect.Value, depth int, fieldName string, opt *options) error {
|
|
|
|
|
len := src.Len()
|
|
|
|
|
func (c *copier) copySlice(dst, src reflect.Value, depth int) error {
|
|
|
|
|
var len int
|
|
|
|
|
if src.Kind() == reflect.Struct {
|
|
|
|
|
len = 0
|
|
|
|
|
} else {
|
|
|
|
|
len = src.Len()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if dst.Len() > 0 && dst.Len() < src.Len() {
|
|
|
|
|
len = dst.Len()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if dst.Kind() == reflect.Slice && dst.Len() == 0 && src.Len() > 0 {
|
|
|
|
|
if dst.Kind() == reflect.Slice && dst.Len() == 0 && len > 0 {
|
|
|
|
|
dstType := dst.Type().Elem()
|
|
|
|
|
newDst := reflect.MakeSlice(reflect.SliceOf(dstType), len, len)
|
|
|
|
|
dst.Set(newDst)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := 0; i < len; i++ {
|
|
|
|
|
if err := deepCopy(dst.Index(i), src.Index(i), depth, fieldName, opt); err != nil {
|
|
|
|
|
if src.Kind() == reflect.Struct {
|
|
|
|
|
if err := c.deepCopy(dst.Index(0), src, depth); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for i := 0; i < len; i++ {
|
|
|
|
|
if err := c.deepCopy(dst.Index(i), src.Index(i), depth); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func copyStruct(dst, src reflect.Value, depth int, opt *options) error {
|
|
|
|
|
func (c *copier) copyStruct(dst, src reflect.Value, depth int) error {
|
|
|
|
|
if dst.CanSet() {
|
|
|
|
|
if _, ok := src.Interface().(time.Time); ok {
|
|
|
|
|
dst.Set(src)
|
|
|
|
@@ -322,41 +351,42 @@ func copyStruct(dst, src reflect.Value, depth int, opt *options) error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typ := src.Type()
|
|
|
|
|
fields := deepFields(typ)
|
|
|
|
|
fields := c.deepFields(typ)
|
|
|
|
|
for _, sf := range fields {
|
|
|
|
|
tag := parseTag(sf.Tag.Get(opt.tagName))
|
|
|
|
|
if tag.Contains(tagIgnore) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name := getFieldName(sf.Name, tag, opt)
|
|
|
|
|
name := c.getFieldName(sf.Field.Name, sf.Tag)
|
|
|
|
|
|
|
|
|
|
if nestedAnonymousField(dst, name) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typ := reflect2.TypeOf(dst)
|
|
|
|
|
dstPtr := reflect2.PtrOf(dst)
|
|
|
|
|
typ.(reflect2.StructType).Field(1).UnsafeGet(dstPtr)
|
|
|
|
|
|
|
|
|
|
dstValue := fieldByName(dst, name, opt)
|
|
|
|
|
dstValue := c.fieldByName(dst, name)
|
|
|
|
|
if !dstValue.IsValid() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sField := src.FieldByName(sf.Name)
|
|
|
|
|
if opt.ignoreEmpty && sField.IsZero() {
|
|
|
|
|
if c.isCricularRefs(dstValue) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := deepCopy(dstValue, sField, depth+1, name, opt); err != nil {
|
|
|
|
|
sField := src.FieldByName(sf.Field.Name)
|
|
|
|
|
if c.opt.ignoreEmpty && sField.IsZero() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ok, err := c.lookupAndCopyWithConverter(dstValue, sField, name); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
} else if ok {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.deepCopy(dstValue, sField, depth+1); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func set(dst, src reflect.Value, fieldName string, opt *options) error {
|
|
|
|
|
func (c *copier) set(dst, src reflect.Value) error {
|
|
|
|
|
if !src.IsValid() {
|
|
|
|
|
return ErrInvalidCopyFrom
|
|
|
|
|
}
|
|
|
|
@@ -365,11 +395,11 @@ func set(dst, src reflect.Value, fieldName string, opt *options) error {
|
|
|
|
|
src = src.Elem()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ok, err := lookupAndCopyWithConverter(dst, src, fieldName, opt); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
} else if ok {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
// if ok, err := c.lookupAndCopyWithConverter(dst, src, fieldName); err != nil {
|
|
|
|
|
// return err
|
|
|
|
|
// } else if ok {
|
|
|
|
|
// return nil
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
if dst.Kind() == reflect.Pointer {
|
|
|
|
|
if dst.IsNil() {
|
|
|
|
@@ -465,17 +495,23 @@ func set(dst, src reflect.Value, fieldName string, opt *options) error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type fieldsWrapper struct {
|
|
|
|
|
Fields []reflect.StructField
|
|
|
|
|
Fields []fieldWrapper
|
|
|
|
|
once sync.Once
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type fieldWrapper struct {
|
|
|
|
|
Field reflect.StructField
|
|
|
|
|
Tag *tagOption
|
|
|
|
|
Index int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var deepFieldsMap sync.Map
|
|
|
|
|
|
|
|
|
|
func deepFields(reflectType reflect.Type) []reflect.StructField {
|
|
|
|
|
func (c *copier) deepFields(reflectType reflect.Type) []fieldWrapper {
|
|
|
|
|
if wrapper, ok := deepFieldsMap.Load(reflectType); ok {
|
|
|
|
|
w := wrapper.(*fieldsWrapper)
|
|
|
|
|
w.once.Do(func() {
|
|
|
|
|
w.Fields = calculateDeepFields(reflectType)
|
|
|
|
|
w.Fields = c.calculateDeepFields(reflectType)
|
|
|
|
|
})
|
|
|
|
|
return w.Fields
|
|
|
|
|
}
|
|
|
|
@@ -484,7 +520,7 @@ func deepFields(reflectType reflect.Type) []reflect.StructField {
|
|
|
|
|
w := wrapper.(*fieldsWrapper)
|
|
|
|
|
if !loaded {
|
|
|
|
|
w.once.Do(func() {
|
|
|
|
|
w.Fields = calculateDeepFields(reflectType)
|
|
|
|
|
w.Fields = c.calculateDeepFields(reflectType)
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
w.once.Do(func() {})
|
|
|
|
@@ -493,10 +529,10 @@ func deepFields(reflectType reflect.Type) []reflect.StructField {
|
|
|
|
|
return w.Fields
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func calculateDeepFields(reflectType reflect.Type) []reflect.StructField {
|
|
|
|
|
func (c *copier) calculateDeepFields(reflectType reflect.Type) []fieldWrapper {
|
|
|
|
|
reflectType, _ = indirectType(reflectType)
|
|
|
|
|
num := reflectType.NumField()
|
|
|
|
|
res := make([]reflect.StructField, 0, num)
|
|
|
|
|
res := make([]fieldWrapper, 0, num)
|
|
|
|
|
if reflectType.Kind() == reflect.Struct {
|
|
|
|
|
for i := range num {
|
|
|
|
|
sf := reflectType.Field(i)
|
|
|
|
@@ -504,11 +540,13 @@ func calculateDeepFields(reflectType reflect.Type) []reflect.StructField {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tag := parseTag(sf.Tag.Get(c.opt.tagName))
|
|
|
|
|
|
|
|
|
|
if sf.Anonymous {
|
|
|
|
|
res = append(res, deepFields(sf.Type)...)
|
|
|
|
|
res = append(res, c.deepFields(sf.Type)...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = append(res, sf)
|
|
|
|
|
res = append(res, fieldWrapper{Field: sf, Tag: tag, Index: i})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -540,18 +578,18 @@ func nestedAnonymousField(dst reflect.Value, fieldName string) bool {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func lookupAndCopyWithConverter(dst, src reflect.Value, fieldName string, opt *options) (bool, error) {
|
|
|
|
|
if cnv, ok := opt.convertByName[fieldName]; ok {
|
|
|
|
|
func (c *copier) lookupAndCopyWithConverter(dst, src reflect.Value, fieldName string) (bool, error) {
|
|
|
|
|
if cnv, ok := c.opt.convertByName[fieldName]; ok {
|
|
|
|
|
return convert(dst, src, cnv)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(opt.converters) > 0 {
|
|
|
|
|
if len(c.opt.converters) > 0 {
|
|
|
|
|
pair := converterPair{
|
|
|
|
|
SrcType: src.Type(),
|
|
|
|
|
DstType: dst.Type(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cnv, ok := opt.converters[pair]; ok {
|
|
|
|
|
if cnv, ok := c.opt.converters[pair]; ok {
|
|
|
|
|
return convert(dst, src, cnv)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -575,36 +613,37 @@ func convert(dst, src reflect.Value, fn convertFunc) (bool, error) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getFieldNameFromJsonTag(field reflect.StructField) string {
|
|
|
|
|
if tag := field.Tag.Get("json"); tag != "" {
|
|
|
|
|
if commaIndex := strings.Index(tag, ","); commaIndex != -1 {
|
|
|
|
|
name := tag[:commaIndex]
|
|
|
|
|
if name != "" {
|
|
|
|
|
return name
|
|
|
|
|
}
|
|
|
|
|
} else if tag != "" {
|
|
|
|
|
return tag
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return field.Name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getFieldName(name string, tag *tagOption, opt *options) string {
|
|
|
|
|
func (c *copier) getFieldName(name string, tag *tagOption) string {
|
|
|
|
|
if tag != nil && tag.Contains(tagToName) {
|
|
|
|
|
return tag.toname
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return opt.NameConvert(name)
|
|
|
|
|
return c.opt.NameConvert(name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func fieldByName(v reflect.Value, name string, opt *options) reflect.Value {
|
|
|
|
|
if opt != nil && opt.caseSensitive {
|
|
|
|
|
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) isCricularRefs(reflectValue reflect.Value) bool {
|
|
|
|
|
if c.opt.detectCircularRefs {
|
|
|
|
|
_, ok := c.visited[reflectValue.Addr()]
|
|
|
|
|
if !ok {
|
|
|
|
|
c.visited[reflectValue.Addr()] = struct{}{}
|
|
|
|
|
}
|
|
|
|
|
return ok
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func indirect(reflectValue reflect.Value) reflect.Value {
|
|
|
|
|
for reflectValue.Kind() == reflect.Pointer {
|
|
|
|
|
reflectValue = reflectValue.Elem()
|
|
|
|
|