cloudflared-mirror/vendor/zombiezen.com/go/capnproto2/pointer.go

305 lines
6.5 KiB
Go

package capnp
// A Ptr is a reference to a Cap'n Proto struct, list, or interface.
// The zero value is a null pointer.
type Ptr struct {
seg *Segment
off Address
lenOrCap uint32
size ObjectSize
depthLimit uint
flags ptrFlags
}
func toPtr(p Pointer) Ptr {
if p == nil {
return Ptr{}
}
switch p := p.underlying().(type) {
case Struct:
return p.ToPtr()
case List:
return p.ToPtr()
case Interface:
return p.ToPtr()
}
return Ptr{}
}
// Struct converts p to a Struct. If p does not hold a Struct pointer,
// the zero value is returned.
func (p Ptr) Struct() Struct {
if p.flags.ptrType() != structPtrType {
return Struct{}
}
return Struct{
seg: p.seg,
off: p.off,
size: p.size,
flags: p.flags.structFlags(),
depthLimit: p.depthLimit,
}
}
// StructDefault attempts to convert p into a struct, reading the
// default value from def if p is not a struct.
func (p Ptr) StructDefault(def []byte) (Struct, error) {
s := p.Struct()
if s.seg == nil {
if def == nil {
return Struct{}, nil
}
defp, err := unmarshalDefault(def)
if err != nil {
return Struct{}, err
}
return defp.Struct(), nil
}
return s, nil
}
// List converts p to a List. If p does not hold a List pointer,
// the zero value is returned.
func (p Ptr) List() List {
if p.flags.ptrType() != listPtrType {
return List{}
}
return List{
seg: p.seg,
off: p.off,
length: int32(p.lenOrCap),
size: p.size,
flags: p.flags.listFlags(),
depthLimit: p.depthLimit,
}
}
// ListDefault attempts to convert p into a list, reading the default
// value from def if p is not a list.
func (p Ptr) ListDefault(def []byte) (List, error) {
l := p.List()
if l.seg == nil {
if def == nil {
return List{}, nil
}
defp, err := unmarshalDefault(def)
if err != nil {
return List{}, err
}
return defp.List(), nil
}
return l, nil
}
// Interface converts p to an Interface. If p does not hold a List
// pointer, the zero value is returned.
func (p Ptr) Interface() Interface {
if p.flags.ptrType() != interfacePtrType {
return Interface{}
}
return Interface{
seg: p.seg,
cap: CapabilityID(p.lenOrCap),
}
}
// Text attempts to convert p into Text, returning an empty string if
// p is not a valid 1-byte list pointer.
func (p Ptr) Text() string {
b, ok := p.text()
if !ok {
return ""
}
return string(b)
}
// TextDefault attempts to convert p into Text, returning def if p is
// not a valid 1-byte list pointer.
func (p Ptr) TextDefault(def string) string {
b, ok := p.text()
if !ok {
return def
}
return string(b)
}
// TextBytes attempts to convert p into Text, returning nil if p is not
// a valid 1-byte list pointer. It returns a slice directly into the
// segment.
func (p Ptr) TextBytes() []byte {
b, ok := p.text()
if !ok {
return nil
}
return b
}
// TextBytesDefault attempts to convert p into Text, returning def if p
// is not a valid 1-byte list pointer. It returns a slice directly into
// the segment.
func (p Ptr) TextBytesDefault(def string) []byte {
b, ok := p.text()
if !ok {
return []byte(def)
}
return b
}
func (p Ptr) text() (b []byte, ok bool) {
if !isOneByteList(p) {
return nil, false
}
l := p.List()
b = l.seg.slice(l.off, Size(l.length))
if len(b) == 0 || b[len(b)-1] != 0 {
// Text must be null-terminated.
return nil, false
}
return b[:len(b)-1 : len(b)], true
}
// Data attempts to convert p into Data, returning nil if p is not a
// valid 1-byte list pointer.
func (p Ptr) Data() []byte {
return p.DataDefault(nil)
}
// DataDefault attempts to convert p into Data, returning def if p is
// not a valid 1-byte list pointer.
func (p Ptr) DataDefault(def []byte) []byte {
if !isOneByteList(p) {
return def
}
l := p.List()
b := l.seg.slice(l.off, Size(l.length))
if b == nil {
return def
}
return b
}
func (p Ptr) toPointer() Pointer {
if p.seg == nil {
return nil
}
switch p.flags.ptrType() {
case structPtrType:
return p.Struct()
case listPtrType:
return p.List()
case interfacePtrType:
return p.Interface()
}
return nil
}
// IsValid reports whether p is valid.
func (p Ptr) IsValid() bool {
return p.seg != nil
}
// Segment returns the segment this pointer points into.
// If nil, then this is an invalid pointer.
func (p Ptr) Segment() *Segment {
return p.seg
}
// Default returns p if it is valid, otherwise it unmarshals def.
func (p Ptr) Default(def []byte) (Ptr, error) {
if !p.IsValid() {
return unmarshalDefault(def)
}
return p, nil
}
// SamePtr reports whether p and q refer to the same object.
func SamePtr(p, q Ptr) bool {
return p.seg == q.seg && p.off == q.off
}
// A value that implements Pointer is a reference to a Cap'n Proto object.
//
// Deprecated: Using this type introduces an unnecessary allocation.
// Use Ptr instead.
type Pointer interface {
// Segment returns the segment this pointer points into.
// If nil, then this is an invalid pointer.
Segment() *Segment
// HasData reports whether the object referenced by the pointer has
// non-zero size.
HasData() bool
// underlying returns a Pointer that is one of a Struct, a List, or an
// Interface.
underlying() Pointer
}
// IsValid reports whether p is valid.
//
// Deprecated: Use Ptr.IsValid instead.
func IsValid(p Pointer) bool {
return p != nil && p.Segment() != nil
}
// HasData reports whether p has non-zero size.
//
// Deprecated: There are usually better ways to determine this
// information: length of a list, checking fields, or using HasFoo
// accessors.
func HasData(p Pointer) bool {
return IsValid(p) && p.HasData()
}
// PointerDefault returns p if it is valid, otherwise it unmarshals def.
//
// Deprecated: Use Ptr.Default.
func PointerDefault(p Pointer, def []byte) (Pointer, error) {
pp, err := toPtr(p).Default(def)
return pp.toPointer(), err
}
func unmarshalDefault(def []byte) (Ptr, error) {
msg, err := Unmarshal(def)
if err != nil {
return Ptr{}, err
}
p, err := msg.RootPtr()
if err != nil {
return Ptr{}, err
}
return p, nil
}
type ptrFlags uint8
const interfacePtrFlag ptrFlags = interfacePtrType << 6
func structPtrFlag(f structFlags) ptrFlags {
return structPtrType<<6 | ptrFlags(f)&ptrLowerMask
}
func listPtrFlag(f listFlags) ptrFlags {
return listPtrType<<6 | ptrFlags(f)&ptrLowerMask
}
const (
structPtrType = iota
listPtrType
interfacePtrType
)
func (f ptrFlags) ptrType() int {
return int(f >> 6)
}
const ptrLowerMask ptrFlags = 0x3f
func (f ptrFlags) listFlags() listFlags {
return listFlags(f & ptrLowerMask)
}
func (f ptrFlags) structFlags() structFlags {
return structFlags(f & ptrLowerMask)
}