github.com/wfusion/gofusion@v1.1.14/common/utils/clone/interfacedata.go (about) 1 package clone 2 3 import ( 4 "reflect" 5 "unsafe" 6 ) 7 8 const sizeOfPointers = unsafe.Sizeof((interface{})(0)) / unsafe.Sizeof(uintptr(0)) 9 10 // interfaceData is the underlying data of an interface. 11 // As the reflect.Value's interfaceData method is deprecated, 12 // it may be broken in any Go release. 13 // It's better to create a custom to hold the data. 14 // 15 // The type of interfaceData fields must be poniters. 16 // It's a way to cheat Go compile to generate calls to write barrier 17 // when copying interfaces. 18 type interfaceData struct { 19 _ [sizeOfPointers]unsafe.Pointer 20 } 21 22 var reflectValuePtrOffset uintptr 23 24 func init() { 25 t := reflect.TypeOf(reflect.Value{}) 26 found := false 27 fields := t.NumField() 28 29 for i := 0; i < fields; i++ { 30 field := t.Field(i) 31 32 if field.Type.Kind() == reflect.UnsafePointer { 33 found = true 34 reflectValuePtrOffset = field.Offset 35 break 36 } 37 } 38 39 if !found { 40 panic("go-clone: fail to find internal ptr field in reflect.Value") 41 } 42 } 43 44 // parseReflectValue returns the underlying interface data in a reflect value. 45 // It assumes that v is an interface value. 46 func parseReflectValue(v reflect.Value) interfaceData { 47 pv := (unsafe.Pointer)(uintptr(unsafe.Pointer(&v)) + reflectValuePtrOffset) 48 ptr := *(*unsafe.Pointer)(pv) 49 return *(*interfaceData)(ptr) 50 }