mirror of
https://github.com/zap-proto/cs.git
synced 2026-10-30 15:05:32 +00:00
Finishes the in-flight capnp→ZAP rebrand on this branch. The prior commits
renamed identifiers/namespaces/files/projects (Capnp.Net.Runtime→Zap.Net.Runtime,
CapnpC→ZapC, .capnp→.zap) but left the human-readable brand name "Cap'n Proto"
throughout doc-comments, .csproj/.nuspec descriptions, README, MSBuild .xaml
rule display names, and the generated XML doc. This completes brand neutrality:
- Replace 154 "Cap'n Proto" / 4 "Cap'n-Proto" / 1 "Cap'n'p" prose occurrences
with "ZAP" across 32 first-party files (runtime, generator, zapc-csharp,
MSBuild integration, chocolatey nuspecs, README, docs, XML doc).
- Revert the LICENSE provenance URL to the real upstream fork
(c80k/capnproto-dotnetcore) — upstream-fork license headers must stay.
- Canonicalize project/repo URLs to github.com/zap-proto/cs (were fabricated
c80k/zap-dotnetcore) in csproj/nuspec/VERIFICATION/README badges.
- Canonicalize docs URLs zap-protocol(.github.io|/zap-cs|/zap-cpp-core)
→ zap-proto.dev / github.com/zap-proto/{cs,cpp-core}.
- Collapse redundant "zap \"ZAP\"" PackageTags to "zap".
Verified consistent (no toolchain on host): every .sln/.csproj ProjectReference
resolves; all namespaces are Zap*/ZapC*; MSBuild task chain
(GenerateZapFileCodeBehindTask, ZapFiles ItemGroup, _ZapcCsharp_TaskAssembly)
is uniformly renamed; props/targets/xaml/coverage/chocolatey carry no capnp.
Deliberately preserved as upstream-derived test data (not first-party source):
upstream Cap'n Proto schema fixtures (rpc.zap, rpc-twoparty.zap, json.zap,
rpc-csharp.zap), golden compiler-error outputs (errors.txt), and the
machine-generated DO-NOT-EDIT test.zap.{c++,h}. Their "Cap'n Proto" strings are
the literal output of the external schema compiler the compat test matches.
188 lines
7.9 KiB
C#
188 lines
7.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace Zap
|
|
{
|
|
/// <summary>
|
|
/// Provides functionality to construct domain objects from <see cref="DeserializerState"/>.
|
|
/// </summary>
|
|
public static class ZapSerializable
|
|
{
|
|
interface IConstructibleFromDeserializerState
|
|
{
|
|
object? Create(DeserializerState state);
|
|
}
|
|
|
|
class FromStruct<T>: IConstructibleFromDeserializerState
|
|
where T : IZapSerializable, new()
|
|
{
|
|
public object Create(DeserializerState state)
|
|
{
|
|
var result = new T();
|
|
if (state.Kind != ObjectKind.Nil)
|
|
{
|
|
result.Deserialize(state);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
class FromList<T>: IConstructibleFromDeserializerState
|
|
where T: class
|
|
{
|
|
readonly Func<DeserializerState, T> _elementSerializer;
|
|
|
|
public FromList()
|
|
{
|
|
var deser = GetSerializer(typeof(T));
|
|
_elementSerializer = d => (deser(d) as T)!;
|
|
|
|
}
|
|
public object Create(DeserializerState state)
|
|
{
|
|
return state.RequireList().Cast(_elementSerializer);
|
|
}
|
|
}
|
|
|
|
class FromCapability<T>: IConstructibleFromDeserializerState
|
|
where T: class
|
|
{
|
|
public object? Create(DeserializerState state)
|
|
{
|
|
return state.RequireCap<T>();
|
|
}
|
|
}
|
|
|
|
static object? CreateFromAny(DeserializerState state)
|
|
{
|
|
switch (state.Kind)
|
|
{
|
|
case ObjectKind.Capability: return state.RequireCap<Rpc.BareProxy>();
|
|
case ObjectKind.Nil: return null;
|
|
default: return state;
|
|
}
|
|
}
|
|
|
|
static readonly ConditionalWeakTable<Type, Func<DeserializerState, object?>> _typeMap =
|
|
new ConditionalWeakTable<Type, Func<DeserializerState, object?>>();
|
|
|
|
static ZapSerializable()
|
|
{
|
|
_typeMap.Add(typeof(object), CreateFromAny);
|
|
_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(IZapSerializable).IsAssignableFrom(type))
|
|
{
|
|
try
|
|
{
|
|
return ((IConstructibleFromDeserializerState)
|
|
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)
|
|
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)
|
|
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="IZapSerializable"/>. 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>IReadOnlyList<bool>, IReadOnlyList<sbyte>, IReadOnlyList<byte></description></item>
|
|
/// <item><description>IReadOnlyList<short>, IReadOnlyList<ushort>, IReadOnlyList<int></description></item>
|
|
/// <item><description>IReadOnlyList<uint>, IReadOnlyList<long>, IReadOnlyList<ulong></description></item>
|
|
/// <item><description>IReadOnlyList<float>, IReadOnlyList<double></description></item>
|
|
/// <item><description>IReadOnlyList<T> whereby T is one of the things listed here.</description></item>
|
|
/// </list>
|
|
/// </typeparam>
|
|
/// <param name="state">deserializer state to construct from</param>
|
|
/// <returns>The domain object instance. Nullability note: The returned reference may be null if
|
|
/// <paramref name="state"/> represents the nil object.</returns>
|
|
/// <exception cref="ArgumentException">Cannot construct object of type <typeparamref name="T"/></exception>
|
|
/// <remarks>Note that capability ownership is moved to the domain object</remarks>
|
|
public static T? Create<T>(DeserializerState state)
|
|
where T: class
|
|
{
|
|
try
|
|
{
|
|
return (T?)GetSerializer(typeof(T))(state);
|
|
}
|
|
catch (TargetInvocationException ex)
|
|
{
|
|
throw new ArgumentException("Failed to construct domain object", ex);
|
|
}
|
|
}
|
|
}
|
|
} |