diff --git a/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj b/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj
index fd9eafd..5eac70b 100644
--- a/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj
+++ b/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj
@@ -34,7 +34,6 @@
-
diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs
index 9ce7fdd..3ea4f63 100644
--- a/Capnp.Net.Runtime.Tests/SerializationTests.cs
+++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs
@@ -1,4 +1,6 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Capnp.Net.Runtime.Tests.GenImpls;
+using Capnproto_test.Capnp.Test;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -32,12 +34,17 @@ namespace Capnp.Net.Runtime.Tests
var b = MessageBuilder.Create();
var list = b.CreateObject();
Assert.ThrowsException(() => list.Init(-1));
+ // Assert.AreEqual(0, list.Count); // Bug or feature? Uninitialized list's Count is -1
+ Assert.ThrowsException(() => { var _ = list[0]; });
+ Assert.ThrowsException(() => { list[0] = false; });
list.Init(130);
list[63] = true;
list[65] = true;
list[66] = true;
list[65] = false;
list[129] = true;
+ Assert.ThrowsException(() => { var _ = list[130]; });
+ Assert.ThrowsException(() => { list[130] = false; });
Assert.IsFalse(list[0]);
Assert.IsTrue(list[63]);
Assert.IsFalse(list[64]);
@@ -59,5 +66,63 @@ namespace Capnp.Net.Runtime.Tests
var list3 = d.RequireList().CastBool();
CheckList(list3);
}
+
+ [TestMethod]
+ public void ListOfCaps()
+ {
+ var b = MessageBuilder.Create();
+ b.InitCapTable();
+ var list = b.CreateObject>();
+ Assert.ThrowsException(() => list.Init(-1));
+ Assert.ThrowsException(() => { var _ = list[0]; });
+ Assert.ThrowsException(() => { list[0] = null; });
+ list.Init(5);
+ Assert.ThrowsException(() => list.Init(1));
+ var c1 = new Counters();
+ var cap1 = new TestInterfaceImpl(c1);
+ var c2 = new Counters();
+ var cap2 = new TestInterfaceImpl(c2);
+ list[0] = null;
+ list[1] = cap1;
+ list[2] = cap2;
+ list[3] = cap1;
+ list[4] = cap2;
+ list[3] = null;
+ Assert.IsTrue(list.All(p => p is Rpc.Proxy));
+ var proxies = list.Cast().ToArray();
+ Assert.IsTrue(proxies[0].IsNull);
+ Assert.IsFalse(proxies[1].IsNull);
+ Assert.IsTrue(proxies[3].IsNull);
+ list[2].Foo(123u, true).Wait();
+ Assert.AreEqual(0, c1.CallCount);
+ Assert.AreEqual(1, c2.CallCount);
+ list[4].Foo(123u, true).Wait();
+ Assert.AreEqual(2, c2.CallCount);
+
+ var list2 = b.CreateObject>();
+ list2.Init(null);
+ list2.Init(list);
+ proxies = list2.Cast().ToArray();
+ Assert.IsTrue(proxies[0].IsNull);
+ Assert.IsFalse(proxies[1].IsNull);
+ Assert.IsTrue(proxies[3].IsNull);
+ list2[2].Foo(123u, true).Wait();
+ Assert.AreEqual(0, c1.CallCount);
+ Assert.AreEqual(3, c2.CallCount);
+ list2[4].Foo(123u, true).Wait();
+ Assert.AreEqual(4, c2.CallCount);
+
+ DeserializerState d = list2;
+ var list3 = d.RequireList().CastCapList();
+ proxies = list3.Cast().ToArray();
+ Assert.IsTrue(proxies[0].IsNull);
+ Assert.IsFalse(proxies[1].IsNull);
+ Assert.IsTrue(proxies[3].IsNull);
+ list3[2].Foo(123u, true).Wait();
+ Assert.AreEqual(0, c1.CallCount);
+ Assert.AreEqual(5, c2.CallCount);
+ list3[4].Foo(123u, true).Wait();
+ Assert.AreEqual(6, c2.CallCount);
+ }
}
}
diff --git a/Capnp.Net.Runtime.Tests/TestInterfaces.cs b/Capnp.Net.Runtime.Tests/TestInterfaces.cs
deleted file mode 100644
index 3d22d54..0000000
--- a/Capnp.Net.Runtime.Tests/TestInterfaces.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-using Capnp.Rpc;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Capnp.Net.Runtime.Tests.ManualImpls
-{
- // [Skeleton(typeof(TestInterfaceSkeleton))]
- // [Proxy(typeof(TestInterfaceProxy))]
- // interface ITestInterface: IDisposable
- // {
- // Task Foo(uint i, bool j);
- // Task Bar();
- // Task Baz(int s);
- // }
-
- // [Skeleton(typeof(TestExtendsSkeleton))]
- // [Proxy(typeof(TestExtendsProxy))]
- // interface ITestExtends: ITestInterface, IDisposable
- // {
- // void Qux();
- // Task Corge(int x);
- // Task Grault();
- // }
-
- // interface ITestExtends2: ITestExtends, IDisposable
- // {
- // }
-
- // struct Box
- // {
- // public ITestExtends Cap { get; set; }
- // }
-
- // struct AnyBox
- // {
- // public object Cap { get; set; }
- // }
-
- // [Skeleton(typeof(TestPipelineSkeleton))]
- // [Proxy(typeof(TestPipelineProxy))]
- // interface ITestPipeline: IDisposable
- // {
- // Task<(string, Box)> GetCap(uint n, ITestInterface inCap);
- // Task TestPointers(ITestExtends cap, DeserializerState obj, IReadOnlyList list);
- // Task<(string, AnyBox)> GetAnyCap(uint n, object inCap);
- // }
-
- // [Skeleton(typeof(TestCallOrderSkeleton))]
- // [Proxy(typeof(TestCallOrderProxy))]
- // interface ITestCallOrder : IDisposable
- // {
- // Task GetCallSequence(uint expected);
- // }
-
- // struct TailResult
- // {
- // public uint I { get; set; }
- // public string T { get; set; }
- // public ITestCallOrder C { get; set; }
- //}
-
- // [Skeleton(typeof(TestTailCalleeSkeleton))]
- // [Proxy(typeof(TestTailCalleeProxy))]
- // interface ITestTailCallee: IDisposable
- // {
- // Task Foo(int i, string t);
- // }
-
- // [Skeleton(typeof(TestTailCallerSkeleton))]
- // [Proxy(typeof(TestTailCallerProxy))]
- // interface ITestTailCaller: IDisposable
- // {
- // Task Foo(int i, ITestTailCallee c);
- // }
-
- // [Skeleton(typeof(TestHandleSkeleton))]
- // [Proxy(typeof(TestHandleProxy))]
- // interface ITestHandle: IDisposable { }
-
-
- // [Skeleton(typeof(TestMoreStuffSkeleton))]
- // [Proxy(typeof(TestMoreStuffProxy))]
- // interface ITestMoreStuff: ITestCallOrder
- // {
- // Task CallFoo(ITestInterface cap);
- // Task CallFooWhenResolved(ITestInterface cap);
- // Task NeverReturn(ITestInterface cap, CancellationToken ct);
- // Task Hold(ITestInterface cap);
- // Task CallHeld();
- // Task GetHeld();
- // Task Echo(ITestCallOrder cap);
- // Task ExpectCancel(ITestInterface cap, CancellationToken ct);
- // Task<(string, string)> MethodWithDefaults(string a, uint b, string c);
- // void MethodWithNullDefault(string a, ITestInterface b);
- // Task GetHandle();
- // Task GetNull();
- // Task GetEnormousString();
- // }
-}
-
diff --git a/Capnp.Net.Runtime/ListDeserializer.cs b/Capnp.Net.Runtime/ListDeserializer.cs
index 8db896b..67d65c4 100644
--- a/Capnp.Net.Runtime/ListDeserializer.cs
+++ b/Capnp.Net.Runtime/ListDeserializer.cs
@@ -89,7 +89,7 @@ namespace Capnp
/// 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
+ public virtual IReadOnlyList CastCapList() where T: class
{
throw new NotSupportedException("This kind of list does not contain nested lists");
}
diff --git a/Capnp.Net.Runtime/ListOfBitsSerializer.cs b/Capnp.Net.Runtime/ListOfBitsSerializer.cs
index af0eed8..2e5a94f 100644
--- a/Capnp.Net.Runtime/ListOfBitsSerializer.cs
+++ b/Capnp.Net.Runtime/ListOfBitsSerializer.cs
@@ -51,6 +51,8 @@ namespace Capnp
{
get
{
+ ListSerializerHelper.EnsureAllocated(this);
+
if (index < 0 || index >= Count)
throw new IndexOutOfRangeException();
@@ -61,6 +63,8 @@ namespace Capnp
}
set
{
+ ListSerializerHelper.EnsureAllocated(this);
+
if (index < 0 || index >= Count)
throw new IndexOutOfRangeException();
diff --git a/Capnp.Net.Runtime/ListOfCapsSerializer.cs b/Capnp.Net.Runtime/ListOfCapsSerializer.cs
index eef1d7c..3b71b21 100644
--- a/Capnp.Net.Runtime/ListOfCapsSerializer.cs
+++ b/Capnp.Net.Runtime/ListOfCapsSerializer.cs
@@ -35,16 +35,29 @@ namespace Capnp
[AllowNull]
public T this[int index]
{
- get => (Rpc.CapabilityReflection.CreateProxy(DecodeCapPointer(index)) as T)!;
+ get
+ {
+ ListSerializerHelper.EnsureAllocated(this);
+
+ try
+ {
+ return (Rpc.CapabilityReflection.CreateProxy(DecodeCapPointer(index)) as T)!;
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ throw new IndexOutOfRangeException();
+ }
+ }
set
{
- if (!IsAllocated)
- throw new InvalidOperationException("Call Init() first");
+ ListSerializerHelper.EnsureAllocated(this);
if (index < 0 || index >= RawData.Length)
throw new IndexOutOfRangeException("index out of range");
- RawData[index] = ProvideCapability(value);
+ var p = default(WirePointer);
+ p.SetCapability(ProvideCapability(value));
+ RawData[index] = p;
}
}
diff --git a/Capnp.Net.Runtime/ListOfPointersDeserializer.cs b/Capnp.Net.Runtime/ListOfPointersDeserializer.cs
index 520e0e7..09aa786 100644
--- a/Capnp.Net.Runtime/ListOfPointersDeserializer.cs
+++ b/Capnp.Net.Runtime/ListOfPointersDeserializer.cs
@@ -83,9 +83,9 @@ namespace Capnp
///
/// Capability interface
/// The desired representation. Since it is evaluated lazily, type conflicts will not happen before accessing the resulting list's elements.
- public override IReadOnlyList> CastCapList()
+ public override IReadOnlyList CastCapList()
{
- return this.LazyListSelect(d => d.RequireCapList());
+ return State.RequireCapList();
}
}
}
\ No newline at end of file
diff --git a/Capnp.Net.Runtime/ListSerializerHelper.cs b/Capnp.Net.Runtime/ListSerializerHelper.cs
new file mode 100644
index 0000000..5e76b8d
--- /dev/null
+++ b/Capnp.Net.Runtime/ListSerializerHelper.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Capnp
+{
+ static class ListSerializerHelper
+ {
+ public static void EnsureAllocated(SerializerState serializer)
+ {
+ if (!serializer.IsAllocated)
+ throw new InvalidOperationException("Call Init() first");
+ }
+ }
+}
\ No newline at end of file