blob: ec9f0838786fbb90538415137d08583af69d45b0 [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This package defines a reflect.Value-like interface that uses unsafe.Pointers
// to reduce the amount of work for each operation, as compared with the
// reflect package.
// This is possible because the Marshaler is built for a specific type and
// therefore the type and structure is known in advance and checks normally
// performed by the reflect package are redundant.
// ASSUMPTIONS:
// - Go's interface implementation is two pointers, type followed by value.
// - reflect.Type is an interface with the runtime type as the concrete
// implementation.
package unsafevalue
import (
"reflect"
"unsafe"
)
// A pointer to a go value.
type Value struct{ data unsafe.Pointer }
// Construct a Value from an interface.
// ValueOf(&x) is identical to ValueOf(x), except the latter will make a
// copy of x (when putting it into the interface).
func ValueOf(i interface{}) Value {
return Value{extractInterface(i).data}
}
func (v Value) UnsafeAddr() uintptr {
return uintptr(v.data)
}
func (v Value) Bool() bool {
return *(*bool)(v.data)
}
func (v Value) Int8() int8 {
return *(*int8)(v.data)
}
func (v Value) Int16() int16 {
return *(*int16)(v.data)
}
func (v Value) Int32() int32 {
return *(*int32)(v.data)
}
func (v Value) Int64() int64 {
return *(*int64)(v.data)
}
func (v Value) Uint8() uint8 {
return *(*uint8)(v.data)
}
func (v Value) Uint16() uint16 {
return *(*uint16)(v.data)
}
func (v Value) Uint32() uint32 {
return *(*uint32)(v.data)
}
func (v Value) Uint64() uint64 {
return *(*uint64)(v.data)
}
func (v Value) Float32() float32 {
return *(*float32)(v.data)
}
func (v Value) Float64() float64 {
return *(*float64)(v.data)
}
func (v Value) String() string {
return *(*string)(v.data)
}
func (v Value) Bytes() []byte {
return *(*[]byte)(v.data)
}
func (v Value) Interface() interface{} {
return *(*interface{})(v.data)
}
func (v Value) SetBool(b bool) {
*(*bool)(v.data) = b
}
func (v Value) SetInt8(i int8) {
*(*int8)(v.data) = i
}
func (v Value) SetInt16(i int16) {
*(*int16)(v.data) = i
}
func (v Value) SetInt32(i int32) {
*(*int32)(v.data) = i
}
func (v Value) SetInt64(i int64) {
*(*int64)(v.data) = i
}
func (v Value) SetUint8(i uint8) {
*(*uint8)(v.data) = i
}
func (v Value) SetUint16(i uint16) {
*(*uint16)(v.data) = i
}
func (v Value) SetUint32(i uint32) {
*(*uint32)(v.data) = i
}
func (v Value) SetUint64(i uint64) {
*(*uint64)(v.data) = i
}
func (v Value) SetFloat32(i float32) {
*(*float32)(v.data) = i
}
func (v Value) SetFloat64(i float64) {
*(*float64)(v.data) = i
}
func (v Value) SetString(s string) {
*(*string)(v.data) = s
}
func (v Value) SetBytes(b []byte) {
*(*[]byte)(v.data) = b
}
func (v Value) SetInterface(s interface{}) {
*(*interface{})(v.data) = s
}
func (v Value) SliceLen() int {
return (*reflect.SliceHeader)(v.data).Len
}
func (v Value) SliceCap() int {
return (*reflect.SliceHeader)(v.data).Cap
}
func (v Value) SliceIndex(elemSize uintptr, index int) Value {
return Value{unsafe.Pointer(uintptr((*reflect.SliceHeader)(v.data).Data) + uintptr(index)*elemSize)}
}
// Analogous to rv.Set(reflect.MakeSlice(elemType, len, cap)).
func (v Value) SliceSetMakeSlice(elemType reflect.Type, len, cap int) {
sh := (*reflect.SliceHeader)(v.data)
sh.Len = len
sh.Cap = cap
sh.Data = uintptr(unsafe_NewArray(runtimeTypeFromReflectType(elemType), cap))
}
func (v Value) ArrayIndex(elemSize uintptr, index int) Value {
return Value{unsafe.Pointer(uintptr(v.data) + uintptr(index)*elemSize)}
}
func (v Value) StructFieldOffset(offset uintptr) Value {
return Value{unsafe.Pointer(uintptr(v.data) + offset)}
}
func (v Value) PointerElem() Value {
return Value{*(*unsafe.Pointer)(v.data)}
}
func (v Value) PointerIsNil() bool {
return *(*unsafe.Pointer)(v.data) == nil
}
func (v Value) PointerSetNil() {
*(*unsafe.Pointer)(v.data) = nil
}
// Analogous to rv.Set(reflect.New(elemType)).
func (v Value) PointerSetNew(elemType reflect.Type) {
*(*unsafe.Pointer)(v.data) = unsafeNew(runtimeTypeFromReflectType(elemType))
}
// The runtime type of a value in go.
// Equivalent to *reflect.rtype.
type runtimeType uintptr
// A struct representing the in-memory layout of a go interface.
type runtimeInterfaceImpl struct {
rtype runtimeType
data unsafe.Pointer
}
// Extract the underlying in-memory structure from an interface.
func extractInterface(i interface{}) *runtimeInterfaceImpl {
// It is also possible to get the data field via
// reflect.ValueOf(v).Elem().UnsafeAddr(), but this does
// not require a heap allocation and dereferences the
// pointer in the interface.
return (*runtimeInterfaceImpl)(unsafe.Pointer(&i))
}
// Extract the runtime type from a reflect.Type.
func runtimeTypeFromReflectType(rt reflect.Type) runtimeType {
// A reflect type is an interface with rtype as its data.
// (see reflect/type.go)/
return runtimeType(extractInterface(rt).data)
}
// unsafeNew is equivalent to reflect.New(rt).Elem().UnsafeAddr().
//go:linkname unsafeNew reflect.unsafe_New
func unsafeNew(rtype runtimeType) unsafe.Pointer
// unsafe_NewArray allocates a new array of the specified type.
//go:linkname unsafe_NewArray reflect.unsafe_NewArray
func unsafe_NewArray(rtype runtimeType, length int) unsafe.Pointer