diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs index 035d562..f719dc6 100644 --- a/Capnp.Net.Runtime.Tests/SerializationTests.cs +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -469,6 +469,21 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(expected, str); } + [TestMethod] + public void CapnpSerializableAnyPointer() + { + var b = MessageBuilder.Create(); + var obj = b.CreateObject(); + obj.SomeText = "hello"; + obj.MoreText = "world"; + DeserializerState d = obj; + var any = CapnpSerializable.Create(d); + var obj2 = new SomeStruct.READER(any.State); + Assert.AreEqual("hello", obj2.SomeText); + Assert.AreEqual("world", obj2.MoreText); + + } + class Unconstructible1 : ICapnpSerializable { public Unconstructible1(int annoyingParameter) @@ -511,8 +526,203 @@ namespace Capnp.Net.Runtime.Tests var d = default(DeserializerState); Assert.ThrowsException(() => CapnpSerializable.Create(d)); Assert.ThrowsException(() => CapnpSerializable.Create>(d)); + Assert.ThrowsException(() => CapnpSerializable.Create>(d)); Assert.ThrowsException(() => CapnpSerializable.Create(d)); Assert.ThrowsException(() => CapnpSerializable.Create(d)); } + + [TestMethod] + public void DynamicSerializerStateBytes() + { + var expected = new byte[] { 1, 2, 3 }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastByte().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateSBytes() + { + var expected = new sbyte[] { 1, 2, 3 }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastSByte().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateShorts() + { + var expected = new short[] { 1, 2, 3 }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastShort().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateUShorts() + { + var expected = new ushort[] { 1, 2, 3 }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastUShort().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateInts() + { + var expected = new int[] { 1, 2, 3 }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastInt().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateUInts() + { + var expected = new uint[] { 1, 2, 3 }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastUInt().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateLongs() + { + var expected = new long[] { 1, 2, 3 }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastLong().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateULongs() + { + var expected = new ulong[] { 1, 2, 3 }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastULong().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateFloats() + { + var expected = new float[] { 1.0f, 2.0f, 3.0f }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastFloat().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateDoubles() + { + var expected = new double[] { 1.0, 2.0, 3.0 }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastDouble().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateBools() + { + var expected = new bool[] { true, true, false }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastBool().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateStrings() + { + var expected = new string[] { "foo", "bar", "baz" }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + CollectionAssert.AreEqual(expected, d.RequireList().CastText2().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateObjects() + { + var c = new Counters(); + var cap = new TestInterfaceImpl(c); + var expected = new object[] { null, "foo", cap }; + + var b = MessageBuilder.Create(); + b.InitCapTable(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + var list = d.RequireList().Cast(_ => _); + Assert.AreEqual(3, list.Count); + Assert.IsTrue(list[0].Kind == ObjectKind.Nil); + Assert.AreEqual("foo", list[1].RequireList().CastText()); + var proxy = list[2].RequireCap(); + proxy.Foo(123u, true); + Assert.AreEqual(1, c.CallCount); + } + + [TestMethod] + public void DynamicSerializerStateFromDeserializerState() + { + var expected = new string[] { "foo", "bar", "baz" }; + + var b = MessageBuilder.Create(); + var lots = b.CreateObject(); + lots.Init(expected); + DeserializerState d = lots; + var dss = b.CreateObject(); + dss.SetObject(d); + DeserializerState d2 = dss; + CollectionAssert.AreEqual(expected, d2.RequireList().CastText2().ToArray()); + } + + [TestMethod] + public void DynamicSerializerStateFromSerializerState() + { + var expected = new string[] { "foo", "bar", "baz" }; + + var b = MessageBuilder.Create(); + var lots = b.CreateObject(); + lots.Init(expected); + var dss = b.CreateObject(); + dss.SetObject(lots); + DeserializerState d2 = dss; + CollectionAssert.AreEqual(expected, d2.RequireList().CastText2().ToArray()); + } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs index 58c66bf..34f01d5 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs @@ -367,6 +367,7 @@ namespace Capnp.Net.Runtime.Tests } [TestMethod] + [TestCategory("Coverage")] public void TestTailCallClient() { LaunchCompatTestProcess("server:TailCaller", stdout => diff --git a/Capnp.Net.Runtime/DynamicSerializerState.cs b/Capnp.Net.Runtime/DynamicSerializerState.cs index 77e615d..a58c688 100644 --- a/Capnp.Net.Runtime/DynamicSerializerState.cs +++ b/Capnp.Net.Runtime/DynamicSerializerState.cs @@ -135,6 +135,13 @@ namespace Capnp /// public void SetObject(object? obj) { + void RewrapAndInheritBack(Action init) where T : SerializerState, new() + { + var r = Rewrap(); + init(r); + InheritFrom(r); + } + switch (obj) { case ICapnpSerializable serializable: @@ -146,55 +153,55 @@ namespace Capnp break; case IReadOnlyList bytes: - Rewrap>().Init(bytes); + RewrapAndInheritBack>(_ => _.Init(bytes)); break; case IReadOnlyList sbytes: - Rewrap>().Init(sbytes); + RewrapAndInheritBack>(_ => _.Init(sbytes)); break; case IReadOnlyList ushorts: - Rewrap>().Init(ushorts); + RewrapAndInheritBack>(_ => _.Init(ushorts)); break; case IReadOnlyList shorts: - Rewrap>().Init(shorts); + RewrapAndInheritBack>(_ => _.Init(shorts)); break; case IReadOnlyList uints: - Rewrap>().Init(uints); + RewrapAndInheritBack>(_ => _.Init(uints)); break; case IReadOnlyList ints: - Rewrap>().Init(ints); + RewrapAndInheritBack>(_ => _.Init(ints)); break; case IReadOnlyList ulongs: - Rewrap>().Init(ulongs); + RewrapAndInheritBack>(_ => _.Init(ulongs)); break; case IReadOnlyList longs: - Rewrap>().Init(longs); + RewrapAndInheritBack>(_ => _.Init(longs)); break; case IReadOnlyList floats: - Rewrap>().Init(floats); + RewrapAndInheritBack>(_ => _.Init(floats)); break; case IReadOnlyList doubles: - Rewrap>().Init(doubles); + RewrapAndInheritBack>(_ => _.Init(doubles)); break; case IReadOnlyList bools: - Rewrap().Init(bools); + RewrapAndInheritBack(_ => _.Init(bools)); break; case IReadOnlyList strings: - Rewrap().Init(strings); + RewrapAndInheritBack(_ => _.Init(strings)); break; case IReadOnlyList objects: - Rewrap>().Init(objects, (s, o) => s.SetObject(o)); + RewrapAndInheritBack>(_ => _.Init(objects, (s, o) => s.SetObject(o))); break; case DeserializerState ds: diff --git a/Capnp.Net.Runtime/PrimitiveCoder.cs b/Capnp.Net.Runtime/PrimitiveCoder.cs deleted file mode 100644 index 9feee41..0000000 --- a/Capnp.Net.Runtime/PrimitiveCoder.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; - -namespace Capnp -{ - class PrimitiveCoder - { - class Coder - { - public static Func? Fn { get; set; } - } - - static PrimitiveCoder() - { - Coder.Fn = (x, y) => x != y; - Coder.Fn = (x, y) => (sbyte)(x ^ y); - Coder.Fn = (x, y) => (byte)(x ^ y); - Coder.Fn = (x, y) => (short)(x ^ y); - Coder.Fn = (x, y) => (ushort)(x ^ y); - Coder.Fn = (x, y) => x ^ y; - Coder.Fn = (x, y) => x ^ y; - Coder.Fn = (x, y) => x ^ y; - Coder.Fn = (x, y) => x ^ y; - Coder.Fn = (x, y) => - { - int xi = x.ReplacementSingleToInt32Bits(); - int yi = y.ReplacementSingleToInt32Bits(); - int zi = xi ^ yi; - return BitConverter.ToSingle(BitConverter.GetBytes(zi), 0); - }; - Coder.Fn = (x, y) => - { - long xi = BitConverter.DoubleToInt64Bits(x); - long yi = BitConverter.DoubleToInt64Bits(y); - long zi = xi ^ yi; - return BitConverter.Int64BitsToDouble(zi); - }; - } - - public static Func Get() - { - return Coder.Fn ?? - throw new NotSupportedException("Generic type argument is not a supported primitive type, no coder defined"); - } - } -} \ No newline at end of file diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index 9824afc..f52cc18 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -75,6 +75,18 @@ namespace Capnp MsgBuilder = owner.MsgBuilder; } + internal void InheritFrom(SerializerState other) + { + SegmentIndex = other.SegmentIndex; + Offset = other.Offset; + ListElementCount = other.ListElementCount; + StructDataCount = other.StructDataCount; + StructPtrCount = other.StructPtrCount; + Kind = other.Kind; + CapabilityIndex = other.CapabilityIndex; + _linkedStates = other._linkedStates; + } + /// /// Represents this state by a different serializer state specialization. This is similar to a type-cast: The underlying object remains the same, /// but the specialization adds a particular "view" on that data. @@ -114,14 +126,7 @@ namespace Capnp break; } - ts.SegmentIndex = SegmentIndex; - ts.Offset = Offset; - ts.ListElementCount = ListElementCount; - ts.StructDataCount = StructDataCount; - ts.StructPtrCount = StructPtrCount; - ts.Kind = Kind; - ts.CapabilityIndex = CapabilityIndex; - ts._linkedStates = _linkedStates; + ts.InheritFrom(this); } if (Owner != null) @@ -132,18 +137,6 @@ namespace Capnp return ts; } - internal void InheritFrom(SerializerState other) - { - SegmentIndex = other.SegmentIndex; - Offset = other.Offset; - ListElementCount = other.ListElementCount; - StructDataCount = other.StructDataCount; - StructPtrCount = other.StructPtrCount; - Kind = other.Kind; - CapabilityIndex = other.CapabilityIndex; - _linkedStates = other._linkedStates; - } - /// /// Whether storage space for the underlying object was already allocated. Note that allocation happens /// lazily, i.e. constructing a SerializerState and binding it to a MessageBuilder does NOT yet result in allocation.