| // Copyright IBM Corp. 2014, 2026 | |
| // SPDX-License-Identifier: BUSL-1.1 | |
| package copy | |
| import ( | |
| "reflect" | |
| ) | |
| // DeepCopyValue produces a deep copy of the given value, where the result | |
| // ideally shares no mutable memory with the given value. | |
| // | |
| // There are some limitations on what's possible, however: | |
| // - This package can't write into an unexported field of a struct, so those | |
| // will be ignored entirely and thus left as their zero values in the | |
| // result. | |
| // - If the given structure contains function pointers then their closures | |
| // might refer to shared memory that this function cannot copy. If they | |
| // refer to memory that's also included in the data structure outside of | |
| // the function pointer then the two will be disconnected in the result. | |
| // - It isn't really meaningful to "copy" a channel since it's a | |
| // synchronization primitive rather than a data structure, so the result | |
| // will share the same channels as the input. | |
| // - Copying other library-based synchronization primitives like [sync.Mutex] | |
| // doesn't really make sense either, although this function doesn't | |
| // understand what they are and so the result is undefined. If your | |
| // synchronization primitive has a "ready to use" zero value then it _might_ | |
| // be acceptable to store it in an unexported field and thus have it be | |
| // zeroed in the result, but at that point you're probably better off | |
| // writing a specialized deepcopy function so that you can actually use | |
| // the synchronization primitive to prevent data races during copying. | |
| // - The uintptr and [unsafe.Pointer] types might well refer to some shared | |
| // memory, but don't give any information about how to copy that memory | |
| // and so those are just preserved verbatim, making the result point to | |
| // the same memory as the input. | |
| // - Broadly, this function needs special handling for each different kind | |
| // of value in Go, and so if a later version of Go has introduced a new kind | |
| // of value then this function might not support it yet. That might cause | |
| // this function to panic, or to ignore part of the structure, or otherwise | |
| // misbehave. | |
| // | |
| // This is intended as a relatively simple utility for straightforward cases, | |
| // primarily for use in contrived situations like unit tests. | |
| // | |
| // It intentionally does not offer any customization; if you need to do | |
| // something special then it's better to just write your own simple direct code | |
| // than to pull in all of this reflection trickery. Even if you don't need to do | |
| // something special it's probably still better to just write some | |
| // straightforward code that directly describes the behavior you're intending, | |
| // so that the Go compiler can help you and so you don't force future | |
| // maintainers to understand all of this metaprogramming if something goes | |
| // wrong. Seriously... don't use this function. | |
| func DeepCopyValue[T any](v T) T { | |
| // We use type parameters in the signature to make usage more convenient | |
| // for the caller (no type assertions required) but we actually do all | |
| // our internal work in the realm of package reflect. | |
| input := reflect.ValueOf(&v).Elem() // if T is an interface type then input is the interface value, not the value inside it | |
| ty := reflect.TypeFor[T]() // likewise, if T is interface type then this is the static interface type, not the dynamic type | |
| result := deepCopyValue(input, ty) | |
| return result.Interface().(T) | |
| } | |
| func deepCopyValue(v reflect.Value, ty reflect.Type) reflect.Value { | |
| switch ty.Kind() { | |
| // A large subset of the kinds don't point to mutable sharable memory, | |
| // or don't refer to something we can possibly copy, and so we can just | |
| // return them directly without any extra work. | |
| case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String, reflect.UnsafePointer, reflect.Func, reflect.Chan: | |
| return v | |
| case reflect.Array: | |
| return deepCopyArray(v, ty) | |
| case reflect.Interface: | |
| return deepCopyInterface(v, ty) | |
| case reflect.Map: | |
| return deepCopyMap(v, ty) | |
| case reflect.Pointer: | |
| return deepCopyPointer(v, ty) | |
| case reflect.Slice: | |
| return deepCopySlice(v, ty) | |
| case reflect.Struct: | |
| return deepCopyStruct(v, ty) | |
| default: | |
| panic("unsupported type kind " + ty.Kind().String()) | |
| } | |
| } | |
| func deepCopyArray(v reflect.Value, ty reflect.Type) reflect.Value { | |
| // Copying an array really means allocating a new array and then | |
| // copying each of the elements from the source. | |
| ret := reflect.New(ty).Elem() | |
| for i := range ret.Len() { | |
| newElemV := deepCopyValue(v.Index(i), ty.Elem()) | |
| ret.Index(i).Set(newElemV) | |
| } | |
| return ret | |
| } | |
| func deepCopyInterface(v reflect.Value, ty reflect.Type) reflect.Value { | |
| if v.IsNil() { | |
| return v | |
| } | |
| // An interface value is not directly mutable itself, but the value | |
| // inside it might be and so we'll copy that and then wrap the result | |
| // in a new interface value of the same type. | |
| ret := reflect.New(ty).Elem() | |
| dynV := deepCopyValue(v.Elem(), v.Elem().Type()) | |
| ret.Set(dynV) | |
| return ret | |
| } | |
| func deepCopyMap(v reflect.Value, ty reflect.Type) reflect.Value { | |
| if v.IsNil() { | |
| return v | |
| } | |
| ret := reflect.MakeMap(ty) | |
| for iter := v.MapRange(); iter.Next(); { | |
| // We don't copy the key because Go does not allow any mutably-aliasable | |
| // types as map keys. (That would make it very easy to corrupt the | |
| // internals of the map, after all!) | |
| k := iter.Key() | |
| v := deepCopyValue(iter.Value(), ty.Elem()) | |
| ret.SetMapIndex(k, v) | |
| } | |
| return ret | |
| } | |
| func deepCopyPointer(v reflect.Value, ty reflect.Type) reflect.Value { | |
| if v.IsNil() { | |
| return v | |
| } | |
| // We copy a pointer by copying what it refers to and then returning | |
| // a pointer to that copy. | |
| newTarget := deepCopyValue(v.Elem(), ty.Elem()) | |
| return newTarget.Addr() | |
| } | |
| func deepCopySlice(v reflect.Value, ty reflect.Type) reflect.Value { | |
| if v.IsNil() { | |
| return v | |
| } | |
| // Copying a slice really means copying the part of its backing array | |
| // that in could potentially observe. In particular, it's possible to | |
| // expand the view of the backing array up to the slice's capacity, | |
| // so we need to copy the entire capacity even if the length is | |
| // currently shorter to ensure that the result is truly equivalent. | |
| length := v.Len() | |
| capacity := v.Cap() | |
| // This exposes any elements that are between length and capacity. | |
| fullView := v.Slice3(0, capacity, capacity) | |
| // Making a slice also allocates a new backing array for it. | |
| ret := reflect.MakeSlice(ty, capacity, capacity) | |
| for i := range capacity { | |
| ret.Index(i).Set(fullView.Index(i)) | |
| } | |
| // We must restore the original length before we return. | |
| return ret.Slice(0, length) | |
| } | |
| func deepCopyStruct(v reflect.Value, ty reflect.Type) reflect.Value { | |
| // To copy a struct we must copy each exported field one by one. | |
| // We can't assign to unexported fields and so we just leave those | |
| // unset in the new value. | |
| ret := reflect.New(ty).Elem() | |
| for i := range ty.NumField() { | |
| fieldRet := ret.Field(i) | |
| if !fieldRet.CanSet() { | |
| // Presumably it's an unexported field, so we can't do anything | |
| // with it and must leave it zeroed. | |
| continue | |
| } | |
| newVal := deepCopyValue(v.Field(i), ty.Field(i).Type) | |
| fieldRet.Set(newVal) | |
| } | |
| return ret | |
| } |