})
}
}
+
+func TestValuePointerAndUnsafePointer(t *testing.T) {
+ ptr := new(int)
+ ch := make(chan int)
+ m := make(map[int]int)
+ unsafePtr := unsafe.Pointer(ptr)
+ slice := make([]int, 1)
+ fn := func() {}
+ s := "foo"
+
+ tests := []struct {
+ name string
+ val Value
+ wantUnsafePointer unsafe.Pointer
+ }{
+ {"pointer", ValueOf(ptr), unsafe.Pointer(ptr)},
+ {"channel", ValueOf(ch), *(*unsafe.Pointer)(unsafe.Pointer(&ch))},
+ {"map", ValueOf(m), *(*unsafe.Pointer)(unsafe.Pointer(&m))},
+ {"unsafe.Pointer", ValueOf(unsafePtr), unsafePtr},
+ {"function", ValueOf(fn), **(**unsafe.Pointer)(unsafe.Pointer(&fn))},
+ {"slice", ValueOf(slice), unsafe.Pointer(unsafe.SliceData(slice))},
+ {"string", ValueOf(s), unsafe.Pointer(unsafe.StringData(s))},
+ }
+
+ for _, tc := range tests {
+ tc := tc
+ t.Run(tc.name, func(t *testing.T) {
+ if got := tc.val.Pointer(); got != uintptr(tc.wantUnsafePointer) {
+ t.Errorf("unexpected uintptr result, got %#x, want %#x", got, uintptr(tc.wantUnsafePointer))
+ }
+ if got := tc.val.UnsafePointer(); got != tc.wantUnsafePointer {
+ t.Errorf("unexpected unsafe.Pointer result, got %#x, want %#x", got, tc.wantUnsafePointer)
+ }
+ })
+ }
+}
// and make an exception.
// Pointer returns v's value as a uintptr.
-// It panics if v's Kind is not [Chan], [Func], [Map], [Pointer], [Slice], or [UnsafePointer].
+// It panics if v's Kind is not [Chan], [Func], [Map], [Pointer], [Slice], [String], or [UnsafePointer].
//
// If v's Kind is [Func], the returned pointer is an underlying
// code pointer, but not necessarily enough to identify a
// element of the slice. If the slice is nil the returned value
// is 0. If the slice is empty but non-nil the return value is non-zero.
//
+// If v's Kind is [String], the returned pointer is to the first
+// element of the underlying bytes of string.
+//
// It's preferred to use uintptr(Value.UnsafePointer()) to get the equivalent result.
func (v Value) Pointer() uintptr {
// The compiler loses track as it converts to uintptr. Force escape.
p = *(*unsafe.Pointer)(p)
}
return uintptr(p)
-
case Slice:
return uintptr((*unsafeheader.Slice)(v.ptr).Data)
+ case String:
+ return uintptr((*unsafeheader.String)(v.ptr).Data)
}
panic(&ValueError{"reflect.Value.Pointer", v.kind()})
}
// If v's Kind is [Slice], the returned pointer is to the first
// element of the slice. If the slice is nil the returned value
// is nil. If the slice is empty but non-nil the return value is non-nil.
+//
+// If v's Kind is [String], the returned pointer is to the first
+// element of the underlying bytes of string.
func (v Value) UnsafePointer() unsafe.Pointer {
k := v.kind()
switch k {
p = *(*unsafe.Pointer)(p)
}
return p
-
case Slice:
return (*unsafeheader.Slice)(v.ptr).Data
+ case String:
+ return (*unsafeheader.String)(v.ptr).Data
}
panic(&ValueError{"reflect.Value.UnsafePointer", v.kind()})
}