-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcopy.go
58 lines (54 loc) · 1.27 KB
/
copy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package reflectricity
import (
"reflect"
)
func DeepCopy[T any](value T, private bool) T {
val := reflect.ValueOf(value)
if val.Kind() == reflect.Ptr && val.IsNil() {
return value
}
return deepCopy(val, private).Interface().(T)
}
func deepCopy(val reflect.Value, p bool) reflect.Value {
if val.Kind() == reflect.Ptr && val.IsNil() {
return val
}
val, depth := ptrUnwrap(val)
t := val.Type()
switch t.Kind() {
case reflect.Map:
s := reflect.MakeMap(t)
iter := val.MapRange()
for iter.Next() {
s.SetMapIndex(deepCopy(iter.Key(), p), deepCopy(iter.Value(), p))
}
val = s
case reflect.Chan:
val = reflect.MakeChan(t, val.Cap())
case reflect.Array, reflect.Slice:
s := reflect.MakeSlice(t, val.Len(), val.Len())
for i := 0; i < val.Len(); i++ {
s.Index(i).Set(deepCopy(val.Index(i), p))
}
val = s
case reflect.Struct:
s := reflect.New(t).Elem()
for i := 0; i < val.NumField(); i++ {
orig := val.Field(i)
dest := s.Field(i)
if orig.CanInterface() {
dest.Set(deepCopy(orig, p))
} else {
// Is this an unholy space?
if canExposeInterface() {
// Perform black magic
orig = exposePrivateValue(orig)
dest = exposePrivateValue(dest)
dest.Set(deepCopy(orig, p))
}
}
}
val = s
}
return ptrWrap(val, depth)
}