// Copyright 2018 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.
//go:build !purego && !appengine && !go1.21
// +build !purego,!appengine,!go1.21
package protoreflect
import (
"unsafe"
"google.golang.org/protobuf/internal/pragma"
)
type (
stringHeader struct {
Data unsafe.Pointer
Len int
}
sliceHeader struct {
Data unsafe.Pointer
Len int
Cap int
}
ifaceHeader struct {
Type unsafe.Pointer
Data unsafe.Pointer
}
)
var (
nilType = typeOf(nil)
boolType = typeOf(*new(bool))
int32Type = typeOf(*new(int32))
int64Type = typeOf(*new(int64))
uint32Type = typeOf(*new(uint32))
uint64Type = typeOf(*new(uint64))
float32Type = typeOf(*new(float32))
float64Type = typeOf(*new(float64))
stringType = typeOf(*new(string))
bytesType = typeOf(*new([]byte))
enumType = typeOf(*new(EnumNumber))
)
// typeOf returns a pointer to the Go type information.
// The pointer is comparable and equal if and only if the types are identical.
func typeOf(t any) unsafe.Pointer {
return (*ifaceHeader)(unsafe.Pointer(&t)).Type
}
// value is a union where only one type can be represented at a time.
// The struct is 24B large on 64-bit systems and requires the minimum storage
// necessary to represent each possible type.
//
// The Go GC needs to be able to scan variables containing pointers.
// As such, pointers and non-pointers cannot be intermixed.
type value struct {
pragma.DoNotCompare // 0B
// typ stores the type of the value as a pointer to the Go type.
typ unsafe.Pointer // 8B
// ptr stores the data pointer for a String, Bytes, or interface value.
ptr unsafe.Pointer // 8B
// num stores a Bool, Int32, Int64, Uint32, Uint64, Float32, Float64, or
// Enum value as a raw uint64.
//
// It is also used to store the length of a String or Bytes value;
// the capacity is ignored.
num uint64 // 8B
}
func valueOfString(v string) Value {
p := (*stringHeader)(unsafe.Pointer(&v))
return Value{typ: stringType, ptr: p.Data, num: uint64(len(v))}
}
func valueOfBytes(v []byte) Value {
p := (*sliceHeader)(unsafe.Pointer(&v))
return Value{typ: bytesType, ptr: p.Data, num: uint64(len(v))}
}
func valueOfIface(v any) Value {
p := (*ifaceHeader)(unsafe.Pointer(&v))
return Value{typ: p.Type, ptr: p.Data}
}
func (v Value) getString() (x string) {
*(*stringHeader)(unsafe.Pointer(&x)) = stringHeader{Data: v.ptr, Len: int(v.num)}
return x
}
func (v Value) getBytes() (x []byte) {
*(*sliceHeader)(unsafe.Pointer(&x)) = sliceHeader{Data: v.ptr, Len: int(v.num), Cap: int(v.num)}
return x
}
func (v Value) getIface() (x any) {
*(*ifaceHeader)(unsafe.Pointer(&x)) = ifaceHeader{Type: v.typ, Data: v.ptr}
return x
}