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 }