github.com/influx6/npkg@v0.8.8/nreflect/deepcopy.go (about) 1 package nreflect 2 3 import ( 4 "reflect" 5 "unsafe" 6 7 "github.com/influx6/npkg/nerror" 8 "github.com/jinzhu/copier" 9 ) 10 11 // DeepCopy copies giving value returning a new distinct value, 12 // else an error due to failure. 13 // 14 // DeepCopy will never attempt to duplicate the following types, as it will simply 15 // return the value it received. 16 // 17 // 1. Channels 18 // 2. Interface 19 // 3. unsafe.Pointer 20 // 4. Func 21 // 22 // For structs, we use github.com/jinzhu/copier for copying, so all rules in that library 23 // applies here also. 24 func DeepCopy(elem interface{}) (interface{}, error) { 25 var err error 26 var refValue reflect.Value 27 28 switch bm := elem.(type) { 29 case reflect.Type: 30 var base = ValueOf(bm) 31 if bm.Kind() == reflect.Ptr { 32 return base, nil 33 } 34 return IndirectValue(base), nil 35 case reflect.Value: 36 refValue, err = deepCopyValue(IndirectValue(bm), bm.Kind() == reflect.Ptr) 37 default: 38 var base = ValueOf(elem) 39 refValue, err = deepCopyValue(IndirectValue(base), base.Kind() == reflect.Ptr) 40 } 41 42 if err != nil { 43 return nil, err 44 } 45 return refValue.Interface(), nil 46 } 47 48 // DeepCopyValue uses the internal deepCopyValue function to make a copy of giving 49 // reflect value type adequately ensuring to return a pointer if a pointer value 50 // was giving to it else returning a value. 51 // 52 // DeepCopy will never attempt to duplicate the following types, as it will simply 53 // return the value it received. 54 // 55 // 1. Channels 56 // 2. Interface 57 // 3. unsafe.Pointer 58 // 4. Func 59 // 60 // For structs, we use github.com/jinzhu/copier for copying, so all rules in that library 61 // applies here also. 62 func DeepCopyValue(baseValue reflect.Value) (interface{}, error) { 63 var refValue, err = deepCopyValue(IndirectValue(baseValue), baseValue.Kind() == reflect.Ptr) 64 if err != nil { 65 return nil, err 66 } 67 return refValue.Interface(), nil 68 } 69 70 // deepCopyValue copies giving reflect.Value returning a new distinct value containing 71 // copy of data, else an error due to failure. 72 // 73 // DeepCopy will never attempt to duplicate the following types, as it will simply 74 // return the value it received. 75 // 76 // 1. Channels 77 // 2. Interface 78 // 3. unsafe.Pointer 79 // 4. Func 80 // 81 // For structs, we use github.com/jinzhu/copier for copying, so all rules in that library 82 // applies here also. 83 func deepCopyValue(baseValue reflect.Value, pointerType bool) (reflect.Value, error) { 84 if !baseValue.IsValid() { 85 return baseValue, nil 86 } 87 88 var valueType = baseValue.Type() 89 90 switch baseValue.Kind() { 91 case reflect.Func: 92 return baseValue, nil 93 case reflect.Interface: 94 return baseValue, nil 95 case reflect.Chan: 96 return baseValue, nil 97 case reflect.UnsafePointer: 98 return baseValue, nil 99 case reflect.Map: 100 var newPtrVal = reflect.MakeMap(baseValue.Type()) 101 var newValue = IndirectValue(newPtrVal) 102 if err := copyMap(&newValue, baseValue); err != nil { 103 return reflect.Value{}, err 104 } 105 if pointerType { 106 return newPtrVal, nil 107 } 108 return newValue, nil 109 case reflect.Struct: 110 var newPtrVal = reflect.New(valueType) 111 var newValue = IndirectValue(newPtrVal) 112 if err := copier.Copy(newPtrVal.Interface(), baseValue.Interface()); err != nil { 113 return reflect.Value{}, nerror.Wrap(err, "Failed to copy struct type %T", baseValue.Interface()) 114 } 115 if pointerType { 116 return newPtrVal, nil 117 } 118 return newValue, nil 119 case reflect.Array: 120 var newPtrVal = reflect.New(valueType) 121 var newValue = IndirectValue(newPtrVal) 122 var copied = reflect.Copy(newValue, baseValue) 123 if copied != baseValue.Len() { 124 return reflect.Value{}, nerror.New("copied has different length to original") 125 } 126 if pointerType { 127 return newPtrVal, nil 128 } 129 return newValue, nil 130 case reflect.Slice: 131 var newPtrVal = reflect.MakeSlice(valueType, baseValue.Len(), baseValue.Cap()) 132 var newValue = IndirectValue(newPtrVal) 133 var copied = reflect.Copy(newValue, baseValue) 134 if copied != baseValue.Len() { 135 return reflect.Value{}, nerror.New("copied has different length to original") 136 } 137 if pointerType { 138 return newPtrVal, nil 139 } 140 return newValue, nil 141 } 142 143 var newPtrValue = reflect.New(valueType) 144 if newPtrValue.CanSet() { 145 return reflect.Value{}, nerror.New("unable to set value for type %q", baseValue.Type()) 146 } 147 148 var newValue = IndirectValue(newPtrValue) 149 newValue.Set(baseValue) 150 if pointerType { 151 return newPtrValue, nil 152 } 153 return newValue, nil 154 } 155 156 func copyMap(dest *reflect.Value, src reflect.Value) error { 157 if dest.Kind() != reflect.Map && src.Kind() != reflect.Map { 158 return nerror.New("unable to copy in between map and another type") 159 } 160 161 var keys = src.MapKeys() 162 for _, key := range keys { 163 newKey, err := deepCopyValue(IndirectValue(key), key.Kind() == reflect.Ptr) 164 if err != nil { 165 return err 166 } 167 168 var mapValue = src.MapIndex(key) 169 newValue, err := deepCopyValue(IndirectValue(mapValue), mapValue.Kind() == reflect.Ptr) 170 if err != nil { 171 return err 172 } 173 dest.SetMapIndex(newKey, newValue) 174 } 175 return nil 176 } 177 178 // func IndirectValue returns the reflect.Value if the provided value is a pointer kind. 179 func IndirectValue(reflectValue reflect.Value) reflect.Value { 180 for reflectValue.Kind() == reflect.Ptr { 181 reflectValue = reflectValue.Elem() 182 } 183 return reflectValue 184 } 185 186 // func IndirectType returns the reflect.Type if the provided value is a pointer kind. 187 func IndirectType(reflectType reflect.Type) reflect.Type { 188 for reflectType.Kind() == reflect.Ptr || reflectType.Kind() == reflect.Slice { 189 reflectType = reflectType.Elem() 190 } 191 return reflectType 192 } 193 194 // ValueOf returns giving value of elem, if elem is a reflect.Type returns 195 // a new reflect.Value for giving type. 196 func ValueOf(elem interface{}) reflect.Value { 197 if telem, ok := elem.(reflect.Value); ok { 198 return telem 199 } 200 if telem, ok := elem.(reflect.Type); ok { 201 return reflect.New(telem) 202 } 203 return reflect.ValueOf(elem) 204 } 205 206 // TypeOf returns giving type of elem. 207 func TypeOf(elem interface{}) reflect.Type { 208 if telem, ok := elem.(reflect.Type); ok { 209 return telem 210 } 211 if telem, ok := elem.(reflect.Value); ok { 212 return telem.Type() 213 } 214 return reflect.TypeOf(elem) 215 } 216 217 // CopyStringMap returns a new copy of a giving string map. 218 func CopyStringMap(src map[string]string) map[string]string { 219 var dest = make(map[string]string, len(src)) 220 for key, value := range src { 221 dest[key] = value 222 } 223 return dest 224 } 225 226 // CopyStringKeyMap returns a new copy of a giving string keyed map. 227 func CopyStringKeyMap(src map[string]interface{}) (map[string]interface{}, error) { 228 var dest = make(map[string]interface{}, len(src)) 229 for key, value := range src { 230 var myValue, err = DeepCopy(value) 231 if err != nil { 232 return dest, err 233 } 234 dest[key] = myValue 235 } 236 return dest, nil 237 } 238 239 // CopyInterfaceKeyMap returns a new copy of a giving interface keyed map. 240 func CopyInterfaceKeyMap(src map[interface{}]interface{}) (map[interface{}]interface{}, error) { 241 var dest = make(map[interface{}]interface{}, len(src)) 242 for key, value := range src { 243 myValue, err := DeepCopy(value) 244 if err != nil { 245 return dest, err 246 } 247 myKey, err := DeepCopy(key) 248 if err != nil { 249 return dest, err 250 } 251 dest[myKey] = myValue 252 } 253 return dest, nil 254 } 255 256 // CopyBytes returns a new copy of giving byte slice. 257 func CopyBytes(bu []byte) []byte { 258 var cu = make([]byte, len(bu)) 259 copy(cu, bu) 260 return cu 261 } 262 263 //***************************************************** 264 // unsafe methods 265 //***************************************************** 266 267 // byte2String converts a byte slice into a string. 268 func bytes2String(bc []byte) string { 269 return *(*string)(unsafe.Pointer(&bc)) 270 } 271 272 // string2Bytes converts a string into a byte slice. 273 func string2Bytes(bc string) []byte { 274 return *(*[]byte)(unsafe.Pointer(&bc)) 275 }