.github
alerting
client
config
controller
core
docs
examples
jsonpath
metric
pattern
security
storage
util
vendor
github.com
go.etcd.io
golang.org
google.golang.org
protobuf
encoding
internal
descfmt
descopts
detrand
encoding
errors
fieldsort
filedesc
filetype
flags
genid
impl
api_export.go
checkinit.go
codec_extension.go
codec_field.go
codec_gen.go
codec_map.go
codec_map_go111.go
codec_map_go112.go
codec_message.go
codec_messageset.go
codec_reflect.go
codec_tables.go
codec_unsafe.go
convert.go
convert_list.go
convert_map.go
decode.go
encode.go
enum.go
extension.go
legacy_enum.go
legacy_export.go
legacy_extension.go
legacy_file.go
legacy_message.go
merge.go
merge_gen.go
message.go
message_reflect.go
message_reflect_field.go
message_reflect_gen.go
pointer_reflect.go
pointer_unsafe.go
validate.go
weak.go
mapsort
pragma
set
strs
version
proto
reflect
runtime
types
AUTHORS
CONTRIBUTORS
LICENSE
PATENTS
gopkg.in
lukechampine.com
modernc.org
modules.txt
watchdog
web
.dockerignore
.gitattributes
.gitignore
Dockerfile
LICENSE.md
Makefile
README.md
config.yaml
go.mod
go.sum
main.go
174 lines
6.8 KiB
Go
174 lines
6.8 KiB
Go
// 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.
|
|
|
|
// +build !purego,!appengine
|
|
|
|
package impl
|
|
|
|
import (
|
|
"reflect"
|
|
"sync/atomic"
|
|
"unsafe"
|
|
)
|
|
|
|
const UnsafeEnabled = true
|
|
|
|
// Pointer is an opaque pointer type.
|
|
type Pointer unsafe.Pointer
|
|
|
|
// offset represents the offset to a struct field, accessible from a pointer.
|
|
// The offset is the byte offset to the field from the start of the struct.
|
|
type offset uintptr
|
|
|
|
// offsetOf returns a field offset for the struct field.
|
|
func offsetOf(f reflect.StructField, x exporter) offset {
|
|
return offset(f.Offset)
|
|
}
|
|
|
|
// IsValid reports whether the offset is valid.
|
|
func (f offset) IsValid() bool { return f != invalidOffset }
|
|
|
|
// invalidOffset is an invalid field offset.
|
|
var invalidOffset = ^offset(0)
|
|
|
|
// zeroOffset is a noop when calling pointer.Apply.
|
|
var zeroOffset = offset(0)
|
|
|
|
// pointer is a pointer to a message struct or field.
|
|
type pointer struct{ p unsafe.Pointer }
|
|
|
|
// pointerOf returns p as a pointer.
|
|
func pointerOf(p Pointer) pointer {
|
|
return pointer{p: unsafe.Pointer(p)}
|
|
}
|
|
|
|
// pointerOfValue returns v as a pointer.
|
|
func pointerOfValue(v reflect.Value) pointer {
|
|
return pointer{p: unsafe.Pointer(v.Pointer())}
|
|
}
|
|
|
|
// pointerOfIface returns the pointer portion of an interface.
|
|
func pointerOfIface(v interface{}) pointer {
|
|
type ifaceHeader struct {
|
|
Type unsafe.Pointer
|
|
Data unsafe.Pointer
|
|
}
|
|
return pointer{p: (*ifaceHeader)(unsafe.Pointer(&v)).Data}
|
|
}
|
|
|
|
// IsNil reports whether the pointer is nil.
|
|
func (p pointer) IsNil() bool {
|
|
return p.p == nil
|
|
}
|
|
|
|
// Apply adds an offset to the pointer to derive a new pointer
|
|
// to a specified field. The pointer must be valid and pointing at a struct.
|
|
func (p pointer) Apply(f offset) pointer {
|
|
if p.IsNil() {
|
|
panic("invalid nil pointer")
|
|
}
|
|
return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))}
|
|
}
|
|
|
|
// AsValueOf treats p as a pointer to an object of type t and returns the value.
|
|
// It is equivalent to reflect.ValueOf(p.AsIfaceOf(t))
|
|
func (p pointer) AsValueOf(t reflect.Type) reflect.Value {
|
|
return reflect.NewAt(t, p.p)
|
|
}
|
|
|
|
// AsIfaceOf treats p as a pointer to an object of type t and returns the value.
|
|
// It is equivalent to p.AsValueOf(t).Interface()
|
|
func (p pointer) AsIfaceOf(t reflect.Type) interface{} {
|
|
// TODO: Use tricky unsafe magic to directly create ifaceHeader.
|
|
return p.AsValueOf(t).Interface()
|
|
}
|
|
|
|
func (p pointer) Bool() *bool { return (*bool)(p.p) }
|
|
func (p pointer) BoolPtr() **bool { return (**bool)(p.p) }
|
|
func (p pointer) BoolSlice() *[]bool { return (*[]bool)(p.p) }
|
|
func (p pointer) Int32() *int32 { return (*int32)(p.p) }
|
|
func (p pointer) Int32Ptr() **int32 { return (**int32)(p.p) }
|
|
func (p pointer) Int32Slice() *[]int32 { return (*[]int32)(p.p) }
|
|
func (p pointer) Int64() *int64 { return (*int64)(p.p) }
|
|
func (p pointer) Int64Ptr() **int64 { return (**int64)(p.p) }
|
|
func (p pointer) Int64Slice() *[]int64 { return (*[]int64)(p.p) }
|
|
func (p pointer) Uint32() *uint32 { return (*uint32)(p.p) }
|
|
func (p pointer) Uint32Ptr() **uint32 { return (**uint32)(p.p) }
|
|
func (p pointer) Uint32Slice() *[]uint32 { return (*[]uint32)(p.p) }
|
|
func (p pointer) Uint64() *uint64 { return (*uint64)(p.p) }
|
|
func (p pointer) Uint64Ptr() **uint64 { return (**uint64)(p.p) }
|
|
func (p pointer) Uint64Slice() *[]uint64 { return (*[]uint64)(p.p) }
|
|
func (p pointer) Float32() *float32 { return (*float32)(p.p) }
|
|
func (p pointer) Float32Ptr() **float32 { return (**float32)(p.p) }
|
|
func (p pointer) Float32Slice() *[]float32 { return (*[]float32)(p.p) }
|
|
func (p pointer) Float64() *float64 { return (*float64)(p.p) }
|
|
func (p pointer) Float64Ptr() **float64 { return (**float64)(p.p) }
|
|
func (p pointer) Float64Slice() *[]float64 { return (*[]float64)(p.p) }
|
|
func (p pointer) String() *string { return (*string)(p.p) }
|
|
func (p pointer) StringPtr() **string { return (**string)(p.p) }
|
|
func (p pointer) StringSlice() *[]string { return (*[]string)(p.p) }
|
|
func (p pointer) Bytes() *[]byte { return (*[]byte)(p.p) }
|
|
func (p pointer) BytesSlice() *[][]byte { return (*[][]byte)(p.p) }
|
|
func (p pointer) WeakFields() *weakFields { return (*weakFields)(p.p) }
|
|
func (p pointer) Extensions() *map[int32]ExtensionField { return (*map[int32]ExtensionField)(p.p) }
|
|
|
|
func (p pointer) Elem() pointer {
|
|
return pointer{p: *(*unsafe.Pointer)(p.p)}
|
|
}
|
|
|
|
// PointerSlice loads []*T from p as a []pointer.
|
|
// The value returned is aliased with the original slice.
|
|
// This behavior differs from the implementation in pointer_reflect.go.
|
|
func (p pointer) PointerSlice() []pointer {
|
|
// Super-tricky - p should point to a []*T where T is a
|
|
// message type. We load it as []pointer.
|
|
return *(*[]pointer)(p.p)
|
|
}
|
|
|
|
// AppendPointerSlice appends v to p, which must be a []*T.
|
|
func (p pointer) AppendPointerSlice(v pointer) {
|
|
*(*[]pointer)(p.p) = append(*(*[]pointer)(p.p), v)
|
|
}
|
|
|
|
// SetPointer sets *p to v.
|
|
func (p pointer) SetPointer(v pointer) {
|
|
*(*unsafe.Pointer)(p.p) = (unsafe.Pointer)(v.p)
|
|
}
|
|
|
|
// Static check that MessageState does not exceed the size of a pointer.
|
|
const _ = uint(unsafe.Sizeof(unsafe.Pointer(nil)) - unsafe.Sizeof(MessageState{}))
|
|
|
|
func (Export) MessageStateOf(p Pointer) *messageState {
|
|
// Super-tricky - see documentation on MessageState.
|
|
return (*messageState)(unsafe.Pointer(p))
|
|
}
|
|
func (ms *messageState) pointer() pointer {
|
|
// Super-tricky - see documentation on MessageState.
|
|
return pointer{p: unsafe.Pointer(ms)}
|
|
}
|
|
func (ms *messageState) messageInfo() *MessageInfo {
|
|
mi := ms.LoadMessageInfo()
|
|
if mi == nil {
|
|
panic("invalid nil message info; this suggests memory corruption due to a race or shallow copy on the message struct")
|
|
}
|
|
return mi
|
|
}
|
|
func (ms *messageState) LoadMessageInfo() *MessageInfo {
|
|
return (*MessageInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&ms.atomicMessageInfo))))
|
|
}
|
|
func (ms *messageState) StoreMessageInfo(mi *MessageInfo) {
|
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&ms.atomicMessageInfo)), unsafe.Pointer(mi))
|
|
}
|
|
|
|
type atomicNilMessage struct{ p unsafe.Pointer } // p is a *messageReflectWrapper
|
|
|
|
func (m *atomicNilMessage) Init(mi *MessageInfo) *messageReflectWrapper {
|
|
if p := atomic.LoadPointer(&m.p); p != nil {
|
|
return (*messageReflectWrapper)(p)
|
|
}
|
|
w := &messageReflectWrapper{mi: mi}
|
|
atomic.CompareAndSwapPointer(&m.p, nil, (unsafe.Pointer)(w))
|
|
return (*messageReflectWrapper)(atomic.LoadPointer(&m.p))
|
|
}
|