github.com/wfusion/gofusion@v1.1.14/common/utils/clone/structtype.go (about) 1 // Copyright 2019 Huan Du. All rights reserved. 2 // Licensed under the MIT license that can be found in the LICENSE file. 3 4 package clone 5 6 import ( 7 "crypto/elliptic" 8 "fmt" 9 "reflect" 10 "sync" 11 "sync/atomic" 12 "time" 13 "unsafe" 14 ) 15 16 type structType struct { 17 PointerFields []structFieldType 18 fn Func 19 } 20 21 type structFieldType struct { 22 Offset uintptr // The offset from the beginning of the struct. 23 Index int // The index of the field. 24 } 25 26 var zeroStructType = structType{} 27 28 func init() { 29 // Some well-known scalar-like structs. 30 MarkAsScalar(reflect.TypeOf(time.Time{})) 31 MarkAsScalar(reflect.TypeOf(reflect.Value{})) 32 33 // Special case for elliptic.Curve which is used by TLS ECC certificate. 34 // Package crypto/tls uses elliptic.Curve as enum values 35 // so that they should be treated as opaque pointers. 36 // 37 // As elliptic.Curve is an interface, it can be *elliptic.CurveParam or elliptic.p256Curve. 38 MarkAsOpaquePointer(reflect.TypeOf(&elliptic.CurveParams{})) 39 curves := []elliptic.Curve{ 40 elliptic.P224(), 41 elliptic.P256(), 42 elliptic.P384(), 43 elliptic.P521(), 44 } 45 46 for _, curve := range curves { 47 MarkAsOpaquePointer(reflect.ValueOf(curve).Type()) 48 } 49 50 // Special case for reflect.Type (actually *reflect.rtype): 51 // The *reflect.rtype should not be copied as it is immutable and 52 // may point to a variable that actual type is not reflect.rtype, 53 // e.g. *reflect.arrayType or *reflect.chanType. 54 MarkAsOpaquePointer(reflect.TypeOf(reflect.TypeOf(0))) 55 56 // Some well-known no-copy structs. 57 // 58 // Almost all structs defined in package "sync" and "go.uber.org/atomic" are set 59 // except `sync.Once` which can be safely cloned with a correct done value. 60 SetCustomFunc(reflect.TypeOf(sync.Mutex{}), emptyCloneFunc) 61 SetCustomFunc(reflect.TypeOf(sync.RWMutex{}), emptyCloneFunc) 62 SetCustomFunc(reflect.TypeOf(sync.WaitGroup{}), emptyCloneFunc) 63 SetCustomFunc(reflect.TypeOf(sync.Cond{}), func(allocator *Allocator, old, new reflect.Value) { 64 // Copy the New func from old value. 65 oldL := old.FieldByName("L") 66 newL := allocator.Clone(oldL) 67 new.FieldByName("L").Set(newL) 68 }) 69 SetCustomFunc(reflect.TypeOf(sync.Pool{}), func(allocator *Allocator, old, new reflect.Value) { 70 // Copy the New func from old value. 71 oldFn := old.FieldByName("New") 72 newFn := allocator.Clone(oldFn) 73 new.FieldByName("New").Set(newFn) 74 }) 75 SetCustomFunc(reflect.TypeOf(sync.Map{}), func(allocator *Allocator, old, new reflect.Value) { 76 if !old.CanAddr() { 77 return 78 } 79 80 // Clone all values inside sync.Map. 81 oldMap := old.Addr().Interface().(*sync.Map) 82 newMap := new.Addr().Interface().(*sync.Map) 83 oldMap.Range(func(key, value interface{}) bool { 84 k := clone(allocator, key) 85 v := clone(allocator, value) 86 newMap.Store(k, v) 87 return true 88 }) 89 }) 90 SetCustomFunc(reflect.TypeOf(atomic.Value{}), func(allocator *Allocator, old, new reflect.Value) { 91 if !old.CanAddr() { 92 return 93 } 94 95 // Clone value inside atomic.Value. 96 oldValue := old.Addr().Interface().(*atomic.Value) 97 newValue := new.Addr().Interface().(*atomic.Value) 98 v := oldValue.Load() 99 cloned := clone(allocator, v) 100 newValue.Store(cloned) 101 }) 102 } 103 104 // MarkAsScalar marks t as a scalar type in heap allocator, 105 // so that all clone methods will copy t by value. 106 // If t is not struct or pointer to struct, MarkAsScalar ignores t. 107 // 108 // In the most cases, it's not necessary to call it explicitly. 109 // If a struct type contains scalar type fields only, the struct will be marked as scalar automatically. 110 // 111 // Here is a list of types marked as scalar by default: 112 // - time.Time 113 // - reflect.Value 114 func markAsScalar(t reflect.Type) { 115 defaultAllocator.MarkAsScalar(t) 116 } 117 118 // MarkAsOpaquePointer marks t as an opaque pointer in heap allocator, 119 // so that all clone methods will copy t by value. 120 // If t is not a pointer, MarkAsOpaquePointer ignores t. 121 // 122 // Here is a list of types marked as opaque pointers by default: 123 // - `elliptic.Curve`, which is `*elliptic.CurveParam` or `elliptic.p256Curve`; 124 // - `reflect.Type`, which is `*reflect.rtype` defined in `runtime`. 125 func markAsOpaquePointer(t reflect.Type) { 126 defaultAllocator.MarkAsOpaquePointer(t) 127 } 128 129 // Func is a custom func to clone value from old to new. 130 // The new is a zero value 131 // which `new.CanSet()` and `new.CanAddr()` is guaranteed to be true. 132 // 133 // Func must update the new to return result. 134 type Func func(allocator *Allocator, old, new reflect.Value) 135 136 // emptyCloneFunc is used to disable shadow copy. 137 // It's useful when cloning sync.Mutex as cloned value must be a zero value. 138 func emptyCloneFunc(allocator *Allocator, old, new reflect.Value) {} 139 140 // SetCustomFunc sets a custom clone function for type t in heap allocator. 141 // If t is not struct or pointer to struct, SetCustomFunc ignores t. 142 // 143 // If fn is nil, remove the custom clone function for type t. 144 func setCustomFunc(t reflect.Type, fn Func) { 145 defaultAllocator.SetCustomFunc(t, fn) 146 } 147 148 // Init creates a new value of src.Type() and shadow copies all content from src. 149 // If noCustomFunc is set to true, custom clone function will be ignored. 150 // 151 // Init returns true if the value is cloned by a custom func. 152 // Caller should skip cloning struct fields in depth. 153 func (st *structType) Init(allocator *Allocator, src, nv reflect.Value, noCustomFunc bool) (done bool) { 154 dst := nv.Elem() 155 156 if !noCustomFunc && st.fn != nil { 157 if !src.CanInterface() { 158 src = forceClearROFlag(src) 159 } 160 161 st.fn(allocator, src, dst) 162 done = true 163 return 164 } 165 166 ptr := unsafe.Pointer(nv.Pointer()) 167 shadowCopy(src, ptr) 168 done = len(st.PointerFields) == 0 169 return 170 } 171 172 func (st *structType) CanShadowCopy() bool { 173 return len(st.PointerFields) == 0 && st.fn == nil 174 } 175 176 // IsScalar returns true if k should be considered as a scalar type. 177 // 178 // For the sake of performance, string is considered as a scalar type unless arena is enabled. 179 // If we need to deep copy string value in some cases, we can create a new allocator with custom isScalar function 180 // in which we can return false when k is reflect.String. 181 // 182 // // Create a new allocator which treats string as non-scalar type. 183 // allocator := NewAllocator(nil, &AllocatorMethods{ 184 // IsScalar: func(k reflect.Kind) bool { 185 // return k != reflect.String && IsScalar(k) 186 // }, 187 // }) 188 func IsScalar(k reflect.Kind) bool { 189 switch k { 190 case reflect.Bool, 191 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 192 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, 193 reflect.Float32, reflect.Float64, 194 reflect.Complex64, reflect.Complex128, 195 reflect.Func, 196 reflect.UnsafePointer, 197 reflect.Invalid: 198 return true 199 200 case reflect.String: 201 // If arena is not enabled, string can be copied as scalar safely 202 // as it's immutable by design. 203 return !arenaIsEnabled 204 } 205 206 return false 207 } 208 209 func copyScalarValue(src reflect.Value) reflect.Value { 210 if src.CanInterface() { 211 return src 212 } 213 214 // src is an unexported field value. Copy its value. 215 switch src.Kind() { 216 case reflect.Bool: 217 return reflect.ValueOf(src.Bool()) 218 219 case reflect.Int: 220 return reflect.ValueOf(int(src.Int())) 221 case reflect.Int8: 222 return reflect.ValueOf(int8(src.Int())) 223 case reflect.Int16: 224 return reflect.ValueOf(int16(src.Int())) 225 case reflect.Int32: 226 return reflect.ValueOf(int32(src.Int())) 227 case reflect.Int64: 228 return reflect.ValueOf(src.Int()) 229 230 case reflect.Uint: 231 return reflect.ValueOf(uint(src.Uint())) 232 case reflect.Uint8: 233 return reflect.ValueOf(uint8(src.Uint())) 234 case reflect.Uint16: 235 return reflect.ValueOf(uint16(src.Uint())) 236 case reflect.Uint32: 237 return reflect.ValueOf(uint32(src.Uint())) 238 case reflect.Uint64: 239 return reflect.ValueOf(src.Uint()) 240 case reflect.Uintptr: 241 return reflect.ValueOf(uintptr(src.Uint())) 242 243 case reflect.Float32: 244 return reflect.ValueOf(float32(src.Float())) 245 case reflect.Float64: 246 return reflect.ValueOf(src.Float()) 247 248 case reflect.Complex64: 249 return reflect.ValueOf(complex64(src.Complex())) 250 case reflect.Complex128: 251 return reflect.ValueOf(src.Complex()) 252 253 case reflect.String: 254 return reflect.ValueOf(src.String()) 255 case reflect.Func: 256 t := src.Type() 257 258 if src.IsNil() { 259 return reflect.Zero(t) 260 } 261 262 // Don't use this trick unless we have no choice. 263 return forceClearROFlag(src) 264 case reflect.UnsafePointer: 265 return reflect.ValueOf(unsafe.Pointer(src.Pointer())) 266 } 267 268 panic(fmt.Errorf("go-clone: <bug> impossible type `%v` when cloning private field", src.Type())) 269 } 270 271 var typeOfInterface = reflect.TypeOf((*interface{})(nil)).Elem() 272 273 // forceClearROFlag clears all RO flags in v to make v accessible. 274 // It's a hack based on the fact that InterfaceData is always available on RO data. 275 // This hack can be broken in any Go version. 276 // Don't use it unless we have no choice, e.g. copying func in some edge cases. 277 func forceClearROFlag(v reflect.Value) reflect.Value { 278 var i interface{} 279 indirect := 0 280 281 // Save flagAddr. 282 for v.CanAddr() { 283 v = v.Addr() 284 indirect++ 285 } 286 287 v = v.Convert(typeOfInterface) 288 nv := reflect.ValueOf(&i) 289 *(*interfaceData)(unsafe.Pointer(nv.Pointer())) = parseReflectValue(v) 290 cleared := nv.Elem().Elem() 291 292 for indirect > 0 { 293 cleared = cleared.Elem() 294 indirect-- 295 } 296 297 return cleared 298 }