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