mirror of
https://github.com/FabInfra/capnproto-dotnetcore_Runtime.git
synced 2025-03-12 23:01:44 +01:00
more fixes, more coverage
This commit is contained in:
parent
2369b4788a
commit
20c8523aae
@ -378,6 +378,10 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
var mb = MessageBuilder.Create();
|
var mb = MessageBuilder.Create();
|
||||||
var root = mb.BuildRoot<TW>();
|
var root = mb.BuildRoot<TW>();
|
||||||
obj.Serialize(root);
|
obj.Serialize(root);
|
||||||
|
using (var tr = new FrameTracing.RpcFrameTracer(Console.Out))
|
||||||
|
{
|
||||||
|
tr.TraceFrame(FrameTracing.FrameDirection.Tx, mb.Frame);
|
||||||
|
}
|
||||||
var d = (DeserializerState)root;
|
var d = (DeserializerState)root;
|
||||||
var obj2 = new TD();
|
var obj2 = new TD();
|
||||||
obj2.Deserialize(d);
|
obj2.Deserialize(d);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Capnp.Net.Runtime.Tests.GenImpls;
|
using Capnp.Net.Runtime.Tests.GenImpls;
|
||||||
|
using Capnp.Rpc;
|
||||||
using Capnproto_test.Capnp.Test;
|
using Capnproto_test.Capnp.Test;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using System;
|
using System;
|
||||||
@ -229,7 +230,7 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ListOfStructs()
|
public void ListOfStructs1()
|
||||||
{
|
{
|
||||||
var b = MessageBuilder.Create();
|
var b = MessageBuilder.Create();
|
||||||
var list = b.CreateObject<ListOfStructsSerializer<SomeStruct.WRITER>>();
|
var list = b.CreateObject<ListOfStructsSerializer<SomeStruct.WRITER>>();
|
||||||
@ -259,6 +260,19 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
Assert.AreEqual("3", list3[3].SomeText);
|
Assert.AreEqual("3", list3[3].SomeText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ListOfStructs2()
|
||||||
|
{
|
||||||
|
var b = MessageBuilder.Create();
|
||||||
|
var list = b.CreateObject<DynamicSerializerState>();
|
||||||
|
list.SetListOfStructs(3, 4, 5);
|
||||||
|
list.SetListOfStructs(3, 4, 5);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => list.SetListOfStructs(1, 4, 5));
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => list.SetListOfStructs(3, 1, 5));
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => list.SetListOfStructs(3, 4, 1));
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => list.StructWriteData(0, 1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void ListOfText()
|
public void ListOfText()
|
||||||
{
|
{
|
||||||
@ -741,5 +755,171 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
Assert.ThrowsException<IndexOutOfRangeException>(() => { var _ = list[0]; });
|
Assert.ThrowsException<IndexOutOfRangeException>(() => { var _ = list[0]; });
|
||||||
Assert.AreEqual(0, list.ToArray().Length);
|
Assert.AreEqual(0, list.ToArray().Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestSerializerStateStruct11 : SerializerState
|
||||||
|
{
|
||||||
|
public TestSerializerStateStruct11()
|
||||||
|
{
|
||||||
|
SetStruct(1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSerializerStateStruct20 : SerializerState
|
||||||
|
{
|
||||||
|
public TestSerializerStateStruct20()
|
||||||
|
{
|
||||||
|
SetStruct(2, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestSerializerStateStruct11X : SerializerState
|
||||||
|
{
|
||||||
|
public TestSerializerStateStruct11X()
|
||||||
|
{
|
||||||
|
SetStruct(1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SerializerStateInvalidRewrap1()
|
||||||
|
{
|
||||||
|
var dss = new DynamicSerializerState(MessageBuilder.Create());
|
||||||
|
dss.SetListOfValues(8, 1);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.Rewrap<TestSerializerStateStruct11>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SerializerStateInvalidRewrap2()
|
||||||
|
{
|
||||||
|
var dss = new DynamicSerializerState();
|
||||||
|
dss.SetStruct(1, 0);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.Rewrap<TestSerializerStateStruct11>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SerializerStateInvalidRewrap3()
|
||||||
|
{
|
||||||
|
var dss = new DynamicSerializerState();
|
||||||
|
dss.SetStruct(0, 1);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.Rewrap<TestSerializerStateStruct11>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SerializerStateInvalidRewrap4()
|
||||||
|
{
|
||||||
|
var dss = new DynamicSerializerState();
|
||||||
|
dss.SetStruct(1, 0);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.Rewrap<ListOfTextSerializer>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void UnboundSerializerState()
|
||||||
|
{
|
||||||
|
var dss = new DynamicSerializerState();
|
||||||
|
dss.SetStruct(1, 0);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.WriteData(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LinkBadUsage1()
|
||||||
|
{
|
||||||
|
var mb = MessageBuilder.Create();
|
||||||
|
var dss = mb.CreateObject<DynamicSerializerState>();
|
||||||
|
dss.SetStruct(0, 1);
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => dss.Link(0, null));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => dss.Link(-1, dss));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => dss.Link(1, dss));
|
||||||
|
dss.Link(0, dss);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.Link(0, mb.CreateObject<DynamicSerializerState>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void LinkBadUsage2()
|
||||||
|
{
|
||||||
|
var dss = new DynamicSerializerState(MessageBuilder.Create());
|
||||||
|
dss.SetListOfPointers(1);
|
||||||
|
Assert.ThrowsException<ArgumentNullException>(() => dss.Link(0, null));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => dss.Link(-1, dss));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => dss.Link(1, dss));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void StructReadCapNoCapTable()
|
||||||
|
{
|
||||||
|
var dss = new DynamicSerializerState(MessageBuilder.Create());
|
||||||
|
dss.SetStruct(0, 1);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.ReadCap(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void StructReadCap()
|
||||||
|
{
|
||||||
|
var dss = DynamicSerializerState.CreateForRpc();
|
||||||
|
dss.SetStruct(0, 3);
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => dss.ReadCap(-1));
|
||||||
|
Assert.ThrowsException<ArgumentOutOfRangeException>(() => dss.ReadCap(100));
|
||||||
|
Assert.IsTrue(dss.ReadCap(0).IsNull);
|
||||||
|
dss.LinkToCapability(1, 99);
|
||||||
|
dss.Link(2, dss);
|
||||||
|
dss.Allocate();
|
||||||
|
Assert.IsTrue(dss.ReadCap(0).IsNull);
|
||||||
|
Assert.IsTrue(dss.ReadCap<ITestCallOrder>(0) is Proxy proxy && proxy.IsNull);
|
||||||
|
Assert.ThrowsException<Rpc.RpcException>(() => dss.ReadCap(1));
|
||||||
|
Assert.ThrowsException<Rpc.RpcException>(() => dss.ReadCap(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Rewrap()
|
||||||
|
{
|
||||||
|
var mb = MessageBuilder.Create();
|
||||||
|
var list1 = mb.CreateObject<ListOfStructsSerializer<TestSerializerStateStruct11>>();
|
||||||
|
list1.Init(3);
|
||||||
|
var list2 = list1.Rewrap<ListOfStructsSerializer<TestSerializerStateStruct11X>>();
|
||||||
|
list2[0].WriteData(0, 0);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => list2.Rewrap<TestSerializerStateStruct11>());
|
||||||
|
var obj = mb.CreateObject<TestSerializerStateStruct11>();
|
||||||
|
var obj2 = obj.Rewrap<TestSerializerStateStruct11X>();
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => obj2.Rewrap<TestSerializerStateStruct20>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AllocatedNil()
|
||||||
|
{
|
||||||
|
var mb = MessageBuilder.Create();
|
||||||
|
mb.InitCapTable();
|
||||||
|
var dss = mb.CreateObject<DynamicSerializerState>();
|
||||||
|
dss.Allocate();
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.SetCapability(0));
|
||||||
|
dss.SetCapability(null);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.SetListOfPointers(1));
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.SetListOfStructs(1, 1, 1));
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.SetListOfValues(8, 1));
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.SetObject(mb.CreateObject<TestSerializerStateStruct11>()));
|
||||||
|
dss.SetObject(null);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.SetStruct(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SetCapability1()
|
||||||
|
{
|
||||||
|
var mb = MessageBuilder.Create();
|
||||||
|
mb.InitCapTable();
|
||||||
|
var dss = mb.CreateObject<DynamicSerializerState>();
|
||||||
|
dss.SetStruct(1, 1);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.SetCapability(null));
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.SetCapability(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SetCapability2()
|
||||||
|
{
|
||||||
|
var mb = MessageBuilder.Create();
|
||||||
|
mb.InitCapTable();
|
||||||
|
var dss = mb.CreateObject<DynamicSerializerState>();
|
||||||
|
dss.SetCapability(7);
|
||||||
|
dss.SetCapability(7);
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.SetCapability(8));
|
||||||
|
Assert.ThrowsException<InvalidOperationException>(() => dss.SetCapability(null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -571,12 +571,12 @@ namespace Capnp.Net.Runtime.Tests
|
|||||||
task1.Result.Dispose();
|
task1.Result.Dispose();
|
||||||
|
|
||||||
testbed.FlushCommunication();
|
testbed.FlushCommunication();
|
||||||
Assert.AreEqual(1, counters.HandleCount);
|
Assert.IsTrue(SpinWait.SpinUntil(() => counters.HandleCount == 1, TestBase.ShortTimeout));
|
||||||
|
|
||||||
task2.Result.Dispose();
|
task2.Result.Dispose();
|
||||||
|
|
||||||
testbed.FlushCommunication();
|
testbed.FlushCommunication();
|
||||||
Assert.AreEqual(0, counters.HandleCount);
|
Assert.IsTrue(SpinWait.SpinUntil(() => counters.HandleCount == 0, TestBase.ShortTimeout));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace Capnp
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The capabilities imported from the capability table. Only valid in RPC context.
|
/// The capabilities imported from the capability table. Only valid in RPC context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IList<Rpc.ConsumedCapability?>? Caps { get; set; }
|
public IList<Rpc.ConsumedCapability>? Caps { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current segment (essentially Segments[CurrentSegmentIndex])
|
/// Current segment (essentially Segments[CurrentSegmentIndex])
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -79,7 +79,7 @@ namespace Capnp
|
|||||||
/// <item><description>This state does neither describe a struct, nor a list of pointers</description></item>
|
/// <item><description>This state does neither describe a struct, nor a list of pointers</description></item>
|
||||||
/// <item><description>Another state is already linked to the specified position (sorry, no overwrite allowed)</description></item></list>
|
/// <item><description>Another state is already linked to the specified position (sorry, no overwrite allowed)</description></item></list>
|
||||||
/// </exception>
|
/// </exception>
|
||||||
public new void LinkToCapability(int slot, uint capabilityIndex) => base.LinkToCapability(slot, capabilityIndex);
|
public new void LinkToCapability(int slot, uint? capabilityIndex) => base.LinkToCapability(slot, capabilityIndex);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the underlying object to be a struct.
|
/// Determines the underlying object to be a struct.
|
||||||
@ -89,6 +89,8 @@ namespace Capnp
|
|||||||
/// <exception cref="InvalidOperationException">The object type was already set to something different</exception>
|
/// <exception cref="InvalidOperationException">The object type was already set to something different</exception>
|
||||||
public new void SetStruct(ushort dataCount, ushort ptrCount) => base.SetStruct(dataCount, ptrCount);
|
public new void SetStruct(ushort dataCount, ushort ptrCount) => base.SetStruct(dataCount, ptrCount);
|
||||||
|
|
||||||
|
public new void SetCapability(uint? capabilityIndex) => base.SetCapability(capabilityIndex);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the underlying object to be a list of (primitive) values.
|
/// Determines the underlying object to be a list of (primitive) values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -10,7 +10,7 @@ namespace Capnp
|
|||||||
{
|
{
|
||||||
readonly ISegmentAllocator _allocator;
|
readonly ISegmentAllocator _allocator;
|
||||||
readonly DynamicSerializerState _rootPtrBuilder;
|
readonly DynamicSerializerState _rootPtrBuilder;
|
||||||
List<Rpc.ConsumedCapability?>? _capTable;
|
List<Rpc.ConsumedCapability>? _capTable;
|
||||||
|
|
||||||
MessageBuilder(ISegmentAllocator allocator)
|
MessageBuilder(ISegmentAllocator allocator)
|
||||||
{
|
{
|
||||||
@ -92,13 +92,13 @@ namespace Capnp
|
|||||||
if (_capTable != null)
|
if (_capTable != null)
|
||||||
throw new InvalidOperationException("Capability table was already initialized");
|
throw new InvalidOperationException("Capability table was already initialized");
|
||||||
|
|
||||||
_capTable = new List<Rpc.ConsumedCapability?>();
|
_capTable = new List<Rpc.ConsumedCapability>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns this message builder's segment allocator.
|
/// Returns this message builder's segment allocator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ISegmentAllocator Allocator => _allocator;
|
public ISegmentAllocator Allocator => _allocator;
|
||||||
internal List<Rpc.ConsumedCapability?>? Caps => _capTable;
|
internal List<Rpc.ConsumedCapability>? Caps => _capTable;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -180,7 +180,7 @@ namespace Capnp.Rpc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<TInterface> Unwrap<TInterface>(this TInterface cap) where TInterface: class, IDisposable
|
public static async Task<TInterface?> Unwrap<TInterface>(this TInterface cap) where TInterface: class, IDisposable
|
||||||
{
|
{
|
||||||
using var proxy = cap as Proxy;
|
using var proxy = cap as Proxy;
|
||||||
|
|
||||||
@ -188,6 +188,9 @@ namespace Capnp.Rpc
|
|||||||
return cap;
|
return cap;
|
||||||
|
|
||||||
var unwrapped = await proxy.ConsumedCap.Unwrap();
|
var unwrapped = await proxy.ConsumedCap.Unwrap();
|
||||||
|
if (unwrapped == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
return ((CapabilityReflection.CreateProxy<TInterface>(unwrapped)) as TInterface)!;
|
return ((CapabilityReflection.CreateProxy<TInterface>(unwrapped)) as TInterface)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,8 +16,6 @@ namespace Capnp.Rpc
|
|||||||
return new LazyCapability(Task.FromCanceled<ConsumedCapability?>(token));
|
return new LazyCapability(Task.FromCanceled<ConsumedCapability?>(token));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LazyCapability Null => CreateBrokenCap("Null capability");
|
|
||||||
|
|
||||||
readonly Task<Proxy>? _proxyTask;
|
readonly Task<Proxy>? _proxyTask;
|
||||||
|
|
||||||
public LazyCapability(Task<ConsumedCapability?> capabilityTask)
|
public LazyCapability(Task<ConsumedCapability?> capabilityTask)
|
||||||
|
@ -108,7 +108,7 @@ namespace Capnp.Rpc
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var cap = aorcq.Answer.Caps![(int)cur.CapabilityIndex];
|
var cap = aorcq.Answer.Caps![(int)cur.CapabilityIndex];
|
||||||
proxy = new Proxy(cap ?? LazyCapability.Null);
|
proxy = new Proxy(cap);
|
||||||
}
|
}
|
||||||
catch (ArgumentOutOfRangeException)
|
catch (ArgumentOutOfRangeException)
|
||||||
{
|
{
|
||||||
|
@ -197,16 +197,13 @@ namespace Capnp.Rpc
|
|||||||
/// <param name="disposeThis">Whether to Dispose() this Proxy instance</param>
|
/// <param name="disposeThis">Whether to Dispose() this Proxy instance</param>
|
||||||
/// <returns>Proxy for desired capability interface</returns>
|
/// <returns>Proxy for desired capability interface</returns>
|
||||||
/// <exception cref="InvalidCapabilityInterfaceException"><typeparamref name="T"/> did not qualify as capability interface.</exception>
|
/// <exception cref="InvalidCapabilityInterfaceException"><typeparamref name="T"/> did not qualify as capability interface.</exception>
|
||||||
/// <exception cref="InvalidOperationException">This capability is broken, or mismatch between generic type arguments (if capability interface is generic).</exception>
|
/// <exception cref="InvalidOperationException">Mismatch between generic type arguments (if capability interface is generic).</exception>
|
||||||
/// <exception cref="ArgumentException">Mismatch between generic type arguments (if capability interface is generic).</exception>
|
/// <exception cref="ArgumentException">Mismatch between generic type arguments (if capability interface is generic).</exception>
|
||||||
/// <exception cref="System.Reflection.TargetInvocationException">Problem with instatiating the Proxy (constructor threw exception).</exception>
|
/// <exception cref="System.Reflection.TargetInvocationException">Problem with instatiating the Proxy (constructor threw exception).</exception>
|
||||||
/// <exception cref="MemberAccessException">Caller does not have permission to invoke the Proxy constructor.</exception>
|
/// <exception cref="MemberAccessException">Caller does not have permission to invoke the Proxy constructor.</exception>
|
||||||
/// <exception cref="TypeLoadException">Problem with building the Proxy type, or problem with loading some dependent class.</exception>
|
/// <exception cref="TypeLoadException">Problem with building the Proxy type, or problem with loading some dependent class.</exception>
|
||||||
public T Cast<T>(bool disposeThis) where T: class
|
public T Cast<T>(bool disposeThis) where T: class
|
||||||
{
|
{
|
||||||
if (IsNull)
|
|
||||||
throw new InvalidOperationException("Capability is broken");
|
|
||||||
|
|
||||||
using (disposeThis ? this : null)
|
using (disposeThis ? this : null)
|
||||||
{
|
{
|
||||||
return (CapabilityReflection.CreateProxy<T>(ConsumedCap) as T)!;
|
return (CapabilityReflection.CreateProxy<T>(ConsumedCap) as T)!;
|
||||||
|
@ -5,13 +5,11 @@ namespace Capnp.Rpc
|
|||||||
{
|
{
|
||||||
static class ResolvingCapabilityExtensions
|
static class ResolvingCapabilityExtensions
|
||||||
{
|
{
|
||||||
public static async Task<ConsumedCapability> Unwrap(this ConsumedCapability? cap)
|
public static async Task<ConsumedCapability?> Unwrap(this ConsumedCapability? cap)
|
||||||
{
|
{
|
||||||
cap ??= LazyCapability.Null;
|
|
||||||
|
|
||||||
while (cap is IResolvingCapability resolving)
|
while (cap is IResolvingCapability resolving)
|
||||||
{
|
{
|
||||||
cap = await resolving.WhenResolved ?? LazyCapability.Null;
|
cap = await resolving.WhenResolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cap;
|
return cap;
|
||||||
@ -66,7 +64,7 @@ namespace Capnp.Rpc
|
|||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
case Proxy proxy: return proxy;
|
case Proxy proxy: return proxy;
|
||||||
case null: return new Proxy(LazyCapability.Null);
|
case null: return new Proxy(null);
|
||||||
default: return BareProxy.FromImpl(obj);
|
default: return BareProxy.FromImpl(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1347,9 +1347,9 @@ namespace Capnp.Rpc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IList<ConsumedCapability?> ImportCapTable(Payload.READER payload)
|
internal IList<ConsumedCapability> ImportCapTable(Payload.READER payload)
|
||||||
{
|
{
|
||||||
var list = new List<ConsumedCapability?>();
|
var list = new List<ConsumedCapability>();
|
||||||
|
|
||||||
if (payload.CapTable != null)
|
if (payload.CapTable != null)
|
||||||
{
|
{
|
||||||
@ -1378,17 +1378,9 @@ namespace Capnp.Rpc
|
|||||||
foreach (var cap in state.MsgBuilder.Caps)
|
foreach (var cap in state.MsgBuilder.Caps)
|
||||||
{
|
{
|
||||||
var capDesc = payload.CapTable[i++];
|
var capDesc = payload.CapTable[i++];
|
||||||
|
|
||||||
if (cap == null)
|
|
||||||
{
|
|
||||||
LazyCapability.Null.Export(this, capDesc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
postAction += cap.Export(this, capDesc);
|
postAction += cap.Export(this, capDesc);
|
||||||
cap.Release();
|
cap.Release();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Tx(state.MsgBuilder.Frame);
|
Tx(state.MsgBuilder.Frame);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ namespace Capnp.Rpc
|
|||||||
{
|
{
|
||||||
class Vine : Skeleton
|
class Vine : Skeleton
|
||||||
{
|
{
|
||||||
public static Skeleton Create(ConsumedCapability cap)
|
public static Skeleton Create(ConsumedCapability? cap)
|
||||||
{
|
{
|
||||||
if (cap is LocalCapability lcap)
|
if (cap is LocalCapability lcap)
|
||||||
return lcap.ProvidedCap;
|
return lcap.ProvidedCap;
|
||||||
@ -15,9 +15,9 @@ namespace Capnp.Rpc
|
|||||||
return new Vine(cap);
|
return new Vine(cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vine(ConsumedCapability consumedCap)
|
Vine(ConsumedCapability? consumedCap)
|
||||||
{
|
{
|
||||||
Proxy = new Proxy(consumedCap ?? throw new ArgumentNullException(nameof(consumedCap)));
|
Proxy = new Proxy(consumedCap);
|
||||||
|
|
||||||
#if DebugFinalizers
|
#if DebugFinalizers
|
||||||
CreatorStackTrace = Environment.StackTrace;
|
CreatorStackTrace = Environment.StackTrace;
|
||||||
|
@ -30,7 +30,7 @@ namespace Capnp
|
|||||||
|
|
||||||
internal MessageBuilder? MsgBuilder { get; set; }
|
internal MessageBuilder? MsgBuilder { get; set; }
|
||||||
internal ISegmentAllocator? Allocator => MsgBuilder?.Allocator;
|
internal ISegmentAllocator? Allocator => MsgBuilder?.Allocator;
|
||||||
internal List<Rpc.ConsumedCapability?>? Caps => MsgBuilder?.Caps;
|
internal List<Rpc.ConsumedCapability>? Caps => MsgBuilder?.Caps;
|
||||||
internal SerializerState? Owner { get; set; }
|
internal SerializerState? Owner { get; set; }
|
||||||
internal int OwnerSlot { get; set; }
|
internal int OwnerSlot { get; set; }
|
||||||
internal uint SegmentIndex { get; set; }
|
internal uint SegmentIndex { get; set; }
|
||||||
@ -156,7 +156,7 @@ namespace Capnp
|
|||||||
/// Returns the allocated memory slice (given this state already is allocated). Note that this definition is somewhat
|
/// Returns the allocated memory slice (given this state already is allocated). Note that this definition is somewhat
|
||||||
/// non-symmetric to <code>DeserializerState.RawData</code>. Never mind: You should not use it directly, anyway.
|
/// non-symmetric to <code>DeserializerState.RawData</code>. Never mind: You should not use it directly, anyway.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Span<ulong> RawData => SegmentSpan.Slice(Offset, (int)WordsAllocated);
|
public Span<ulong> RawData => IsAllocated ? SegmentSpan.Slice(Offset, (int)WordsAllocated) : Span<ulong>.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The kind of object this state currently represents.
|
/// The kind of object this state currently represents.
|
||||||
@ -170,12 +170,6 @@ namespace Capnp
|
|||||||
SegmentIndex = 0;
|
SegmentIndex = 0;
|
||||||
Offset = 0;
|
Offset = 0;
|
||||||
}
|
}
|
||||||
else if (Owner?.Kind == ObjectKind.ListOfStructs)
|
|
||||||
{
|
|
||||||
Owner.Allocate();
|
|
||||||
SegmentIndex = Owner.SegmentIndex;
|
|
||||||
Offset = Owner.Offset + OwnerSlot + 1;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Allocator == null)
|
if (Allocator == null)
|
||||||
@ -242,25 +236,43 @@ namespace Capnp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void EncodePointer(int offset, SerializerState target, bool allowCopy)
|
internal Rpc.ConsumedCapability? DecodeCapPointer(int offset)
|
||||||
{
|
{
|
||||||
if (target == null)
|
if (Caps == null)
|
||||||
throw new ArgumentNullException(nameof(target));
|
throw new InvalidOperationException("Capbility table not set");
|
||||||
|
|
||||||
if (!target.IsAllocated)
|
if (!IsAllocated)
|
||||||
throw new InvalidOperationException("Target must be allocated before a pointer can be built");
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (MsgBuilder == null)
|
WirePointer pointer = RawData[offset];
|
||||||
throw Unbound();
|
|
||||||
|
|
||||||
try
|
if (pointer.IsNull)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointer.Kind != PointerKind.Other)
|
||||||
|
{
|
||||||
|
throw new Rpc.RpcException(
|
||||||
|
"Expected a capability pointer, but got something different");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointer.CapabilityIndex >= Caps.Count)
|
||||||
|
{
|
||||||
|
throw new Rpc.RpcException(
|
||||||
|
"Capability index out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Caps[(int)pointer.CapabilityIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
void EncodePointer(int offset, SerializerState target, bool allowCopy)
|
||||||
{
|
{
|
||||||
if (SegmentSpan[offset] != 0)
|
if (SegmentSpan[offset] != 0)
|
||||||
throw new InvalidOperationException("Won't replace an already allocated pointer to prevent memory leaks and security flaws");
|
|
||||||
}
|
|
||||||
catch (IndexOutOfRangeException)
|
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
throw new InvalidOperationException("Won't replace an already allocated pointer to prevent memory leaks and security flaws");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.Allocator != null &&
|
if (target.Allocator != null &&
|
||||||
@ -375,31 +387,6 @@ namespace Capnp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Rpc.ConsumedCapability? DecodeCapPointer(int offset)
|
|
||||||
{
|
|
||||||
if (offset < 0)
|
|
||||||
throw new IndexOutOfRangeException(nameof(offset));
|
|
||||||
|
|
||||||
if (Caps == null)
|
|
||||||
throw new InvalidOperationException("Capbility table not set");
|
|
||||||
|
|
||||||
WirePointer pointer = RawData[offset];
|
|
||||||
|
|
||||||
if (pointer.Kind != PointerKind.Other)
|
|
||||||
{
|
|
||||||
throw new Rpc.RpcException(
|
|
||||||
"Expected a capability pointer, but got something different");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pointer.CapabilityIndex >= Caps.Count)
|
|
||||||
{
|
|
||||||
throw new Rpc.RpcException(
|
|
||||||
"Capability index out of range");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Caps[(int)pointer.CapabilityIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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.
|
/// 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).
|
/// However, there might be some advanced scenarios where you want to reference the same object twice (also interesting for designing amplification attacks).
|
||||||
@ -471,7 +458,7 @@ namespace Capnp
|
|||||||
/// <item><description>This state does neither describe a struct, nor a list of pointers</description></item>
|
/// <item><description>This state does neither describe a struct, nor a list of pointers</description></item>
|
||||||
/// <item><description>Another state is already linked to the specified position (sorry, no overwrite allowed)</description></item></list>
|
/// <item><description>Another state is already linked to the specified position (sorry, no overwrite allowed)</description></item></list>
|
||||||
/// </exception>
|
/// </exception>
|
||||||
protected void LinkToCapability(int slot, uint capabilityIndex)
|
protected void LinkToCapability(int slot, uint? capabilityIndex)
|
||||||
{
|
{
|
||||||
var cstate = new SerializerState();
|
var cstate = new SerializerState();
|
||||||
cstate.SetCapability(capabilityIndex);
|
cstate.SetCapability(capabilityIndex);
|
||||||
@ -511,14 +498,16 @@ namespace Capnp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCapability(uint capabilityIndex)
|
protected void SetCapability(uint? capabilityIndex)
|
||||||
|
{
|
||||||
|
if (capabilityIndex.HasValue)
|
||||||
{
|
{
|
||||||
if (Kind == ObjectKind.Nil)
|
if (Kind == ObjectKind.Nil)
|
||||||
{
|
{
|
||||||
VerifyNotYetAllocated();
|
VerifyNotYetAllocated();
|
||||||
|
|
||||||
Kind = ObjectKind.Capability;
|
Kind = ObjectKind.Capability;
|
||||||
CapabilityIndex = capabilityIndex;
|
CapabilityIndex = capabilityIndex.Value;
|
||||||
Allocate();
|
Allocate();
|
||||||
}
|
}
|
||||||
else if (Kind != ObjectKind.Capability || CapabilityIndex != capabilityIndex)
|
else if (Kind != ObjectKind.Capability || CapabilityIndex != capabilityIndex)
|
||||||
@ -526,6 +515,14 @@ namespace Capnp
|
|||||||
throw AlreadySet();
|
throw AlreadySet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Kind != ObjectKind.Nil)
|
||||||
|
{
|
||||||
|
throw AlreadySet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the underlying object to be a list of (primitive) values.
|
/// Determines the underlying object to be a list of (primitive) values.
|
||||||
@ -1225,10 +1222,13 @@ namespace Capnp
|
|||||||
/// Adds an entry to the capability table if the provided capability does not yet exist.
|
/// Adds an entry to the capability table if the provided capability does not yet exist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="capability">The low-level capability object to provide.</param>
|
/// <param name="capability">The low-level capability object to provide.</param>
|
||||||
/// <returns>Index of the given capability in the capability table</returns>
|
/// <returns>Index of the given capability in the capability table, null if capability is null</returns>
|
||||||
/// <exception cref="InvalidOperationException">The underlying message builder was not configured for capability table support.</exception>
|
/// <exception cref="InvalidOperationException">The underlying message builder was not configured for capability table support.</exception>
|
||||||
public uint ProvideCapability(Rpc.ConsumedCapability? capability)
|
public uint? ProvideCapability(Rpc.ConsumedCapability? capability)
|
||||||
{
|
{
|
||||||
|
if (capability == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
if (Caps == null)
|
if (Caps == null)
|
||||||
throw new InvalidOperationException("Underlying MessageBuilder was not enabled to support capabilities");
|
throw new InvalidOperationException("Underlying MessageBuilder was not enabled to support capabilities");
|
||||||
|
|
||||||
@ -1252,7 +1252,7 @@ namespace Capnp
|
|||||||
/// <exception cref="InvalidOperationException">The underlying message builder was not configured for capability table support.</exception>
|
/// <exception cref="InvalidOperationException">The underlying message builder was not configured for capability table support.</exception>
|
||||||
public uint ProvideCapability(Rpc.Skeleton capability)
|
public uint ProvideCapability(Rpc.Skeleton capability)
|
||||||
{
|
{
|
||||||
return ProvideCapability(Rpc.LocalCapability.Create(capability));
|
return ProvideCapability(Rpc.LocalCapability.Create(capability))!.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1267,12 +1267,12 @@ namespace Capnp
|
|||||||
/// </list></param>
|
/// </list></param>
|
||||||
/// <returns>Index of the given capability in the capability table</returns>
|
/// <returns>Index of the given capability in the capability table</returns>
|
||||||
/// <exception cref="InvalidOperationException">The underlying message builder was not configured for capability table support.</exception>
|
/// <exception cref="InvalidOperationException">The underlying message builder was not configured for capability table support.</exception>
|
||||||
public uint ProvideCapability(object? obj)
|
public uint? ProvideCapability(object? obj)
|
||||||
{
|
{
|
||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
case null:
|
case null:
|
||||||
return ProvideCapability(default(Rpc.ConsumedCapability));
|
return null;
|
||||||
case Rpc.Proxy proxy: using (proxy)
|
case Rpc.Proxy proxy: using (proxy)
|
||||||
return ProvideCapability(proxy.ConsumedCap);
|
return ProvideCapability(proxy.ConsumedCap);
|
||||||
case Rpc.ConsumedCapability consumedCapability:
|
case Rpc.ConsumedCapability consumedCapability:
|
||||||
@ -1348,8 +1348,8 @@ namespace Capnp
|
|||||||
if (Kind != ObjectKind.Struct && Kind != ObjectKind.Nil)
|
if (Kind != ObjectKind.Struct && Kind != ObjectKind.Nil)
|
||||||
throw new InvalidOperationException("Allowed on structs only");
|
throw new InvalidOperationException("Allowed on structs only");
|
||||||
|
|
||||||
if (index >= StructPtrCount)
|
if (index < 0 || index >= StructPtrCount)
|
||||||
return null;
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
|
||||||
return DecodeCapPointer(index + StructDataCount);
|
return DecodeCapPointer(index + StructDataCount);
|
||||||
}
|
}
|
||||||
|
@ -219,10 +219,13 @@ namespace Capnp
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encodes a capability pointer.
|
/// Encodes a capability pointer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">capability index</param>
|
/// <param name="index">capability index, 'null' means 'null pointer'</param>
|
||||||
public void SetCapability(uint index)
|
public void SetCapability(uint? index)
|
||||||
{
|
{
|
||||||
|
if (index.HasValue)
|
||||||
_ptrData = ((ulong)index << 32) | (ulong)PointerKind.Other;
|
_ptrData = ((ulong)index << 32) | (ulong)PointerKind.Other;
|
||||||
|
else
|
||||||
|
_ptrData = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user