github.com/vc42/parquet-go@v0.0.0-20240320194221-1a9adb5f23f5/internal/unsafecast/unsafecast_go18.go (about) 1 //go:build go1.18 2 3 // Package unsafecast exposes functions to bypass the Go type system and perform 4 // conversions between types that would otherwise not be possible. 5 // 6 // The functions of this package are mostly useful as optimizations to avoid 7 // memory copies when converting between compatible memory layouts; for example, 8 // casting a [][16]byte to a []byte in order to use functions of the standard 9 // bytes package on the slices. 10 // 11 // With great power comes great responsibility. 12 // 13 package unsafecast 14 15 import ( 16 "reflect" 17 "unsafe" 18 ) 19 20 // AddressOf returns the address to the first element in data, even if the slice 21 // has length zero. 22 func AddressOf[T any](data []T) *T { 23 return *(**T)(unsafe.Pointer(&data)) 24 } 25 26 // AddressOfBytes returns the address of the first byte in data. 27 func AddressOfBytes(data []byte) *byte { 28 return AddressOf(data) 29 } 30 31 // AddressOfString returns the address of the first byte in data. 32 func AddressOfString(data string) *byte { 33 return *(**byte)(unsafe.Pointer(&data)) 34 } 35 36 // PointerOf is like AddressOf but returns an unsafe.Pointer, losing type 37 // information about the underlying data. 38 func PointerOf[T any](data []T) unsafe.Pointer { 39 return unsafe.Pointer(AddressOf(data)) 40 } 41 42 // PointerOfString is like AddressOfString but returns an unsafe.Pointer, losing 43 // type information about the underlying data. 44 func PointerOfString(data string) unsafe.Pointer { 45 return unsafe.Pointer(AddressOfString(data)) 46 } 47 48 // PointerOfValue returns the address of the object packed in the given value. 49 // 50 // This function is like value.UnsafePointer but works for any underlying type, 51 // bypassing the safety checks done by the reflect package. 52 func PointerOfValue(value reflect.Value) unsafe.Pointer { 53 return (*[2]unsafe.Pointer)(unsafe.Pointer(&value))[1] 54 } 55 56 // The slice type represents the memory layout of slices in Go. It is similar to 57 // reflect.SliceHeader but uses a unsafe.Pointer instead of uintptr to for the 58 // backing array to allow the garbage collector to track track the reference. 59 type slice struct { 60 ptr unsafe.Pointer 61 len int 62 cap int 63 } 64 65 // Slice converts the data slice of type []From to a slice of type []To sharing 66 // the same backing array. The length and capacity of the returned slice are 67 // scaled according to the size difference between the source and destination 68 // types. 69 // 70 // Note that the function does not perform any checks to ensure that the memory 71 // layouts of the types are compatible, it is possible to cause memory 72 // corruption if the layouts mismatch (e.g. the pointers in the From are different 73 // than the pointers in To). 74 func Slice[To, From any](data []From) []To { 75 // This function could use unsafe.Slice but it would drop the capacity 76 // information, so instead we implement the type conversion. 77 var zf From 78 var zt To 79 var s = (*slice)(unsafe.Pointer(&data)) 80 s.len = int((uintptr(s.len) * unsafe.Sizeof(zf)) / unsafe.Sizeof(zt)) 81 s.cap = int((uintptr(s.cap) * unsafe.Sizeof(zf)) / unsafe.Sizeof(zt)) 82 return *(*[]To)(unsafe.Pointer(s)) 83 } 84 85 // BytesToString converts a byte slice to a string value. The returned string 86 // shares the backing array of the byte slice. 87 // 88 // Programs using this function are responsible for ensuring that the data slice 89 // is not modified while the returned string is in use, otherwise the guarantee 90 // of immutability of Go string values will be violated, resulting in undefined 91 // behavior. 92 func BytesToString(data []byte) string { 93 return *(*string)(unsafe.Pointer(&data)) 94 } 95 96 // StringToBytes applies the inverse conversion of BytesToString. 97 func StringToBytes(data string) []byte { 98 return *(*[]byte)(unsafe.Pointer(&slice{ 99 ptr: PointerOfString(data), 100 len: len(data), 101 cap: len(data), 102 })) 103 } 104 105 // ----------------------------------------------------------------------------- 106 // TODO: the functions below are used for backward compatibility with Go 1.17 107 // where generics weren't available. We should remove them and inline calls to 108 // unsafecast.Slice when we change our minimum supported Go version to 1.18. 109 // ----------------------------------------------------------------------------- 110 111 func BoolToBytes(data []bool) []byte { return Slice[byte](data) } 112 113 func Int8ToBytes(data []int8) []byte { return Slice[byte](data) } 114 115 func Int16ToBytes(data []int16) []byte { return Slice[byte](data) } 116 117 func Int32ToBytes(data []int32) []byte { return Slice[byte](data) } 118 119 func Int64ToBytes(data []int64) []byte { return Slice[byte](data) } 120 121 func Float32ToBytes(data []float32) []byte { return Slice[byte](data) } 122 123 func Float64ToBytes(data []float64) []byte { return Slice[byte](data) } 124 125 func Uint32ToBytes(data []uint32) []byte { return Slice[byte](data) } 126 127 func Uint64ToBytes(data []uint64) []byte { return Slice[byte](data) } 128 129 func Uint128ToBytes(data [][16]byte) []byte { return Slice[byte](data) } 130 131 func Int16ToUint16(data []int16) []uint16 { return Slice[uint16](data) } 132 133 func Int32ToUint32(data []int32) []uint32 { return Slice[uint32](data) } 134 135 func Int64ToUint64(data []int64) []uint64 { return Slice[uint64](data) } 136 137 func Float32ToUint32(data []float32) []uint32 { return Slice[uint32](data) } 138 139 func Float64ToUint64(data []float64) []uint64 { return Slice[uint64](data) } 140 141 func Uint32ToInt32(data []uint32) []int32 { return Slice[int32](data) } 142 143 func Uint32ToInt64(data []uint32) []int64 { return Slice[int64](data) } 144 145 func Uint64ToInt64(data []uint64) []int64 { return Slice[int64](data) } 146 147 func BytesToBool(data []byte) []bool { return Slice[bool](data) } 148 149 func BytesToInt8(data []byte) []int8 { return Slice[int8](data) } 150 151 func BytesToInt16(data []byte) []int16 { return Slice[int16](data) } 152 153 func BytesToInt32(data []byte) []int32 { return Slice[int32](data) } 154 155 func BytesToInt64(data []byte) []int64 { return Slice[int64](data) } 156 157 func BytesToUint32(data []byte) []uint32 { return Slice[uint32](data) } 158 159 func BytesToUint64(data []byte) []uint64 { return Slice[uint64](data) } 160 161 func BytesToUint128(data []byte) [][16]byte { return Slice[[16]byte](data) } 162 163 func BytesToFloat32(data []byte) []float32 { return Slice[float32](data) } 164 165 func BytesToFloat64(data []byte) []float64 { return Slice[float64](data) }