2019-06-12 21:56:55 +02:00
using System ;
using System.Collections.Generic ;
namespace Capnp
{
/// <summary>
/// Base class for interpreting a <see cref="DeserializerState"/> as List(T).
/// </summary>
public abstract class ListDeserializer
{
static class GenericCasts < T >
{
2020-01-11 17:21:31 +01:00
public static Func < ListDeserializer , T > ? CastFunc ;
2020-03-01 17:56:14 +01:00
public static Func < ListDeserializer , T > GetCastFunc ( ) = > CastFunc ? ?
throw new NotSupportedException ( "Requested cast is not supported" ) ;
2019-06-12 21:56:55 +02:00
}
static ListDeserializer ( )
{
GenericCasts < IReadOnlyList < bool > > . CastFunc = _ = > _ . CastBool ( ) ;
GenericCasts < IReadOnlyList < sbyte > > . CastFunc = _ = > _ . CastSByte ( ) ;
GenericCasts < IReadOnlyList < byte > > . CastFunc = _ = > _ . CastByte ( ) ;
GenericCasts < IReadOnlyList < short > > . CastFunc = _ = > _ . CastShort ( ) ;
GenericCasts < IReadOnlyList < ushort > > . CastFunc = _ = > _ . CastUShort ( ) ;
GenericCasts < IReadOnlyList < int > > . CastFunc = _ = > _ . CastInt ( ) ;
GenericCasts < IReadOnlyList < uint > > . CastFunc = _ = > _ . CastUInt ( ) ;
GenericCasts < IReadOnlyList < long > > . CastFunc = _ = > _ . CastLong ( ) ;
GenericCasts < IReadOnlyList < ulong > > . CastFunc = _ = > _ . CastULong ( ) ;
GenericCasts < IReadOnlyList < float > > . CastFunc = _ = > _ . CastFloat ( ) ;
GenericCasts < IReadOnlyList < double > > . CastFunc = _ = > _ . CastDouble ( ) ;
2020-03-01 13:18:55 +01:00
GenericCasts < string > . CastFunc = _ = > _ . CastText ( ) ! ; // it *may* return null, but how to express this syntactically correct?
2019-06-12 21:56:55 +02:00
}
/// <summary>
/// Underlying deserializer state
/// </summary>
protected readonly DeserializerState State ;
2020-02-09 13:49:21 +01:00
internal ListDeserializer ( in DeserializerState state )
2019-06-12 21:56:55 +02:00
{
State = state ;
}
internal ListDeserializer ( )
{
}
T Cast < T > ( )
{
2020-03-01 17:56:14 +01:00
return GenericCasts < T > . GetCastFunc ( ) ( this ) ;
2019-06-12 21:56:55 +02:00
}
/// <summary>
/// This list's element count
/// </summary>
public int Count = > State . ListElementCount ;
/// <summary>
/// The list's element category
/// </summary>
public abstract ListKind Kind { get ; }
/// <summary>
/// Represents this list by applying a selector function to each element's deserializer state.
/// This operator is only supported by certain specializations.
/// </summary>
/// <typeparam name="T">Target element type</typeparam>
/// <param name="cons">Selector function</param>
/// <returns>The desired representation</returns>
public abstract IReadOnlyList < T > Cast < T > ( Func < DeserializerState , T > cons ) ;
/// <summary>
/// Represents this list as a list of lists.
/// </summary>
/// <returns>The list of lists representation, each element being a <see cref="ListDeserializer"/> on its own.</returns>
/// <exception cref="NotSupportedException">If this kind of list cannot be represented as list of lists (because it is a list of non-pointers)</exception>
public virtual IReadOnlyList < ListDeserializer > CastList ( )
{
throw new NotSupportedException ( "This kind of list does not contain nested lists" ) ;
}
/// <summary>
/// Represents this list as a list of capabilities.
/// </summary>
/// <typeparam name="T">Capability interface</typeparam>
/// <returns>Capability list representation</returns>
/// <exception cref="NotSupportedException">If this kind of list cannot be represented as list of capabilities (because it is a list of non-pointers)</exception>
/// <exception cref="Rpc.InvalidCapabilityInterfaceException">If <typeparamref name="T"/> does not qualify as capability interface.</exception>
2020-02-26 22:04:59 +01:00
public virtual IReadOnlyList < T > CastCapList < T > ( ) where T : class
2019-06-12 21:56:55 +02:00
{
2020-03-01 17:56:14 +01:00
throw new NotSupportedException ( "This kind of list cannot be represented as list of capabilities" ) ;
2019-06-12 21:56:55 +02:00
}
object CastND ( int n , Func < ListDeserializer , object > 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 ) ;
}
/// <summary>
/// Represents this list as n-dimensional list of T, with T being a primitive type.
/// </summary>
/// <typeparam name="T">Element type, must be primitive</typeparam>
/// <param name="n">Number of dimensions</param>
/// <returns>The desired representation as <![CDATA[IReadOnlyList<...IReadOnlyList<T>>]]></returns>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is less than or equal to 0</exception>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public object CastND < T > ( int n ) = > CastND ( n , ld = > ld . Cast < IReadOnlyList < T > > ( ) ) ;
/// <summary>
/// Represents this list as n-dimensional list of T, with T being any type.
/// </summary>
/// <typeparam name="T">Element type</typeparam>
/// <param name="n">Number of dimensions</param>
/// <param name="cons">Selector function which constructs an instance of <typeparamref name="T"/> from a <see cref="DeserializerState"/></param>
/// <returns>The desired representation as <![CDATA[IReadOnlyList<...IReadOnlyList<T>>]]></returns>
/// <exception cref="ArgumentNullException"><paramref name="cons"/> is null.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is less than or equals 0.</exception>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public object CastND < T > ( int n , Func < DeserializerState , T > cons ) = > CastND ( n , ld = > ld . Cast ( cons ) ) ;
/// <summary>
/// Represents this list as n-dimensional list of enums.
/// </summary>
/// <typeparam name="T">Enum type</typeparam>
/// <param name="n">Number of dimensions</param>
/// <param name="cons">Cast function which converts ushort value to enum value</param>
/// <returns>The desired representation as <![CDATA[IReadOnlyList<...IReadOnlyList<T>>]]></returns>
/// <exception cref="ArgumentNullException"><paramref name="cons"/> is null.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is less than or equals 0.</exception>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public object CastEnumsND < T > ( int n , Func < ushort , T > cons ) = > CastND ( n , ld = > ld . CastEnums ( cons ) ) ;
/// <summary>
/// Represents this list as n-dimensional List(...List(Void))
/// </summary>
/// <param name="n">Number of dimensions</param>
/// <returns>The desired representation as <![CDATA[IReadOnlyList<...IReadOnlyList<T>>]]></returns>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="n"/> is less than or equals 0</exception>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public object CastVoidND ( int n ) = > CastND ( n , ( ListDeserializer ld ) = > ld . Count ) ;
/// <summary>
/// Represents this list as "matrix" (jagged array) with primitive element type.
/// </summary>
/// <typeparam name="T">Element type, must be primitive</typeparam>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public IReadOnlyList < IReadOnlyList < T > > Cast2D < T > ( )
{
2020-03-01 17:56:14 +01:00
GenericCasts < IReadOnlyList < T > > . GetCastFunc ( ) ; // Probe to avoid lazy NotSupportedException
2019-06-12 21:56:55 +02:00
return CastList ( ) . LazyListSelect ( ld = > ld . Cast < IReadOnlyList < T > > ( ) ) ;
}
/// <summary>
/// Represents this list as List(Data).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public IReadOnlyList < IReadOnlyList < byte > > CastData ( ) = > Cast2D < byte > ( ) ;
/// <summary>
/// Represents this list as "matrix" (jagged array) with complex element type.
/// </summary>
/// <typeparam name="T">Element type</typeparam>
/// <param name="cons">Selector function which constructs an instance of <typeparamref name="T"/> from a <see cref="DeserializerState"/></param>
/// <returns>The desired representation</returns>
/// <exception cref="ArgumentNullException"><paramref name="cons"/> is null.</exception>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public IReadOnlyList < IReadOnlyList < T > > Cast2D < T > ( Func < DeserializerState , T > cons )
{
return CastList ( ) . LazyListSelect ( ld = > ld . Cast ( cons ) ) ;
}
/// <summary>
/// Represents this list as "matrix" (jagged array) of enum-typed elements.
/// </summary>
/// <typeparam name="T">Enum type</typeparam>
/// <param name="cons">Cast function which converts ushort value to enum value</param>
/// <returns>The desired representation</returns>
/// <exception cref="ArgumentNullException"><paramref name="cons"/> is null.</exception>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public IReadOnlyList < IReadOnlyList < T > > CastEnums2D < T > ( Func < ushort , T > cons )
{
return CastList ( ) . LazyListSelect ( ld = > ld . CastEnums ( cons ) ) ;
}
/// <summary>
/// Represents this list as 3-dimensional jagged array with primitive element type.
/// </summary>
/// <typeparam name="T">Element type, must be primitive</typeparam>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public IReadOnlyList < IReadOnlyList < IReadOnlyList < T > > > Cast3D < T > ( )
{
return CastList ( ) . LazyListSelect ( ld = > ld . Cast2D < T > ( ) ) ;
}
/// <summary>
/// Represents this list as 3-dimensional jagged array with complex element type.
/// </summary>
/// <typeparam name="T">Element type</typeparam>
/// <param name="cons">Selector function which constructs an instance of <typeparamref name="T"/> from a <see cref="DeserializerState"/></param>
/// <returns>The desired representation</returns>
/// <exception cref="ArgumentNullException"><paramref name="cons"/> is null.</exception>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public IReadOnlyList < IReadOnlyList < IReadOnlyList < T > > > Cast3D < T > ( Func < DeserializerState , T > cons )
{
return CastList ( ) . LazyListSelect ( ld = > ld . Cast2D ( cons ) ) ;
}
/// <summary>
/// Represents this list as 3-dimensional jagged array of enum-typed elements.
/// </summary>
/// <typeparam name="T">Enum type</typeparam>
/// <param name="cons">Cast function which converts ushort value to enum value</param>
/// <returns>The desired representation</returns>
/// <exception cref="ArgumentNullException"><paramref name="cons"/> is null.</exception>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public IReadOnlyList < IReadOnlyList < IReadOnlyList < T > > > CastEnums3D < T > ( Func < ushort , T > cons )
{
return CastList ( ) . LazyListSelect ( ld = > ld . CastEnums2D ( cons ) ) ;
}
/// <summary>
/// Represents this list as list of enum-typed elements.
/// </summary>
/// <typeparam name="T">Enum type</typeparam>
/// <param name="cons">Cast function which converts ushort value to enum value</param>
/// <returns>The desired representation</returns>
/// <exception cref="ArgumentNullException"><paramref name="cons"/> is null.</exception>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public IReadOnlyList < T > CastEnums < T > ( Func < ushort , T > cons )
{
return CastUShort ( ) . LazyListSelect ( cons ) ;
}
/// <summary>
/// Represents this list as List(Void), which boils down to returning the number of elements.
/// </summary>
/// <returns>The List(Void) representation which is nothing but the list's element count.</returns>
public int CastVoid ( ) = > Count ;
/// <summary>
/// Represents this list as List(List(Void)), which boils down to returning a list of element counts.
/// </summary>
/// <returns>A list of integers whereby each number equals the sublist's element count.</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public IReadOnlyList < int > CastVoid2D ( ) = > CastList ( ) . LazyListSelect ( ld = > ld . Count ) ;
/// <summary>
/// Represents this list as List(List(List(Void))).
/// </summary>
/// <returns>The List(List(List(Void))) representation which is in turn a 2-dimensional jagged array of element counts.</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public IReadOnlyList < IReadOnlyList < int > > CastVoid3D ( ) = > CastList ( ) . LazyListSelect ( ld = > ld . CastVoid2D ( ) ) ;
/// <summary>
/// Represents this list as List(Text). For representing it as Text, use <seealso cref="CastText"/>.
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
2020-03-01 13:18:55 +01:00
public IReadOnlyList < string? > CastText2 ( ) = > CastList ( ) . LazyListSelect ( ld = > ld . CastText ( ) ) ;
2019-06-12 21:56:55 +02:00
/// <summary>
/// Represents this list as Text. For representing it as List(Text), use <seealso cref="CastText2"/>.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <returns>The decoded text</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
2020-03-01 13:18:55 +01:00
public virtual string? CastText ( )
2019-06-12 21:56:55 +02:00
{
throw new NotSupportedException ( "This kind of list does not represent text" ) ;
}
/// <summary>
/// Represents this list as List(Bool).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public virtual IReadOnlyList < bool > CastBool ( )
{
return Cast ( sd = > sd . ReadDataBool ( 0 ) ) ;
}
/// <summary>
/// Represents this list as List(Int8).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public virtual IReadOnlyList < sbyte > CastSByte ( )
{
return Cast ( sd = > sd . ReadDataSByte ( 0 ) ) ;
}
/// <summary>
/// Represents this list as List(UInt8).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public virtual IReadOnlyList < byte > CastByte ( )
{
return Cast ( sd = > sd . ReadDataByte ( 0 ) ) ;
}
/// <summary>
/// Represents this list as List(Int16).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public virtual IReadOnlyList < short > CastShort ( )
{
return Cast ( sd = > sd . ReadDataShort ( 0 ) ) ;
}
/// <summary>
/// Represents this list as List(UInt16).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public virtual IReadOnlyList < ushort > CastUShort ( )
{
return Cast ( sd = > sd . ReadDataUShort ( 0 ) ) ;
}
/// <summary>
/// Represents this list as List(Int32).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public virtual IReadOnlyList < int > CastInt ( )
{
return Cast ( sd = > sd . ReadDataInt ( 0 ) ) ;
}
/// <summary>
/// Represents this list as List(UInt32).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public virtual IReadOnlyList < uint > CastUInt ( )
{
return Cast ( sd = > sd . ReadDataUInt ( 0 ) ) ;
}
/// <summary>
/// Represents this list as List(Int64).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
2019-07-12 21:48:01 +02:00
public virtual IReadOnlyList < long > CastLong ( )
2019-06-12 21:56:55 +02:00
{
return Cast ( sd = > sd . ReadDataLong ( 0 ) ) ;
}
/// <summary>
/// Represents this list as List(UInt64).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public virtual IReadOnlyList < ulong > CastULong ( )
{
return Cast ( sd = > sd . ReadDataULong ( 0 ) ) ;
}
/// <summary>
/// Represents this list as List(Float32).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public virtual IReadOnlyList < float > CastFloat ( )
{
return Cast ( sd = > sd . ReadDataFloat ( 0 ) ) ;
}
/// <summary>
/// Represents this list as List(Float64).
/// </summary>
/// <returns>The desired representation</returns>
/// <exception cref="NotSupportedException">If this list cannot be represented in the desired manner.</exception>
public virtual IReadOnlyList < double > CastDouble ( )
{
return Cast ( sd = > sd . ReadDataDouble ( 0 ) ) ;
}
}
2020-01-11 17:56:12 +01:00
}