using System; namespace Capnp { /// /// Pointer tag, see https://capnproto.org/encoding.html/> /// public enum PointerKind : byte { /// /// Struct pointer /// Struct = 0, /// /// List pointer /// List = 1, /// /// Far pointer /// Far = 2, /// /// Other (capability) pointer /// Other = 3 } /// /// Lightweight wrapper struct around a Cap'n Proto pointer. Useful for both encoding and decoding pointers. /// public struct WirePointer { ulong _ptrData; /// /// Constructs this struct from pointer raw data /// public WirePointer(ulong ptrData) { _ptrData = ptrData; } /// /// Interprets any ulong value as Cap'n Proto pointer /// public static implicit operator WirePointer (ulong value) => new WirePointer(value); /// /// Extracts the wire data from the pointer. /// public static implicit operator ulong (WirePointer pointer) => pointer._ptrData; /// /// Pointer tag "A" /// public PointerKind Kind { get => (PointerKind)(_ptrData & 3); set { _ptrData = _ptrData & ~3ul | (ulong)value; } } /// /// Returns true iff this is a null pointer. /// public bool IsNull => _ptrData == 0; /// /// The Offset (field "B") for struct and list pointers. /// /// Thrown by setter if encoded value would require more than 30 bits public int Offset { get => unchecked((int)_ptrData) >> 2; set { if (value >= (1 << 29) || value < -(1 << 29)) throw new ArgumentOutOfRangeException(nameof(value)); _ptrData |= (uint)(value << 2); } } /// /// Returns the landing pad offset (field "C") for inter-segment pointers. /// public int LandingPadOffset { get => unchecked((int)((_ptrData >> 3) & 0x1fffffff)); } /// /// Returns the size of the struct's data section (field "C"), in words, for struct pointers. /// public ushort StructDataCount { get => unchecked((ushort)(_ptrData >> 32)); } /// /// Returns the size of the struct's pointer section (field "D"), in words, for struct pointers. /// public ushort StructPtrCount { get => unchecked((ushort)(_ptrData >> 48)); } /// /// Convenience getter which returns the sum of the struct's pointer and data section sizes. /// public uint StructSize { get => (uint)StructDataCount + StructPtrCount; } /// /// Begins encoding a struct pointer. /// /// the size of the struct's data section, in words /// the size of the struct's pointer section, in words public void BeginStruct(ushort dataCount, ushort ptrCount) { _ptrData = ((ulong)dataCount << 32) | ((ulong)ptrCount << 48); } /// /// Returns the list "size" (field "C") for list pointers. /// public ListKind ListKind { get => (ListKind)((int)(_ptrData >> 32) & 0x7); } /// /// Gets or sets the element count if this pointer represents a list of fixed-width composite values. /// /// negative value, or encoded value would require more than 30 bits public int ListOfStructsElementCount { get => (int)((_ptrData >> 2) & 0x3fffffff); set { _ptrData = _ptrData & 0xffffffff00000000ul | checked((uint)value << 2); } } /// /// Returns the element count if this pointer represents a list of anything, except fixed-width composite values. /// public int ListElementCount { get => (int)(_ptrData >> 35); } /// /// Begins encoding a list pointer /// /// element "size" (field "C") /// element count /// element count would require more than 29 bits public void BeginList(ListKind kind, int count) { if (count < 0 || count >= (1 << 29)) throw new ArgumentOutOfRangeException(nameof(count)); _ptrData = ((ulong)count << 35) | ((ulong)kind << 32) | (ulong)PointerKind.List; } /// /// Returns the target segment index (field "D") for inter-segment pointers. /// public uint TargetSegmentIndex { get => (uint)(_ptrData >> 32); } /// /// Whether the landing pad is two words (field "B") for inter-segment pointers. /// public bool IsDoubleFar { get => (_ptrData & 4) != 0; } /// /// Encodes an inter-segment pointer. /// /// target segment index /// landing pad offset /// whether the landing pad is two words /// negative landing pad offset, or encoding would require more than 29 bits public void SetFarPointer(uint targetSegmentIndex, int landingPadOffset, bool isDoubleFar) { if (landingPadOffset < 0 || landingPadOffset >= (1 << 29)) throw new ArgumentOutOfRangeException(nameof(landingPadOffset)); _ptrData = ((ulong)targetSegmentIndex << 32) | ((uint)landingPadOffset << 3) | (ulong)PointerKind.Far; if (isDoubleFar) _ptrData |= 4; } /// /// Returns the sub-kind of pointer (field "B") if this is an "other" pointer. /// Currently, only 0 is specified, which is a capability pointer. /// public uint OtherPointerKind { get => unchecked((uint)_ptrData) >> 2; } /// /// Returns the capability index (field "C") if this is a capability pointer. /// public uint CapabilityIndex { get => (uint)(_ptrData >> 32); } /// /// Encodes a capability pointer. /// /// capability index, 'null' means 'null pointer' public void SetCapability(uint? index) { if (index.HasValue) _ptrData = ((ulong)index << 32) | (ulong)PointerKind.Other; else _ptrData = 0; } } }