golang.design/x/reflect@v0.0.0-20220504060917-02c43be63f3b/deepcopy.go (about) 1 // Copyright 2022 The golang.design Initiative Authors. 2 // All rights reserved. Use of this source code is governed 3 // by a MIT license that can be found in the LICENSE file. 4 // 5 // Written by Changkun Ou <changkun.de> 6 7 // Package reflect implements the proposal https://go.dev/issue/51520. 8 // 9 // Warning: Not largely tested. Use it with care. 10 package reflect 11 12 import ( 13 "fmt" 14 "reflect" 15 "strings" 16 "unsafe" 17 ) 18 19 // DeepCopyOption represents an option to customize deep copied results. 20 type DeepCopyOption func(opt *copyConfig) 21 22 type copyConfig struct { 23 disallowCopyUnexported bool 24 disallowCopyCircular bool 25 disallowCopyBidirectionalChan bool 26 disallowCopyTypes []reflect.Type 27 } 28 29 // DisallowCopyUnexported returns a DeepCopyOption that disables the behavior 30 // of copying unexported fields. 31 func DisallowCopyUnexported() DeepCopyOption { 32 return func(opt *copyConfig) { 33 opt.disallowCopyUnexported = true 34 } 35 } 36 37 // DisallowCopyCircular returns a DeepCopyOption that disables the behavior 38 // of copying circular structures. 39 func DisallowCopyCircular() DeepCopyOption { 40 return func(opt *copyConfig) { 41 opt.disallowCopyCircular = true 42 } 43 } 44 45 // DisallowCopyBidirectionalChan returns a DeepCopyOption that disables 46 // the behavior of producing new channel when a bidirectional channel is copied. 47 func DisallowCopyBidirectionalChan() DeepCopyOption { 48 return func(opt *copyConfig) { 49 opt.disallowCopyBidirectionalChan = true 50 } 51 } 52 53 // DisallowTypes returns a DeepCopyOption that disallows copying any types 54 // that are in given values. 55 func DisallowTypes(val ...any) DeepCopyOption { 56 return func(opt *copyConfig) { 57 for i := range val { 58 opt.disallowCopyTypes = append(opt.disallowCopyTypes, reflect.TypeOf(val[i])) 59 } 60 } 61 } 62 63 // DeepCopy copies src to dst recursively. 64 // 65 // Two values of identical type are deeply copied if one of the following 66 // cases apply. 67 // 68 // Numbers, bools, strings are deeply copied and have different underlying 69 // memory address. 70 // 71 // Slice and Array values are deeply copied, including its elements. 72 // 73 // Map values are deeply copied for all of its key and corresponding 74 // values. 75 // 76 // Pointer values are deeply copied for their pointed value, and the 77 // pointer points to the deeply copied value. 78 // 79 // Struct values are deeply copied for all fields, including exported 80 // and unexported. 81 // 82 // Interface values are deeply copied if the underlying type can be 83 // deeply copied. 84 // 85 // There are a few exceptions that may result in a deeply copied value not 86 // deeply equal (asserted by DeepEqual(dst, src)) to the source value: 87 // 88 // 1) Func values are still refer to the same function 89 // 2) Chan values are replaced by newly created channels 90 // 3) One-way Chan values (receive or read-only) values are still refer 91 // to the same channel 92 // 93 // Note that while correct uses of DeepCopy do exist, they are not rare. 94 // The use of DeepCopy often indicates the copying object does not contain 95 // a singleton or is never meant to be copied, such as sync.Mutex, os.File, 96 // net.Conn, js.Value, etc. In these cases, the copied value retains the 97 // memory representations of the source value but may result in unexpected 98 // consequences in follow-up usage, the caller should clear these values 99 // depending on their usage context. 100 // 101 // To change these predefined behaviors, use provided DeepCopyOption. 102 func DeepCopy[T any](src T, opts ...DeepCopyOption) (dst T) { 103 ptrs := map[uintptr]any{} 104 conf := ©Config{} 105 for _, opt := range opts { 106 opt(conf) 107 } 108 109 ret := copyAny(src, ptrs, conf) 110 if v, ok := ret.(T); ok { 111 dst = v 112 return 113 } 114 panic(fmt.Sprintf("reflect: internal error: copied value is not typed in %T, got %T", src, ret)) 115 } 116 117 func copyAny(src any, ptrs map[uintptr]any, copyConf *copyConfig) (dst any) { 118 119 if len(copyConf.disallowCopyTypes) != 0 { 120 for i := range copyConf.disallowCopyTypes { 121 if reflect.TypeOf(src) == copyConf.disallowCopyTypes[i] { 122 panic(fmt.Sprintf("reflect: deep copying type %T is disallowed", src)) 123 } 124 } 125 } 126 127 v := reflect.ValueOf(src) 128 if !v.IsValid() { 129 return src 130 } 131 132 // Look up the corresponding copy function. 133 switch v.Kind() { 134 case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, 135 reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, 136 reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, 137 reflect.Complex64, reflect.Complex128, reflect.Func: 138 dst = copyPremitive(src, ptrs, copyConf) 139 case reflect.String: 140 dst = strings.Clone(src.(string)) 141 case reflect.Slice: 142 dst = copySlice(src, ptrs, copyConf) 143 case reflect.Array: 144 dst = copyArray(src, ptrs, copyConf) 145 case reflect.Map: 146 dst = copyMap(src, ptrs, copyConf) 147 case reflect.Ptr, reflect.UnsafePointer: 148 dst = copyPointer(src, ptrs, copyConf) 149 case reflect.Struct: 150 dst = copyStruct(src, ptrs, copyConf) 151 case reflect.Interface: 152 dst = copyAny(src, ptrs, copyConf) 153 case reflect.Chan: 154 dst = copyChan(src, ptrs, copyConf) 155 default: 156 panic(fmt.Sprintf("reflect: internal error: unknown type %v", v.Kind())) 157 } 158 return 159 } 160 161 func copyPremitive(src any, ptr map[uintptr]any, copyConf *copyConfig) (dst any) { 162 kind := reflect.ValueOf(src).Kind() 163 switch kind { 164 case reflect.Array, reflect.Chan, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.Struct, reflect.UnsafePointer: 165 panic(fmt.Sprintf("reflect: internal error: type %v is not a primitive", kind)) 166 } 167 dst = src 168 return 169 } 170 171 func copySlice(x any, ptrs map[uintptr]any, copyConf *copyConfig) any { 172 v := reflect.ValueOf(x) 173 kind := v.Kind() 174 if kind != reflect.Slice { 175 panic(fmt.Sprintf("reflect: internal error: type %v is not a slice", kind)) 176 } 177 178 size := v.Len() 179 t := reflect.TypeOf(x) 180 dc := reflect.MakeSlice(t, size, size) 181 for i := 0; i < size; i++ { 182 iv := reflect.ValueOf(copyAny(v.Index(i).Interface(), ptrs, copyConf)) 183 if iv.IsValid() { 184 dc.Index(i).Set(iv) 185 } 186 } 187 return dc.Interface() 188 } 189 190 func copyArray(x any, ptrs map[uintptr]any, copyConf *copyConfig) any { 191 v := reflect.ValueOf(x) 192 if v.Kind() != reflect.Array { 193 panic(fmt.Errorf("reflect: internal error: must be an Array; got %v", v.Kind())) 194 } 195 t := reflect.TypeOf(x) 196 size := t.Len() 197 dc := reflect.New(reflect.ArrayOf(size, t.Elem())).Elem() 198 for i := 0; i < size; i++ { 199 item := copyAny(v.Index(i).Interface(), ptrs, copyConf) 200 dc.Index(i).Set(reflect.ValueOf(item)) 201 } 202 return dc.Interface() 203 } 204 205 func copyMap(x any, ptrs map[uintptr]any, copyConf *copyConfig) any { 206 v := reflect.ValueOf(x) 207 if v.Kind() != reflect.Map { 208 panic(fmt.Errorf("reflect: internal error: must be a Map; got %v", v.Kind())) 209 } 210 t := reflect.TypeOf(x) 211 dc := reflect.MakeMapWithSize(t, v.Len()) 212 iter := v.MapRange() 213 for iter.Next() { 214 item := copyAny(iter.Value().Interface(), ptrs, copyConf) 215 k := copyAny(iter.Key().Interface(), ptrs, copyConf) 216 dc.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(item)) 217 } 218 return dc.Interface() 219 } 220 221 func copyPointer(x any, ptrs map[uintptr]any, copyConf *copyConfig) any { 222 v := reflect.ValueOf(x) 223 if v.Kind() != reflect.Pointer { 224 panic(fmt.Errorf("reflect: internal error: must be a Pointer or Ptr; got %v", v.Kind())) 225 } 226 addr := uintptr(v.UnsafePointer()) 227 if dc, ok := ptrs[addr]; ok { 228 if copyConf.disallowCopyCircular { 229 panic("reflect: deep copy dircular value is disallowed") 230 } 231 return dc 232 } 233 t := reflect.TypeOf(x) 234 dc := reflect.New(t.Elem()) 235 ptrs[addr] = dc.Interface() 236 if !v.IsNil() { 237 item := copyAny(v.Elem().Interface(), ptrs, copyConf) 238 iv := reflect.ValueOf(item) 239 if iv.IsValid() { 240 dc.Elem().Set(reflect.ValueOf(item)) 241 } 242 } 243 return dc.Interface() 244 } 245 246 func copyStruct(x any, ptrs map[uintptr]any, copyConf *copyConfig) any { 247 v := reflect.ValueOf(x) 248 if v.Kind() != reflect.Struct { 249 panic(fmt.Errorf("reflect: internal error: must be a Struct; got %v", v.Kind())) 250 } 251 t := reflect.TypeOf(x) 252 dc := reflect.New(t) 253 for i := 0; i < t.NumField(); i++ { 254 if copyConf.disallowCopyUnexported { 255 f := t.Field(i) 256 if f.PkgPath != "" { 257 continue 258 } 259 item := copyAny(v.Field(i).Interface(), ptrs, copyConf) 260 dc.Elem().Field(i).Set(reflect.ValueOf(item)) 261 } else { 262 item := copyAny(valueInterfaceUnsafe(v.Field(i)), ptrs, copyConf) 263 setField(dc.Elem().Field(i), reflect.ValueOf(item)) 264 } 265 } 266 return dc.Elem().Interface() 267 } 268 269 func copyChan(x any, ptrs map[uintptr]any, copyConf *copyConfig) any { 270 v := reflect.ValueOf(x) 271 if v.Kind() != reflect.Chan { 272 panic(fmt.Errorf("reflect: internal error: must be a Chan; got %v", v.Kind())) 273 } 274 t := reflect.TypeOf(x) 275 dir := t.ChanDir() 276 var dc any 277 switch dir { 278 case reflect.BothDir: 279 if !copyConf.disallowCopyBidirectionalChan { 280 dc = reflect.MakeChan(t, v.Cap()).Interface() 281 } 282 fallthrough 283 case reflect.SendDir, reflect.RecvDir: 284 dc = x 285 } 286 return dc 287 } 288 289 // valueInterfaceUnsafe overpasses the reflect package check regarding 290 // unexported methods. 291 func valueInterfaceUnsafe(v reflect.Value) any { 292 return reflect_valueInterface(v, false) 293 } 294 295 // setField sets the given value to the field value, regardless whether 296 // the filed is exported or not. 297 func setField(field reflect.Value, value reflect.Value) { 298 reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Set(value) 299 } 300 301 //go:linkname reflect_valueInterface reflect.valueInterface 302 func reflect_valueInterface(v reflect.Value, safe bool) any