mirror of
https://github.com/FabInfra/capnproto-dotnetcore_Runtime.git
synced 2025-03-12 23:01:44 +01:00
174 lines
7.5 KiB
C#
174 lines
7.5 KiB
C#
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Reflection;
|
|||
|
using System.Runtime.CompilerServices;
|
|||
|
|
|||
|
namespace Capnp
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// Provides functionality to construct domain objects from <see cref="DeserializerState"/>.
|
|||
|
/// </summary>
|
|||
|
public static class CapnpSerializable
|
|||
|
{
|
|||
|
interface IConstructibleFromDeserializerState<out T>
|
|||
|
{
|
|||
|
T Create(DeserializerState state);
|
|||
|
}
|
|||
|
|
|||
|
class FromStruct<T>: IConstructibleFromDeserializerState<T>
|
|||
|
where T : ICapnpSerializable, new()
|
|||
|
{
|
|||
|
public T Create(DeserializerState state)
|
|||
|
{
|
|||
|
var result = new T();
|
|||
|
if (state.Kind != ObjectKind.Nil)
|
|||
|
{
|
|||
|
result.Deserialize(state);
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class FromList<T>: IConstructibleFromDeserializerState<IReadOnlyList<T>>
|
|||
|
where T: class
|
|||
|
{
|
|||
|
readonly Func<DeserializerState, T> _elementSerializer;
|
|||
|
|
|||
|
public FromList()
|
|||
|
{
|
|||
|
_elementSerializer = (Func<DeserializerState, T>)GetSerializer(typeof(T));
|
|||
|
|
|||
|
}
|
|||
|
public IReadOnlyList<T> Create(DeserializerState state)
|
|||
|
{
|
|||
|
return state.RequireList().Cast(_elementSerializer);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class FromCapability<T>: IConstructibleFromDeserializerState<T>
|
|||
|
where T: class
|
|||
|
{
|
|||
|
public T Create(DeserializerState state)
|
|||
|
{
|
|||
|
return state.RequireCap<T>();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static readonly ConditionalWeakTable<Type, Func<DeserializerState, object>> _typeMap =
|
|||
|
new ConditionalWeakTable<Type, Func<DeserializerState, object>>();
|
|||
|
|
|||
|
static CapnpSerializable()
|
|||
|
{
|
|||
|
_typeMap.Add(typeof(string), d => d.RequireList().CastText());
|
|||
|
_typeMap.Add(typeof(IReadOnlyList<bool>), d => d.RequireList().CastBool());
|
|||
|
_typeMap.Add(typeof(IReadOnlyList<sbyte>), d => d.RequireList().CastSByte());
|
|||
|
_typeMap.Add(typeof(IReadOnlyList<byte>), d => d.RequireList().CastByte());
|
|||
|
_typeMap.Add(typeof(IReadOnlyList<short>), d => d.RequireList().CastShort());
|
|||
|
_typeMap.Add(typeof(IReadOnlyList<ushort>), d => d.RequireList().CastUShort());
|
|||
|
_typeMap.Add(typeof(IReadOnlyList<int>), d => d.RequireList().CastInt());
|
|||
|
_typeMap.Add(typeof(IReadOnlyList<uint>), d => d.RequireList().CastUInt());
|
|||
|
_typeMap.Add(typeof(IReadOnlyList<long>), d => d.RequireList().CastLong());
|
|||
|
_typeMap.Add(typeof(IReadOnlyList<ulong>), d => d.RequireList().CastULong());
|
|||
|
_typeMap.Add(typeof(IReadOnlyList<float>), d => d.RequireList().CastFloat());
|
|||
|
_typeMap.Add(typeof(IReadOnlyList<double>), d => d.RequireList().CastDouble());
|
|||
|
}
|
|||
|
|
|||
|
static Func<DeserializerState, object> CreateSerializer(Type type)
|
|||
|
{
|
|||
|
if (typeof(ICapnpSerializable).IsAssignableFrom(type))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
return ((IConstructibleFromDeserializerState<object>)
|
|||
|
Activator.CreateInstance(typeof(FromStruct<>).MakeGenericType(type))).Create;
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
throw new ArgumentException(
|
|||
|
$"Cannot create serializer, probably because serializer {type.Name} does not expose a public parameterless constructor",
|
|||
|
ex);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (type.IsGenericType && typeof(IReadOnlyList<>) == type.GetGenericTypeDefinition())
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
var elementType = type.GetGenericArguments()[0];
|
|||
|
return ((IConstructibleFromDeserializerState<object>)
|
|||
|
Activator.CreateInstance(typeof(FromList<>).MakeGenericType(elementType))).Create;
|
|||
|
}
|
|||
|
catch (TargetInvocationException ex)
|
|||
|
{
|
|||
|
throw ex.InnerException;
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
throw new ArgumentException(
|
|||
|
$"Cannot create list serializer, probably because the element type is not a reference type",
|
|||
|
ex);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
Rpc.CapabilityReflection.ValidateCapabilityInterface(type);
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
throw new ArgumentException(
|
|||
|
$"Don't know how to construct a serializer from {type.Name}. Tried to interpret it as capability interface, but it didn't work.",
|
|||
|
ex);
|
|||
|
}
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
return ((IConstructibleFromDeserializerState<object>)
|
|||
|
Activator.CreateInstance(typeof(FromCapability<>).MakeGenericType(type))).Create;
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
throw new ArgumentException(
|
|||
|
$"Cannot create serializer, probably because serializer {type.Name} a not a viable capability interface",
|
|||
|
ex);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static Func<DeserializerState, object> GetSerializer(Type type)
|
|||
|
{
|
|||
|
return _typeMap.GetValue(type, CreateSerializer);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Constructs a domain object from a given deserializer state.
|
|||
|
/// </summary>
|
|||
|
/// <typeparam name="T">Type of domain object to construct. Must be one of the following:
|
|||
|
/// <list type="bullet">
|
|||
|
/// <item><description>Type implementing <see cref="ICapnpSerializable"/>. The type must must have a public parameterless constructor.</description></item>
|
|||
|
/// <item><description>A capability interface (<seealso cref="Rpc.InvalidCapabilityInterfaceException"/> for further explanation)</description></item>
|
|||
|
/// <item><description><see cref="String"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{Boolean}"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{SByte}"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{Byte}"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{Int16}"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{UInt16}"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{Int32}"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{UInt32}"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{Int64}"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{UInt64}"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{Single}"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{Double}"/></description></item>
|
|||
|
/// <item><description><see cref="IReadOnlyList{T}"/> whereby T is one of the things listed here.</description></item>
|
|||
|
/// </list>
|
|||
|
/// </typeparam>
|
|||
|
/// <param name="state"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public static T Create<T>(DeserializerState state)
|
|||
|
where T: class
|
|||
|
{
|
|||
|
return (T)GetSerializer(typeof(T))(state);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|