using System; using System.Collections.Generic; namespace Capnp { /// /// This SerializerState specialization provides functionality to build arbitrary Cap'n Proto objects without requiring the schema code generator. /// public class DynamicSerializerState : SerializerState { /// /// Constructs an unbound instance. /// public DynamicSerializerState() { } /// /// Constructs an instance and binds it to the given . /// /// message builder public DynamicSerializerState(MessageBuilder messageBuilder): base(messageBuilder) { } /// /// Constructs an instance, binds it to a dedicated message builder, and initializes the capability table for usage in RPC context. /// public static DynamicSerializerState CreateForRpc() { var mb = MessageBuilder.Create(); mb.InitCapTable(); return new DynamicSerializerState(mb); } /// /// Converts any to a DynamicSerializerState instance, which involves deep copying the object graph. /// /// The deserializer state to convert public static explicit operator DynamicSerializerState(DeserializerState state) { var mb = MessageBuilder.Create(); if (state.Caps != null) { mb.InitCapTable(); } var sstate = mb.CreateObject(); Reserializing.DeepCopy(state, sstate); return sstate; } /// /// Links a sub-item (struct field or list element) of this state to another state. Usually, this operation is not necessary, since objects are constructed top-down. /// However, there might be some advanced scenarios where you want to reference the same object twice (also interesting for designing amplification attacks). /// The Cap'n Proto serialization intrinsically supports this, since messages are object graphs, not trees. /// /// If this state describes a struct: Index into this struct's pointer table. /// If this state describes a list of pointers: List element index. /// state to be linked /// Whether to deep copy the target state if it belongs to a different message builder than this state. /// is null /// out of range /// /// This state does neither describe a struct, nor a list of pointers /// Another state is already linked to the specified position (sorry, no overwrite allowed) /// This state and belong to different message builder, and is false /// public new void Link(int slot, SerializerState target, bool allowCopy = true) => base.Link(slot, target, allowCopy); /// /// Links a sub-item (struct field or list element) of this state to a capability. /// /// If this state describes a struct: Index into this struct's pointer table. /// If this state describes a list of pointers: List element index. /// capability index inside the capability table /// /// This state does neither describe a struct, nor a list of pointers /// Another state is already linked to the specified position (sorry, no overwrite allowed) /// public new void LinkToCapability(int slot, uint? capabilityIndex) => base.LinkToCapability(slot, capabilityIndex); /// /// Determines the underlying object to be a struct. /// /// Desired size of the struct's data section, in words /// Desired size of the struct's pointer section, in words /// The object type was already set to something different public new void SetStruct(ushort dataCount, ushort ptrCount) => base.SetStruct(dataCount, ptrCount); /// /// Determines the underyling object to be a capability. /// /// Capability table index, or null to encode a null pointer /// The object type was already set to something different public new void SetCapability(uint? capabilityIndex) => base.SetCapability(capabilityIndex); /// /// Determines the underlying object to be a list of (primitive) values. /// /// Element size in bits, must be 0 (void), 1 (bool), 8, 16, 32, or 64 /// Desired element count /// The object type was already set to something different /// outside allowed range, /// negative or exceeding 2^29-1 public new void SetListOfValues(byte bitsPerElement, int totalCount) => base.SetListOfValues(bitsPerElement, totalCount); /// /// Determines the underlying object to be a list of pointers. /// /// Desired element count /// The object type was already set to something different /// negative or exceeding 2^29-1 public new void SetListOfPointers(int totalCount) => base.SetListOfPointers(totalCount); /// /// Determines the underlying object to be a list of structs (fixed-width compound list). /// /// Desired element count /// Desired size of each struct's data section, in words /// Desired size of each struct's pointer section, in words /// The object type was already set to something different /// negative, or total word count would exceed 2^29-1 public new void SetListOfStructs(int totalCount, ushort dataCount, ushort ptrCount) => base.SetListOfStructs(totalCount, dataCount, ptrCount); /// /// Constructs the underlying object from the given representation. /// /// Object representation. Must be one of the following: /// /// An instance implementing /// null, /// IReadOnlyList<byte>, IReadOnlyList<sbyte>, IReadOnlyList<ushort>, IReadOnlyList<short> /// IReadOnlyList<int>, IReadOnlyList<uint>, IReadOnlyList<long>, IReadOnlyList<ulong> /// IReadOnlyList<float>, IReadOnlyList<double>, IReadOnlyList<bool>, IReadOnlyList<string> /// Another or /// Low-level capability object () /// Proxy object () /// Skeleton object () /// Capability interface implementation /// IReadOnlyList<object>, whereby each list item is one of the things listed here. /// /// public void SetObject(object? obj) { void RewrapAndInheritBack(Action init) where T : SerializerState, new() { var r = Rewrap(); init(r); InheritFrom(r); } switch (obj) { case ICapnpSerializable serializable: serializable.Serialize(this); break; case string s: WriteText(s); break; case IReadOnlyList bytes: RewrapAndInheritBack>(_ => _.Init(bytes)); break; case IReadOnlyList sbytes: RewrapAndInheritBack>(_ => _.Init(sbytes)); break; case IReadOnlyList ushorts: RewrapAndInheritBack>(_ => _.Init(ushorts)); break; case IReadOnlyList shorts: RewrapAndInheritBack>(_ => _.Init(shorts)); break; case IReadOnlyList uints: RewrapAndInheritBack>(_ => _.Init(uints)); break; case IReadOnlyList ints: RewrapAndInheritBack>(_ => _.Init(ints)); break; case IReadOnlyList ulongs: RewrapAndInheritBack>(_ => _.Init(ulongs)); break; case IReadOnlyList longs: RewrapAndInheritBack>(_ => _.Init(longs)); break; case IReadOnlyList floats: RewrapAndInheritBack>(_ => _.Init(floats)); break; case IReadOnlyList doubles: RewrapAndInheritBack>(_ => _.Init(doubles)); break; case IReadOnlyList bools: RewrapAndInheritBack(_ => _.Init(bools)); break; case IReadOnlyList strings: RewrapAndInheritBack(_ => _.Init(strings)); break; case IReadOnlyList objects: RewrapAndInheritBack>(_ => _.Init(objects, (s, o) => s.SetObject(o))); break; case DeserializerState ds: Reserializing.DeepCopy(ds, this); break; case SerializerState s: Reserializing.DeepCopy(s, this); break; case null: break; default: SetCapability(ProvideCapability(obj)); break; } } } }