github.com/hedzr/evendeep@v0.4.8/deepcopy.go (about)

     1  package evendeep
     2  
     3  import (
     4  	"github.com/hedzr/evendeep/dbglog"
     5  	"github.com/hedzr/evendeep/flags"
     6  	"github.com/hedzr/evendeep/flags/cms"
     7  	"github.com/hedzr/evendeep/internal/tool"
     8  
     9  	"reflect"
    10  )
    11  
    12  // New gets a new instance of DeepCopier (the underlying
    13  // is *cpController) different with DefaultCopyController.
    14  //
    15  // Use New:
    16  //
    17  //	src, tgt := 123, 0
    18  //	err = evendeep.New().CopyTo(src, &tgt)
    19  //
    20  // Use package functions (With-opts might cumulate):
    21  //
    22  //	evendeep.Copy(src, &tgt) // or synonym: evendeep.DeepCopy(src, &tgt)
    23  //	tgt = evendeep.MakeClone(src)
    24  //
    25  // Use DefaultCopyController (With-opts might cumulate):
    26  //
    27  //	evendeep.DefaultCopyController.CopyTo(src, &tgt)
    28  //
    29  // The most conventional way is:
    30  //
    31  //	err := evendeep.New().CopyTo(src, &tgt)
    32  func New(opts ...Opt) DeepCopier {
    33  	var c = newDeepCopier()
    34  	for _, opt := range opts {
    35  		opt(c)
    36  	}
    37  	return c
    38  }
    39  
    40  // Copy is a synonym of DeepCopy.
    41  //
    42  // DeepCopy makes a deep clone of a source object or merges it into the target.
    43  func Copy(fromObj, toObj interface{}, opts ...Opt) (result interface{}) {
    44  	return DeepCopy(fromObj, toObj, opts...)
    45  }
    46  
    47  // DeepCopy makes a deep clone of a source object or merges it into the target.
    48  func DeepCopy(fromObj, toObj interface{}, opts ...Opt) (result interface{}) {
    49  	if fromObj == nil {
    50  		return toObj
    51  	}
    52  
    53  	defer DefaultCopyController.SaveFlagsAndRestore()()
    54  
    55  	if err := DefaultCopyController.CopyTo(fromObj, toObj, opts...); err == nil {
    56  		result = toObj
    57  	}
    58  
    59  	return
    60  }
    61  
    62  // MakeClone makes a deep clone of a source object.
    63  func MakeClone(fromObj interface{}) (result interface{}) {
    64  	if fromObj == nil {
    65  		return nil
    66  	}
    67  
    68  	var (
    69  		from     = reflect.ValueOf(fromObj)
    70  		fromTyp  = from.Type()
    71  		findTyp  = tool.Rdecodetypesimple(fromTyp)
    72  		toPtr    = reflect.New(findTyp)
    73  		toPtrObj = toPtr.Interface()
    74  	)
    75  	dbglog.Log("toPtrObj: %v", toPtrObj)
    76  
    77  	defer defaultCloneController.SaveFlagsAndRestore()()
    78  
    79  	if err := defaultCloneController.CopyTo(fromObj, toPtrObj); err == nil {
    80  		result = toPtr.Elem().Interface()
    81  	}
    82  
    83  	return
    84  }
    85  
    86  // Cloneable interface represents a cloneable object that supports Clone() method.
    87  //
    88  // The native Clone algorithm of a Cloneable object can be adapted into DeepCopier.
    89  type Cloneable interface {
    90  	// Clone return a pointer to copy of source object.
    91  	// But you can return the copy itself with your will.
    92  	Clone() interface{}
    93  }
    94  
    95  // DeepCopyable interface represents a cloneable object that supports DeepCopy() method.
    96  //
    97  // The native DeepCopy algorithm of a DeepCopyable object can be adapted into DeepCopier.
    98  type DeepCopyable interface {
    99  	DeepCopy() interface{}
   100  }
   101  
   102  // DeepCopier interface.
   103  type DeepCopier interface {
   104  	// CopyTo function.
   105  	CopyTo(fromObj, toObj interface{}, opts ...Opt) (err error)
   106  }
   107  
   108  //nolint:gochecknoglobals //i know that
   109  var (
   110  	// DefaultCopyController provides standard deepcopy feature.
   111  	// copy and merge slice or map to an existed target.
   112  	DefaultCopyController *cpController // by newDeepCopier()
   113  
   114  	// defaultCloneController provides standard clone feature.
   115  	// simply clone itself to a new fresh object to make a deep clone object.
   116  	defaultCloneController *cpController // by newCloner()
   117  )
   118  
   119  // NewFlatDeepCopier gets a new instance of DeepCopier (the underlying
   120  // is *cpController) like NewDeepCopier but no merge strategies
   121  // (SliceMerge and MapMerge).
   122  func NewFlatDeepCopier(opts ...Opt) DeepCopier {
   123  	// lazyInitRoutines()
   124  	var c = newCopier()
   125  	c.flags = flags.New()
   126  	for _, opt := range opts {
   127  		opt(c)
   128  	}
   129  	return c
   130  }
   131  
   132  func newDeepCopier() *cpController {
   133  	// lazyInitRoutines()
   134  	return &cpController{
   135  		valueConverters: defaultValueConverters(),
   136  		valueCopiers:    defaultValueCopiers(),
   137  
   138  		copyUnexportedFields:       true,
   139  		copyFunctionResultToTarget: true,
   140  		passSourceAsFunctionInArgs: true,
   141  		autoExpandStruct:           true,
   142  		autoNewStruct:              true,
   143  
   144  		flags:        flags.New(cms.SliceMerge, cms.MapMerge),
   145  		rethrow:      true,
   146  		makeNewClone: false,
   147  	}
   148  }
   149  
   150  func newCopier() *cpController {
   151  	return &cpController{
   152  		valueConverters: defaultValueConverters(),
   153  		valueCopiers:    defaultValueCopiers(),
   154  
   155  		copyFunctionResultToTarget: true,
   156  		passSourceAsFunctionInArgs: true,
   157  
   158  		rethrow:      true,
   159  		makeNewClone: false,
   160  	}
   161  }
   162  
   163  func newCloner() *cpController {
   164  	return &cpController{
   165  		valueConverters: defaultValueConverters(),
   166  		valueCopiers:    defaultValueCopiers(),
   167  
   168  		copyFunctionResultToTarget: true,
   169  		passSourceAsFunctionInArgs: true,
   170  		autoExpandStruct:           true,
   171  		autoNewStruct:              true,
   172  
   173  		flags:        flags.New(cms.Default),
   174  		rethrow:      true,
   175  		makeNewClone: true,
   176  	}
   177  }