using System;
using System.Collections.Generic;
namespace Capnp
{
///
/// Base class for interpreting a as List(T).
///
public abstract class ListDeserializer
{
static class GenericCasts
{
public static Func? CastFunc;
public static Func GetCastFunc() => CastFunc ??
throw new NotSupportedException("Requested cast is not supported");
}
static ListDeserializer()
{
GenericCasts>.CastFunc = _ => _.CastBool();
GenericCasts>.CastFunc = _ => _.CastSByte();
GenericCasts>.CastFunc = _ => _.CastByte();
GenericCasts>.CastFunc = _ => _.CastShort();
GenericCasts>.CastFunc = _ => _.CastUShort();
GenericCasts>.CastFunc = _ => _.CastInt();
GenericCasts>.CastFunc = _ => _.CastUInt();
GenericCasts>.CastFunc = _ => _.CastLong();
GenericCasts>.CastFunc = _ => _.CastULong();
GenericCasts>.CastFunc = _ => _.CastFloat();
GenericCasts>.CastFunc = _ => _.CastDouble();
GenericCasts.CastFunc = _ => _.CastText()!; // it *may* return null, but how to express this syntactically correct?
}
///
/// Underlying deserializer state
///
protected readonly DeserializerState State;
internal ListDeserializer(in DeserializerState state)
{
State = state;
}
internal ListDeserializer()
{
}
T Cast()
{
return GenericCasts.GetCastFunc()(this);
}
///
/// This list's element count
///
public int Count => State.ListElementCount;
///
/// The list's element category
///
public abstract ListKind Kind { get; }
///
/// Represents this list by applying a selector function to each element's deserializer state.
/// This operator is only supported by certain specializations.
///
/// Target element type
/// Selector function
/// The desired representation
public abstract IReadOnlyList Cast(Func cons);
///
/// Represents this list as a list of lists.
///
/// The list of lists representation, each element being a on its own.
/// If this kind of list cannot be represented as list of lists (because it is a list of non-pointers)
public virtual IReadOnlyList CastList()
{
throw new NotSupportedException("This kind of list does not contain nested lists");
}
///
/// Represents this list as a list of capabilities.
///
/// Capability interface
/// Capability list representation
/// If this kind of list cannot be represented as list of capabilities (because it is a list of non-pointers)
/// If does not qualify as capability interface.
public virtual IReadOnlyList CastCapList() where T: class
{
throw new NotSupportedException("This kind of list cannot be represented as list of capabilities");
}
object CastND(int n, Func func)
{
if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n));
for (int i = 1; i < n; i++)
{
var copy = func; // This copy assignment is intentional. Try to optimize it away and be amazed!
func = ld => ld.CastList().LazyListSelect(copy);
}
return func(this);
}
///
/// Represents this list as n-dimensional list of T, with T being a primitive type.
///
/// Element type, must be primitive
/// Number of dimensions
/// The desired representation as >]]>
/// is less than or equal to 0
/// If this list cannot be represented in the desired manner.
public object CastND(int n) => CastND(n, ld => ld.Cast>());
///
/// Represents this list as n-dimensional list of T, with T being any type.
///
/// Element type
/// Number of dimensions
/// Selector function which constructs an instance of from a
/// The desired representation as >]]>
/// is null.
/// is less than or equals 0.
/// If this list cannot be represented in the desired manner.
public object CastND(int n, Func cons) => CastND(n, ld => ld.Cast(cons));
///
/// Represents this list as n-dimensional list of enums.
///
/// Enum type
/// Number of dimensions
/// Cast function which converts ushort value to enum value
/// The desired representation as >]]>
/// is null.
/// is less than or equals 0.
/// If this list cannot be represented in the desired manner.
public object CastEnumsND(int n, Func cons) => CastND(n, ld => ld.CastEnums(cons));
///
/// Represents this list as n-dimensional List(...List(Void))
///
/// Number of dimensions
/// The desired representation as >]]>
/// is less than or equals 0
/// If this list cannot be represented in the desired manner.
public object CastVoidND(int n) => CastND(n, (ListDeserializer ld) => ld.Count);
///
/// Represents this list as "matrix" (jagged array) with primitive element type.
///
/// Element type, must be primitive
/// The desired representation
/// If this list cannot be represented in the desired manner.
public IReadOnlyList> Cast2D()
{
GenericCasts>.GetCastFunc(); // Probe to avoid lazy NotSupportedException
return CastList().LazyListSelect(ld => ld.Cast>());
}
///
/// Represents this list as List(Data).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public IReadOnlyList> CastData() => Cast2D();
///
/// Represents this list as "matrix" (jagged array) with complex element type.
///
/// Element type
/// Selector function which constructs an instance of from a
/// The desired representation
/// is null.
/// If this list cannot be represented in the desired manner.
public IReadOnlyList> Cast2D(Func cons)
{
return CastList().LazyListSelect(ld => ld.Cast(cons));
}
///
/// Represents this list as "matrix" (jagged array) of enum-typed elements.
///
/// Enum type
/// Cast function which converts ushort value to enum value
/// The desired representation
/// is null.
/// If this list cannot be represented in the desired manner.
public IReadOnlyList> CastEnums2D(Func cons)
{
return CastList().LazyListSelect(ld => ld.CastEnums(cons));
}
///
/// Represents this list as 3-dimensional jagged array with primitive element type.
///
/// Element type, must be primitive
/// The desired representation
/// If this list cannot be represented in the desired manner.
public IReadOnlyList>> Cast3D()
{
return CastList().LazyListSelect(ld => ld.Cast2D());
}
///
/// Represents this list as 3-dimensional jagged array with complex element type.
///
/// Element type
/// Selector function which constructs an instance of from a
/// The desired representation
/// is null.
/// If this list cannot be represented in the desired manner.
public IReadOnlyList>> Cast3D(Func cons)
{
return CastList().LazyListSelect(ld => ld.Cast2D(cons));
}
///
/// Represents this list as 3-dimensional jagged array of enum-typed elements.
///
/// Enum type
/// Cast function which converts ushort value to enum value
/// The desired representation
/// is null.
/// If this list cannot be represented in the desired manner.
public IReadOnlyList>> CastEnums3D(Func cons)
{
return CastList().LazyListSelect(ld => ld.CastEnums2D(cons));
}
///
/// Represents this list as list of enum-typed elements.
///
/// Enum type
/// Cast function which converts ushort value to enum value
/// The desired representation
/// is null.
/// If this list cannot be represented in the desired manner.
public IReadOnlyList CastEnums(Func cons)
{
return CastUShort().LazyListSelect(cons);
}
///
/// Represents this list as List(Void), which boils down to returning the number of elements.
///
/// The List(Void) representation which is nothing but the list's element count.
public int CastVoid() => Count;
///
/// Represents this list as List(List(Void)), which boils down to returning a list of element counts.
///
/// A list of integers whereby each number equals the sublist's element count.
/// If this list cannot be represented in the desired manner.
public IReadOnlyList CastVoid2D() => CastList().LazyListSelect(ld => ld.Count);
///
/// Represents this list as List(List(List(Void))).
///
/// The List(List(List(Void))) representation which is in turn a 2-dimensional jagged array of element counts.
/// If this list cannot be represented in the desired manner.
public IReadOnlyList> CastVoid3D() => CastList().LazyListSelect(ld => ld.CastVoid2D());
///
/// Represents this list as List(Text). For representing it as Text, use .
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public IReadOnlyList CastText2() => CastList().LazyListSelect(ld => ld.CastText());
///
/// Represents this list as Text. For representing it as List(Text), use .
///
///
/// Did you notice that the naming pattern is broken here? For every other CastX method, X depicts the element type.
/// CastX actually means "represent this list as list of X". Logically, the semantics of CastText should be the semantics
/// implemented by CastText2. And this method's name should be "CastChar". This wouldn't be accurate either, since a string
/// is semantically more than the list of its characters. Trying to figure out a consistent naming pattern, we'd probably
/// end up in less concise method names (do you have a good suggestion?). Considering this and the fact that you probably
/// won't use these methods directly (because the code generator will produce nice wrappers for you) it seems acceptable to
/// live with the asymmetric and somewhat ugly naming.
///
/// The decoded text
/// If this list cannot be represented in the desired manner.
public virtual string? CastText()
{
throw new NotSupportedException("This kind of list does not represent text");
}
///
/// Represents this list as List(Bool).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public virtual IReadOnlyList CastBool()
{
return Cast(sd => sd.ReadDataBool(0));
}
///
/// Represents this list as List(Int8).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public virtual IReadOnlyList CastSByte()
{
return Cast(sd => sd.ReadDataSByte(0));
}
///
/// Represents this list as List(UInt8).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public virtual IReadOnlyList CastByte()
{
return Cast(sd => sd.ReadDataByte(0));
}
///
/// Represents this list as List(Int16).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public virtual IReadOnlyList CastShort()
{
return Cast(sd => sd.ReadDataShort(0));
}
///
/// Represents this list as List(UInt16).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public virtual IReadOnlyList CastUShort()
{
return Cast(sd => sd.ReadDataUShort(0));
}
///
/// Represents this list as List(Int32).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public virtual IReadOnlyList CastInt()
{
return Cast(sd => sd.ReadDataInt(0));
}
///
/// Represents this list as List(UInt32).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public virtual IReadOnlyList CastUInt()
{
return Cast(sd => sd.ReadDataUInt(0));
}
///
/// Represents this list as List(Int64).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public virtual IReadOnlyList CastLong()
{
return Cast(sd => sd.ReadDataLong(0));
}
///
/// Represents this list as List(UInt64).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public virtual IReadOnlyList CastULong()
{
return Cast(sd => sd.ReadDataULong(0));
}
///
/// Represents this list as List(Float32).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public virtual IReadOnlyList CastFloat()
{
return Cast(sd => sd.ReadDataFloat(0));
}
///
/// Represents this list as List(Float64).
///
/// The desired representation
/// If this list cannot be represented in the desired manner.
public virtual IReadOnlyList CastDouble()
{
return Cast(sd => sd.ReadDataDouble(0));
}
}
}