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  }