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