github.com/wfusion/gofusion@v1.1.14/common/utils/clone/api_go118.go (about) 1 //go:build go1.18 2 // +build go1.18 3 4 package clone 5 6 import ( 7 "reflect" 8 "unsafe" 9 ) 10 11 // Clone recursively deep clone v to a new value in heap. 12 // It assumes that there is no pointer cycle in v, 13 // e.g. v has a pointer points to v itself. 14 // If there is a pointer cycle, use Slowly instead. 15 // 16 // Clone allocates memory and deeply copies values inside v in depth-first sequence. 17 // There are a few special rules for following types. 18 // 19 // - Scalar types: all number-like types are copied by value. 20 // - func: Copied by value as func is an opaque pointer at runtime. 21 // - string: Copied by value as string is immutable by design. 22 // - unsafe.Pointer: Copied by value as we don't know what's in it. 23 // - chan: A new empty chan is created as we cannot read data inside the old chan. 24 // 25 // Unlike many other packages, Clone is able to clone unexported fields of any struct. 26 // Use this feature wisely. 27 func Clone[T any](t T) T { 28 return cloner.Clone(t).(T) 29 } 30 31 // Slowly recursively deep clone v to a new value in heap. 32 // It marks all cloned values internally, thus it can clone v with cycle pointer. 33 // 34 // Slowly works exactly the same as Clone. See Clone doc for more details. 35 func Slowly[T any](t T) T { 36 return cloner.CloneSlowly(t).(T) 37 } 38 39 // Wrap creates a wrapper of v, which must be a pointer. 40 // If v is not a pointer, Wrap simply returns v and do nothing. 41 // 42 // The wrapper is a deep clone of v's value. It holds a shadow copy to v internally. 43 // 44 // t := &T{Foo: 123} 45 // v := Wrap(t).(*T) // v is a clone of t. 46 // reflect.DeepEqual(t, v) == true // v equals t. 47 // v.Foo = 456 // v.Foo is changed, but t.Foo doesn't change. 48 // orig := Unwrap(v) // Use `Unwrap` to discard wrapper and return original value, which is t. 49 // orig.(*T) == t // orig and t is exactly the same. 50 // Undo(v) // Use `Undo` to discard any change on v. 51 // v.Foo == t.Foo // Now, the value of v and t are the same again. 52 func Wrap[T any](t T) T { 53 return wrap(t).(T) 54 } 55 56 // Unwrap returns v's original value if v is a wrapped value. 57 // Otherwise, simply returns v itself. 58 func Unwrap[T any](t T) T { 59 return unwrap(t).(T) 60 } 61 62 // Undo discards any change made in wrapped value. 63 // If v is not a wrapped value, nothing happens. 64 func Undo[T any](t T) { 65 undo(t) 66 } 67 68 // MarkAsOpaquePointer marks t as an opaque pointer in heap allocator, 69 // so that all clone methods will copy t by value. 70 // If t is not a pointer, MarkAsOpaquePointer ignores t. 71 // 72 // Here is a list of types marked as opaque pointers by default: 73 // - `elliptic.Curve`, which is `*elliptic.CurveParam` or `elliptic.p256Curve`; 74 // - `reflect.Type`, which is `*reflect.rtype` defined in `runtime`. 75 func MarkAsOpaquePointer(t reflect.Type) { 76 markAsOpaquePointer(t) 77 } 78 79 // MarkAsScalar marks t as a scalar type in heap allocator, 80 // so that all clone methods will copy t by value. 81 // If t is not struct or pointer to struct, MarkAsScalar ignores t. 82 // 83 // In the most cases, it's not necessary to call it explicitly. 84 // If a struct type contains scalar type fields only, the struct will be marked as scalar automatically. 85 // 86 // Here is a list of types marked as scalar by default: 87 // - time.Time 88 // - reflect.Value 89 func MarkAsScalar(t reflect.Type) { 90 markAsScalar(t) 91 } 92 93 // SetCustomFunc sets a custom clone function for type t in heap allocator. 94 // If t is not struct or pointer to struct, SetCustomFunc ignores t. 95 // 96 // If fn is nil, remove the custom clone function for type t. 97 func SetCustomFunc(t reflect.Type, fn Func) { 98 setCustomFunc(t, fn) 99 } 100 101 // FromHeap creates an allocator which allocate memory from heap. 102 func FromHeap() *Allocator { 103 return fromHeap() 104 } 105 106 // NewAllocator creates an allocator which allocate memory from the pool. 107 // Both pool and methods are optional. 108 // 109 // If methods.New is not nil, the allocator itself is created by calling methods.New. 110 // 111 // The pool is a pointer to the memory pool which is opaque to the allocator. 112 // It's methods' responsibility to allocate memory from the pool properly. 113 func NewAllocator(pool unsafe.Pointer, methods *AllocatorMethods) (allocator *Allocator) { 114 return newAllocator(pool, methods) 115 }