From 420ba4f8ef35db46b6ca1a7b12ef81f1ec160218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 25 Feb 2020 21:46:15 +0100 Subject: [PATCH 01/76] added coverage measurement --- .gitignore | 3 ++ .../DeserializationTests.cs | 1 + .../DynamicSerializerStateTests.cs | 1 + Capnp.Net.Runtime.Tests/FramePumpTests.cs | 1 + Capnp.Net.Runtime.Tests/Interception.cs | 1 + .../MessageBuilderTests.cs | 1 + Capnp.Net.Runtime.Tests/RpcSchemaTests.cs | 1 + .../SegmentAllocatorTests.cs | 1 + Capnp.Net.Runtime.Tests/TcpRpc.cs | 1 + .../TcpRpcAdvancedStuff.cs | 1 + Capnp.Net.Runtime.Tests/TcpRpcPorted.cs | 1 + Capnp.Net.Runtime.Tests/WirePointerTests.cs | 1 + appveyor.yml | 13 +++++ scripts/choco-install-coverage-tools.ps1 | 4 ++ scripts/measure-coverage.ps1 | 48 +++++++++++++++++++ scripts/vsdevcmdprompt-measure-coverage.bat | 4 ++ 16 files changed, 83 insertions(+) create mode 100644 scripts/choco-install-coverage-tools.ps1 create mode 100644 scripts/measure-coverage.ps1 create mode 100644 scripts/vsdevcmdprompt-measure-coverage.bat diff --git a/.gitignore b/.gitignore index 64fa334..752be25 100644 --- a/.gitignore +++ b/.gitignore @@ -336,3 +336,6 @@ ASALocalRun/ # Capnp code behind *.capnp.cs /globalPackages + +# Coverage results folder +coverage/ diff --git a/Capnp.Net.Runtime.Tests/DeserializationTests.cs b/Capnp.Net.Runtime.Tests/DeserializationTests.cs index 882d4d7..647799b 100644 --- a/Capnp.Net.Runtime.Tests/DeserializationTests.cs +++ b/Capnp.Net.Runtime.Tests/DeserializationTests.cs @@ -3,6 +3,7 @@ namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class DeserializationTests { [TestMethod] diff --git a/Capnp.Net.Runtime.Tests/DynamicSerializerStateTests.cs b/Capnp.Net.Runtime.Tests/DynamicSerializerStateTests.cs index 0797860..a65c71f 100644 --- a/Capnp.Net.Runtime.Tests/DynamicSerializerStateTests.cs +++ b/Capnp.Net.Runtime.Tests/DynamicSerializerStateTests.cs @@ -7,6 +7,7 @@ using System.IO; namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class DynamicSerializerStateTests { [TestMethod] diff --git a/Capnp.Net.Runtime.Tests/FramePumpTests.cs b/Capnp.Net.Runtime.Tests/FramePumpTests.cs index 2ebef32..8c964a6 100644 --- a/Capnp.Net.Runtime.Tests/FramePumpTests.cs +++ b/Capnp.Net.Runtime.Tests/FramePumpTests.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class FramePumpTests { class MyStruct : SerializerState diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index ea7c1f5..ac0ea63 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -14,6 +14,7 @@ using System.Threading.Tasks.Dataflow; namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class Interception: TestBase { class MyPolicy : IInterceptionPolicy diff --git a/Capnp.Net.Runtime.Tests/MessageBuilderTests.cs b/Capnp.Net.Runtime.Tests/MessageBuilderTests.cs index 32196a6..5b3d6b1 100644 --- a/Capnp.Net.Runtime.Tests/MessageBuilderTests.cs +++ b/Capnp.Net.Runtime.Tests/MessageBuilderTests.cs @@ -3,6 +3,7 @@ namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class MessageBuilderTests { class Struct2D0P : SerializerState diff --git a/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs b/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs index 8032cc3..f8841ec 100644 --- a/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs +++ b/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs @@ -4,6 +4,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class RpcSchemaTests { [TestMethod] diff --git a/Capnp.Net.Runtime.Tests/SegmentAllocatorTests.cs b/Capnp.Net.Runtime.Tests/SegmentAllocatorTests.cs index 7506f08..7ff67b5 100644 --- a/Capnp.Net.Runtime.Tests/SegmentAllocatorTests.cs +++ b/Capnp.Net.Runtime.Tests/SegmentAllocatorTests.cs @@ -3,6 +3,7 @@ namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class SegmentAllocatorTests { [TestMethod] diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index b5482e4..56d8229 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -12,6 +12,7 @@ namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class TcpRpc { public static int TcpPort = 49153; diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index b708d77..e029d0a 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class TcpRpcAdvancedStuff : TestBase { [TestMethod, Timeout(10000)] diff --git a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs index db6a450..5bf3b17 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs @@ -13,6 +13,7 @@ using Microsoft.Extensions.Logging; namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class TcpRpcPorted: TestBase { [TestMethod] diff --git a/Capnp.Net.Runtime.Tests/WirePointerTests.cs b/Capnp.Net.Runtime.Tests/WirePointerTests.cs index ba7cd91..18ec167 100644 --- a/Capnp.Net.Runtime.Tests/WirePointerTests.cs +++ b/Capnp.Net.Runtime.Tests/WirePointerTests.cs @@ -4,6 +4,7 @@ using System; namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class WirePointerTests { [TestMethod] diff --git a/appveyor.yml b/appveyor.yml index b8c4883..da2ecb5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,9 +11,15 @@ install: - vcpkg install capnproto - cd %APPVEYOR_BUILD_FOLDER% - dotnet tool install -g nbgv + - choco install opencover --version=4.7.922 --force -y + - choco install reportgenerator.portable --version=2.5.0.0 --force -y + - dotnet tool install -g coveralls.net --version 1.0.0 init: # Good practise, because Windows line endings are different from Unix/Linux ones - cmd: git config --global core.autocrlf true +environment: + COVERALLS_REPO_TOKEN: + secure: mwxwOymoS7vB56iQN5Obbt8+oMqbRpK8Ei2GZUI7Mm46C8asDR/Wu0RAXYlhp85Q before_build: - cmd: nbgv cloud - cmd: dotnet --version @@ -51,6 +57,9 @@ artifacts: - path: capnpc-csharp\nupkg\*.nupkg name: capnpc-csharp type: NuGetPackage + - path: coverage\report\* + name: Coverage report + type: zip test_script: - cmd: | nbgv get-version -v NuGetPackageVersion >> version.txt @@ -80,6 +89,10 @@ test_script: vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Release\net471\Capnp.Net.Runtime.Tests.Std20.dll vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Debug\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll + - ps: | + .\scipts\measure-coverage.ps1 + $coveralls = ".\tools\csmacnz.coveralls.exe" + & $coveralls --reportgenerator -i coverage/report --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID on_finish : # any cleanup in here deploy: diff --git a/scripts/choco-install-coverage-tools.ps1 b/scripts/choco-install-coverage-tools.ps1 new file mode 100644 index 0000000..82e6e98 --- /dev/null +++ b/scripts/choco-install-coverage-tools.ps1 @@ -0,0 +1,4 @@ +if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit } + +choco install opencover --version=4.7.922 +choco install reportgenerator.portable --version=2.5.0.0 diff --git a/scripts/measure-coverage.ps1 b/scripts/measure-coverage.ps1 new file mode 100644 index 0000000..8b9f809 --- /dev/null +++ b/scripts/measure-coverage.ps1 @@ -0,0 +1,48 @@ +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$rootDir = "$scriptDir\.." +$coverageDir = "$rootDir\coverage" +$coverageReportDir = "$rootDir\coverage\report" +$openCover = "$env:LOCALAPPDATA\Apps\OpenCover\OpenCover.Console.exe" +$vsTestConsole = where.exe vstest.console + +$runtimeTestsDnc21 = "$rootDir\Capnp.Net.Runtime.Tests.Core21\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll" +$coverageOutputRuntimeDnc21 = "$coverageDir\cov-Capnp.Net.Runtime-dnc21.xml" + +$runtimeTestsNet471 = "$rootDir\Capnp.Net.Runtime.Tests\bin\Release\net471\Capnp.Net.Runtime.Tests.Std20.dll" +$coverageOutputRuntimeNet471 = "$coverageDir\cov-Capnp.Net.Runtime-net471.xml" + +$generatorTests = "$rootDir\CapnpC.CSharp.Generator.Tests\bin\Release\netcoreapp3.0\CapnpC.CSharp.Generator.Tests.dll" +$coverageOutputGenerator = "$coverageDir\cov-CapnpC.CSharp.Generator.xml" + +If(!(test-path $coverageDir)) +{ + New-Item -ItemType Directory -Force -Path $coverageDir +} + +If(!(test-path $coverageReportDir)) +{ + New-Item -ItemType Directory -Force -Path $coverageReportDir +} + +& $openCover -target:"$vsTestConsole" ` + -targetArgs:"/inIsolation $runtimeTestsDnc21 /TestCaseFilter:`"TestCategory=Coverage`"" ` + -filter:"+[Capnp.Net.Runtime]Capnp.*" ` + -excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" ` + -output:"$coverageOutputRuntimeDnc21" ` + -mergebyhash -register:user -oldStyle + +& $openCover -target:"$vsTestConsole" ` + -targetArgs:"/inIsolation $runtimeTestsNet471 /TestCaseFilter:`"TestCategory=Coverage`"" ` + -filter:"+[Capnp.Net.Runtime]Capnp.*" ` + -excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" ` + -output:"$coverageOutputRuntimeNet471" ` + -mergebyhash -register:user -oldStyle + +& $openCover -target:"$vsTestConsole" ` + -targetArgs:"/inIsolation $generatorTests" ` + -filter:"+[CapnpC.CSharp.Generator]*" ` + -excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" ` + -output:"$coverageOutputGenerator" ` + -mergebyhash -register:user -oldStyle + +ReportGenerator.exe -reports:"$coverageOutputRuntimeDnc21;$coverageOutputRuntimeNet471;$coverageOutputGenerator" -targetdir:"$coverageReportDir" -reportTypes:"Html;Xml" diff --git a/scripts/vsdevcmdprompt-measure-coverage.bat b/scripts/vsdevcmdprompt-measure-coverage.bat new file mode 100644 index 0000000..be2bf74 --- /dev/null +++ b/scripts/vsdevcmdprompt-measure-coverage.bat @@ -0,0 +1,4 @@ +rem This batch file assumes to be run from a Visual Studio developer command prompt +rem This is necessary because we need to locate vstest.console.exe + +powershell -File measure-coverage.ps1 From 68d4ad668e9f3d9f75b63e40065046e522aaae5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Wed, 26 Feb 2020 20:25:14 +0100 Subject: [PATCH 02/76] typo --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index da2ecb5..a41b38e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -90,7 +90,7 @@ test_script: vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Debug\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll - ps: | - .\scipts\measure-coverage.ps1 + .\scripts\measure-coverage.ps1 $coveralls = ".\tools\csmacnz.coveralls.exe" & $coveralls --reportgenerator -i coverage/report --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID on_finish : From 3877e2aca3e1307f0cbf4f6b7268467d72313b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Wed, 26 Feb 2020 21:08:54 +0100 Subject: [PATCH 03/76] first ListSerializer TC ListOfBitsSerializer stack overflow bugfix build script fix --- .../Capnp.Net.Runtime.Tests.Core21.csproj | 1 + .../Capnp.Net.Runtime.Tests.Std20.csproj | 2 + Capnp.Net.Runtime.Tests/SerializationTests.cs | 63 +++++++++++++++++++ Capnp.Net.Runtime/ListOfBitsSerializer.cs | 33 +++++++++- Capnp.Net.Runtime/MessageBuilder.cs | 5 +- appveyor.yml | 3 +- 6 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 Capnp.Net.Runtime.Tests/SerializationTests.cs 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 30d40e2..fd9eafd 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 @@ -24,6 +24,7 @@ + diff --git a/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj b/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj index 2f47c80..1fdeec0 100644 --- a/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj +++ b/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj @@ -10,6 +10,8 @@ Library Debug;Release + + Capnp.Net.Runtime.Tests diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs new file mode 100644 index 0000000..9ce7fdd --- /dev/null +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -0,0 +1,63 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Capnp.Net.Runtime.Tests +{ + [TestClass] + [TestCategory("Coverage")] + public class SerializationTests + { + [TestMethod] + public void ListOfBits() + { + void CheckList(IEnumerable items) + { + int i = 0; + foreach (bool bit in items) + { + if (i == 63 || i == 66 || i == 129) + Assert.IsTrue(bit); + else + Assert.IsFalse(bit); + + ++i; + } + Assert.AreEqual(130, i); + } + + var b = MessageBuilder.Create(); + var list = b.CreateObject(); + Assert.ThrowsException(() => list.Init(-1)); + list.Init(130); + list[63] = true; + list[65] = true; + list[66] = true; + list[65] = false; + list[129] = true; + Assert.IsFalse(list[0]); + Assert.IsTrue(list[63]); + Assert.IsFalse(list[64]); + Assert.IsFalse(list[65]); + Assert.IsTrue(list[66]); + Assert.IsTrue(list[129]); + var list2 = b.CreateObject(); + list2.Init(null); + list2.Init(list); + Assert.IsFalse(list2[0]); + Assert.IsTrue(list2[63]); + Assert.IsFalse(list2[64]); + Assert.IsFalse(list2[65]); + Assert.IsTrue(list2[66]); + Assert.IsTrue(list2[129]); + CheckList(list2); + Assert.ThrowsException(() => list.Init(4)); + DeserializerState d = list2; + var list3 = d.RequireList().CastBool(); + CheckList(list3); + } + } +} diff --git a/Capnp.Net.Runtime/ListOfBitsSerializer.cs b/Capnp.Net.Runtime/ListOfBitsSerializer.cs index 6c00c7a..af0eed8 100644 --- a/Capnp.Net.Runtime/ListOfBitsSerializer.cs +++ b/Capnp.Net.Runtime/ListOfBitsSerializer.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; namespace Capnp { @@ -10,6 +11,34 @@ namespace Capnp /// public class ListOfBitsSerializer: SerializerState, IReadOnlyList { + class Enumerator : IEnumerator + { + readonly ListOfBitsSerializer _self; + int _pos = -1; + + public Enumerator(ListOfBitsSerializer self) + { + _self = self; + } + + public bool Current => _pos >= 0 && _pos < _self.Count ? _self[_pos] : false; + + object IEnumerator.Current => Current; + + public void Dispose() + { + } + + public bool MoveNext() + { + return ++_pos < _self.Count; + } + + public void Reset() + { + _pos = -1; + } + } /// /// Gets or sets the element at given index. @@ -91,8 +120,8 @@ namespace Capnp /// /// Implements /// - public IEnumerator GetEnumerator() => (IEnumerator)this.ToArray().GetEnumerator(); + public IEnumerator GetEnumerator() => new Enumerator(this); - IEnumerator IEnumerable.GetEnumerator() => this.ToArray().GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/MessageBuilder.cs b/Capnp.Net.Runtime/MessageBuilder.cs index 9a5d826..6afb40e 100644 --- a/Capnp.Net.Runtime/MessageBuilder.cs +++ b/Capnp.Net.Runtime/MessageBuilder.cs @@ -64,7 +64,7 @@ namespace Capnp /// /// Creates an object and sets it as root object. /// - /// Serializer state specialization + /// Serializer state specialization (must be a struct) /// Serializer state instance representing the new object public TS BuildRoot() where TS: SerializerState, new() { @@ -72,6 +72,9 @@ namespace Capnp throw new InvalidOperationException("Root already set"); var root = CreateObject(); + if (root.Kind != ObjectKind.Struct) + throw new InvalidOperationException("Root object must be a struct"); + Root = root; return root; } diff --git a/appveyor.yml b/appveyor.yml index a41b38e..67656b3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -91,8 +91,7 @@ test_script: vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll - ps: | .\scripts\measure-coverage.ps1 - $coveralls = ".\tools\csmacnz.coveralls.exe" - & $coveralls --reportgenerator -i coverage/report --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID + csmacnz.Coveralls --reportgenerator -i coverage/report --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID on_finish : # any cleanup in here deploy: From fc6af91833bb2a35cb9e5705d91f6d47ae25bda5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Wed, 26 Feb 2020 22:04:59 +0100 Subject: [PATCH 04/76] added cap list serializer TC bugfixes --- .../Capnp.Net.Runtime.Tests.Core21.csproj | 1 - Capnp.Net.Runtime.Tests/SerializationTests.cs | 67 +++++++++++- Capnp.Net.Runtime.Tests/TestInterfaces.cs | 102 ------------------ Capnp.Net.Runtime/ListDeserializer.cs | 2 +- Capnp.Net.Runtime/ListOfBitsSerializer.cs | 4 + Capnp.Net.Runtime/ListOfCapsSerializer.cs | 21 +++- .../ListOfPointersDeserializer.cs | 4 +- Capnp.Net.Runtime/ListSerializerHelper.cs | 13 +++ 8 files changed, 103 insertions(+), 111 deletions(-) delete mode 100644 Capnp.Net.Runtime.Tests/TestInterfaces.cs create mode 100644 Capnp.Net.Runtime/ListSerializerHelper.cs 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 From 9b82ce12fe576df8423aa70db2270135eac353f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 1 Mar 2020 13:18:55 +0100 Subject: [PATCH 05/76] made nullable behavior more consistent added serialization tests bug fixes --- .../Capnp.Net.Runtime.Tests.Core21.csproj | 1 + Capnp.Net.Runtime.Tests/SerializationTests.cs | 170 +++++++- Capnp.Net.Runtime/CapnpSerializable.cs | 5 +- Capnp.Net.Runtime/DeserializerState.cs | 82 ++-- Capnp.Net.Runtime/DynamicSerializerState.cs | 23 +- Capnp.Net.Runtime/EmptyListDeserializer.cs | 2 +- Capnp.Net.Runtime/ListDeserializer.cs | 6 +- .../ListOfPrimitivesDeserializer.cs | 2 - .../ListOfPrimitivesSerializer.cs | 20 +- Capnp.Net.Runtime/ListOfTextSerializer.cs | 8 +- Capnp.Net.Runtime/Rpc/TcpRpcClient.cs | 6 +- Capnp.Net.Runtime/SerializerState.cs | 56 +-- .../Embedded Resources/test.cs | 366 +++++++++--------- .../CodeGen/DomainClassSnippetGen.cs | 18 +- CapnpC.CSharp.Generator/CodeGen/GenNames.cs | 23 +- 15 files changed, 459 insertions(+), 329 deletions(-) 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 5eac70b..b72dab4 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 @@ -8,6 +8,7 @@ Debug;Release + diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs index 3ea4f63..75b1aa2 100644 --- a/Capnp.Net.Runtime.Tests/SerializationTests.cs +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using static Capnproto_test.Capnp.Test.TestStructUnion; namespace Capnp.Net.Runtime.Tests { @@ -53,7 +54,7 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(list[129]); var list2 = b.CreateObject(); list2.Init(null); - list2.Init(list); + list2.Init(list.ToArray()); Assert.IsFalse(list2[0]); Assert.IsTrue(list2[63]); Assert.IsFalse(list2[64]); @@ -101,7 +102,7 @@ namespace Capnp.Net.Runtime.Tests var list2 = b.CreateObject>(); list2.Init(null); - list2.Init(list); + list2.Init(list.ToArray()); proxies = list2.Cast().ToArray(); Assert.IsTrue(proxies[0].IsNull); Assert.IsFalse(proxies[1].IsNull); @@ -124,5 +125,170 @@ namespace Capnp.Net.Runtime.Tests list3[4].Foo(123u, true).Wait(); Assert.AreEqual(6, c2.CallCount); } + + [TestMethod] + public void ListOfEmpty() + { + var b = MessageBuilder.Create(); + var list = b.CreateObject(); + Assert.ThrowsException(() => list.Init(-1)); + list.Init(987654321); + Assert.AreEqual(987654321, list.Count); + Assert.ThrowsException(() => list.Init(42)); + DeserializerState d = list; + int list2 = d.RequireList().CastVoid(); + Assert.AreEqual(987654321, list2); + } + + [TestMethod] + public void ListOfPointers() + { + 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(7); + Assert.ThrowsException(() => list.Init(1)); + Assert.AreEqual(7, list.Count); + var c1 = new Counters(); + var cap1 = new TestInterfaceImpl(c1); + var obj1 = b.CreateObject(); + obj1.SetObject(cap1); + var obj2 = b.CreateObject(); + obj2.SetStruct(1, 1); + var lobs = b.CreateObject(); + lobs.Init(1); + var obj3 = lobs.Rewrap(); + list[1] = obj1; + list[2] = obj2; + list[3] = obj3; + Assert.IsNotNull(list[0]); + Assert.AreEqual(ObjectKind.Nil, list[0].Kind); + Assert.AreEqual(obj1, list[1]); + Assert.AreEqual(obj2, list[2]); + Assert.AreEqual(obj3, list[3]); + var list2 = list.ToArray(); + Assert.IsNotNull(list2[0]); + Assert.AreEqual(ObjectKind.Nil, list2[0].Kind); + Assert.AreEqual(obj1, list2[1]); + Assert.AreEqual(obj2, list2[2]); + Assert.AreEqual(obj3, list2[3]); + + DeserializerState d = list; + var list3 = d.RequireList().Cast(_ => _); + Assert.AreEqual(7, list3.Count); + Assert.IsNotNull(list3[0]); + Assert.AreEqual(ObjectKind.Nil, list3[0].Kind); + Assert.AreEqual(ObjectKind.Capability, list3[1].Kind); + Assert.AreEqual(ObjectKind.Struct, list3[2].Kind); + Assert.AreEqual(ObjectKind.ListOfBits, list3[3].Kind); + } + + [TestMethod] + public void ListOfPrimitives() + { + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + Assert.ThrowsException(() => list.Init(-1)); + Assert.ThrowsException(() => { var _ = list[0]; }); + Assert.ThrowsException(() => { list[0] = 1.0f; }); + list.Init(4); + Assert.ThrowsException(() => list.Init(1)); + Assert.AreEqual(4, list.Count); + list[0] = 0.0f; + list[1] = 1.0f; + list[2] = 2.0f; + list[3] = 3.0f; + Assert.AreEqual(0.0f, list[0]); + Assert.AreEqual(1.0f, list[1]); + Assert.AreEqual(2.0f, list[2]); + Assert.AreEqual(3.0f, list[3]); + + var list2 = b.CreateObject>(); + list2.Init(null); + list2.Init(list.ToArray()); + Assert.AreEqual(4, list2.Count); + Assert.AreEqual(0.0f, list2[0]); + Assert.AreEqual(1.0f, list2[1]); + Assert.AreEqual(2.0f, list2[2]); + Assert.AreEqual(3.0f, list2[3]); + + DeserializerState d = list2; + var list3 = d.RequireList().CastFloat(); + Assert.AreEqual(4, list3.Count); + Assert.AreEqual(0.0f, list3[0]); + Assert.AreEqual(1.0f, list3[1]); + Assert.AreEqual(2.0f, list3[2]); + Assert.AreEqual(3.0f, list3[3]); + } + + [TestMethod] + public void ListOfStructs() + { + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + Assert.ThrowsException(() => list.Init(-1)); + Assert.ThrowsException(() => { var _ = list[0]; }); + list.Init(4); + Assert.ThrowsException(() => list.Init(1)); + Assert.AreEqual(4, list.Count); + list[0].SomeText = "0"; + list[1].SomeText = "1"; + list[2].SomeText = "2"; + list[3].SomeText = "3"; + Assert.AreEqual("0", list[0].SomeText); + Assert.AreEqual("3", list[3].SomeText); + + var list2 = b.CreateObject>(); + list2.Init(list.ToArray(), (dst, src) => { dst.SomeText = src.SomeText; dst.MoreText = src.MoreText; }); + Assert.AreEqual(4, list2.Count); + Assert.AreEqual("0", list2[0].SomeText); + Assert.AreEqual("3", list2[3].SomeText); + + DeserializerState d = list2; + var list3 = d.RequireList().Cast(_ => new SomeStruct.READER(_)); + Assert.AreEqual(4, list3.Count); + Assert.AreEqual("0", list3[0].SomeText); + Assert.AreEqual("3", list3[3].SomeText); + } + + [TestMethod] + public void ListOfText() + { + var b = MessageBuilder.Create(); + var list = b.CreateObject(); + Assert.ThrowsException(() => list.Init(-1)); + Assert.ThrowsException(() => { var _ = list[0]; }); + Assert.ThrowsException(() => { list[0] = "foo"; }); + list.Init(4); + Assert.ThrowsException(() => list.Init(1)); + Assert.AreEqual(4, list.Count); + list[0] = "0"; + list[2] = null; + list[3] = "3"; + Assert.AreEqual("0", list[0]); + Assert.IsNull(list[1]); + Assert.IsNull(list[2]); + Assert.AreEqual("3", list[3]); + + var list2 = b.CreateObject(); + list2.Init(list.ToArray()); + Assert.AreEqual(4, list2.Count); + Assert.AreEqual("0", list2[0]); + Assert.IsNull(list2[1]); + Assert.IsNull(list2[2]); + Assert.AreEqual("3", list2[3]); + + DeserializerState d = list2; + var tmp = d.RequireList(); + var list3 = tmp.CastText2(); + Assert.AreEqual(4, list3.Count); + Assert.AreEqual("0", list3[0]); + Assert.IsNull(list3[1]); + Assert.IsNull(list3[2]); + Assert.AreEqual("3", list3[3]); + } } } diff --git a/Capnp.Net.Runtime/CapnpSerializable.cs b/Capnp.Net.Runtime/CapnpSerializable.cs index 81b86b6..631f869 100644 --- a/Capnp.Net.Runtime/CapnpSerializable.cs +++ b/Capnp.Net.Runtime/CapnpSerializable.cs @@ -163,9 +163,8 @@ namespace Capnp /// /// /// deserializer state to construct from - /// The domain object instance. Nullability note: The returned reference will be null if (and only if) is a capability interface and - /// represents the nil object (obtained from a null pointer). For all other types, when the state is nil, - /// the method still constructs a valid but "empty" object instance (such as domain object without any properties set, empty string, empty list etc.) + /// The domain object instance. Nullability note: The returned reference may be null if + /// represents the nil object. public static T? Create(DeserializerState state) where T: class { diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs index 8dd7ce8..026b29e 100644 --- a/Capnp.Net.Runtime/DeserializerState.cs +++ b/Capnp.Net.Runtime/DeserializerState.cs @@ -158,7 +158,6 @@ namespace Capnp /// Memory span which represents this struct's data section (given this state actually represents a struct) /// public ReadOnlySpan StructDataSection => CurrentSegment.Slice(Offset, StructDataCount); - ReadOnlySpan StructPtrSection => CurrentSegment.Slice(Offset + StructDataCount, StructPtrCount); ReadOnlySpan GetRawBits() => CurrentSegment.Slice(Offset, (ListElementCount + 63) / 64); ReadOnlySpan GetRawBytes() => CurrentSegment.Slice(Offset, (ListElementCount + 7) / 8); @@ -172,26 +171,15 @@ namespace Capnp { get { - switch (Kind) + return Kind switch { - case ObjectKind.ListOfBits: - return GetRawBits(); - - case ObjectKind.ListOfBytes: - return GetRawBytes(); - - case ObjectKind.ListOfShorts: - return GetRawShorts(); - - case ObjectKind.ListOfInts: - return GetRawInts(); - - case ObjectKind.ListOfLongs: - return GetRawLongs(); - - default: - return default; - } + ObjectKind.ListOfBits => GetRawBits(), + ObjectKind.ListOfBytes => GetRawBytes(), + ObjectKind.ListOfShorts => GetRawShorts(), + ObjectKind.ListOfInts => GetRawInts(), + ObjectKind.ListOfLongs => GetRawLongs(), + _ => default, + }; } } @@ -513,38 +501,19 @@ namespace Capnp /// state does not represent a list public ListDeserializer RequireList() { - switch (Kind) + return Kind switch { - case ObjectKind.ListOfBits: - return new ListOfBitsDeserializer(ref this, false); - - case ObjectKind.ListOfBytes: - return new ListOfPrimitivesDeserializer(ref this, ListKind.ListOfBytes); - - case ObjectKind.ListOfEmpty: - return new ListOfEmptyDeserializer(ref this); - - case ObjectKind.ListOfInts: - return new ListOfPrimitivesDeserializer(ref this, ListKind.ListOfInts); - - case ObjectKind.ListOfLongs: - return new ListOfPrimitivesDeserializer(ref this, ListKind.ListOfLongs); - - case ObjectKind.ListOfPointers: - return new ListOfPointersDeserializer(ref this); - - case ObjectKind.ListOfShorts: - return new ListOfPrimitivesDeserializer(ref this, ListKind.ListOfShorts); - - case ObjectKind.ListOfStructs: - return new ListOfStructsDeserializer(ref this); - - case ObjectKind.Nil: - return new EmptyListDeserializer(); - - default: - throw new DeserializationException("Cannot deserialize this object as list"); - } + ObjectKind.ListOfBits => new ListOfBitsDeserializer(ref this, false), + ObjectKind.ListOfBytes => new ListOfPrimitivesDeserializer(ref this, ListKind.ListOfBytes), + ObjectKind.ListOfEmpty => new ListOfEmptyDeserializer(ref this), + ObjectKind.ListOfInts => new ListOfPrimitivesDeserializer(ref this, ListKind.ListOfInts), + ObjectKind.ListOfLongs => new ListOfPrimitivesDeserializer(ref this, ListKind.ListOfLongs), + ObjectKind.ListOfPointers => new ListOfPointersDeserializer(ref this), + ObjectKind.ListOfShorts => new ListOfPrimitivesDeserializer(ref this, ListKind.ListOfShorts), + ObjectKind.ListOfStructs => new ListOfStructsDeserializer(ref this), + ObjectKind.Nil => new EmptyListDeserializer(), + _ => throw new DeserializationException("Cannot deserialize this object as list"), + }; } /// @@ -554,14 +523,11 @@ namespace Capnp /// state does not represent a list of pointers public ListOfCapsDeserializer RequireCapList() where T: class { - switch (Kind) + return Kind switch { - case ObjectKind.ListOfPointers: - return new ListOfCapsDeserializer(ref this); - - default: - throw new DeserializationException("Cannot deserialize this object as capability list"); - } + ObjectKind.ListOfPointers => new ListOfCapsDeserializer(ref this), + _ => throw new DeserializationException("Cannot deserialize this object as capability list"), + }; } /// diff --git a/Capnp.Net.Runtime/DynamicSerializerState.cs b/Capnp.Net.Runtime/DynamicSerializerState.cs index 679a59f..77e615d 100644 --- a/Capnp.Net.Runtime/DynamicSerializerState.cs +++ b/Capnp.Net.Runtime/DynamicSerializerState.cs @@ -121,27 +121,16 @@ namespace Capnp /// Object representation. Must be one of the following: /// /// An instance implementing - /// null - /// A - /// A ]]> - /// A ]]> - /// A ]]> - /// A ]]> - /// A ]]> - /// A ]]> - /// A ]]> - /// A ]]> - /// A ]]> - /// A ]]> - /// A ]]> - /// A ]]> - /// Another - /// Another + /// null, + /// IReadOnlyList<byte>, IReadOnlyList<sbyte>, IReadOnlyList<ushort>, IReadOnlyList<short> + /// IReadOnlyList<int>, IReadOnlyList<uint>, IReadOnlyList<long>, IReadOnlyList<ulong> + /// IReadOnlyList<float>, IReadOnlyList<double>, IReadOnlyList<bool>, IReadOnlyList<string> + /// Another or /// Low-level capability object () /// Proxy object () /// Skeleton object () /// Capability interface implementation - /// A ]]> whereby each list item is one of the things listed here. + /// IReadOnlyList<object>, whereby each list item is one of the things listed here. /// /// public void SetObject(object? obj) diff --git a/Capnp.Net.Runtime/EmptyListDeserializer.cs b/Capnp.Net.Runtime/EmptyListDeserializer.cs index 76ee7d1..255f233 100644 --- a/Capnp.Net.Runtime/EmptyListDeserializer.cs +++ b/Capnp.Net.Runtime/EmptyListDeserializer.cs @@ -68,7 +68,7 @@ namespace Capnp /// /// Returns an empty string. /// - public override string CastText() => string.Empty; + public override string? CastText() => null; /// /// Returns an empty ]]>. diff --git a/Capnp.Net.Runtime/ListDeserializer.cs b/Capnp.Net.Runtime/ListDeserializer.cs index 67d65c4..6d28ab9 100644 --- a/Capnp.Net.Runtime/ListDeserializer.cs +++ b/Capnp.Net.Runtime/ListDeserializer.cs @@ -26,7 +26,7 @@ namespace Capnp GenericCasts>.CastFunc = _ => _.CastULong(); GenericCasts>.CastFunc = _ => _.CastFloat(); GenericCasts>.CastFunc = _ => _.CastDouble(); - GenericCasts.CastFunc = _ => _.CastText(); + GenericCasts.CastFunc = _ => _.CastText()!; // it *may* return null, but how to express this syntactically correct? } /// @@ -269,7 +269,7 @@ namespace Capnp /// /// The desired representation /// If this list cannot be represented in the desired manner. - public IReadOnlyList CastText2() => CastList().LazyListSelect(ld => ld.CastText()); + public IReadOnlyList CastText2() => CastList().LazyListSelect(ld => ld.CastText()); /// /// Represents this list as Text. For representing it as List(Text), use . @@ -285,7 +285,7 @@ namespace Capnp /// /// The decoded text /// If this list cannot be represented in the desired manner. - public virtual string CastText() + public virtual string? CastText() { throw new NotSupportedException("This kind of list does not represent text"); } diff --git a/Capnp.Net.Runtime/ListOfPrimitivesDeserializer.cs b/Capnp.Net.Runtime/ListOfPrimitivesDeserializer.cs index 1cb357a..aa47218 100644 --- a/Capnp.Net.Runtime/ListOfPrimitivesDeserializer.cs +++ b/Capnp.Net.Runtime/ListOfPrimitivesDeserializer.cs @@ -77,8 +77,6 @@ namespace Capnp base(ref state) { _kind = kind; - - var binCoder = PrimitiveCoder.Get(); } /// diff --git a/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs b/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs index b70a3a9..7f53839 100644 --- a/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs +++ b/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs @@ -37,8 +37,16 @@ namespace Capnp /// Element value public T this[int index] { - get => Data[index]; - set => Data[index] = value; + get + { + ListSerializerHelper.EnsureAllocated(this); + return Data[index]; + } + set + { + ListSerializerHelper.EnsureAllocated(this); + Data[index] = value; + } } /// @@ -84,11 +92,17 @@ namespace Capnp } } + IEnumerable Enumerate() + { + for (int i = 0; i < Data.Length; i++) + yield return Data[i]; + } + /// /// Implements . /// /// - public IEnumerator GetEnumerator() => (IEnumerator)Data.ToArray().GetEnumerator(); + public IEnumerator GetEnumerator() => Enumerate().GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => Data.ToArray().GetEnumerator(); } diff --git a/Capnp.Net.Runtime/ListOfTextSerializer.cs b/Capnp.Net.Runtime/ListOfTextSerializer.cs index 5bd63e7..c1dabbf 100644 --- a/Capnp.Net.Runtime/ListOfTextSerializer.cs +++ b/Capnp.Net.Runtime/ListOfTextSerializer.cs @@ -22,8 +22,7 @@ namespace Capnp { get { - if (!IsAllocated) - throw new InvalidOperationException("Not initialized"); + ListSerializerHelper.EnsureAllocated(this); if (index < 0 || index >= Count) throw new IndexOutOfRangeException(); @@ -32,8 +31,7 @@ namespace Capnp } set { - if (!IsAllocated) - throw new InvalidOperationException("Not initialized"); + ListSerializerHelper.EnsureAllocated(this); if (index < 0 || index >= Count) throw new IndexOutOfRangeException(); @@ -53,7 +51,7 @@ namespace Capnp for (int i = 0; i < count; i++) { - yield return TryGetPointer(i)?.ListReadAsText(); + yield return this[i]; } } diff --git a/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs b/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs index 02a975d..6b872fd 100644 --- a/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs +++ b/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs @@ -19,12 +19,10 @@ namespace Capnp.Rpc class OutboundTcpEndpoint : IEndpoint { - readonly TcpRpcClient _client; readonly FramePump _pump; - public OutboundTcpEndpoint(TcpRpcClient client, FramePump pump) + public OutboundTcpEndpoint(FramePump pump) { - _client = client; _pump = pump; } @@ -84,7 +82,7 @@ namespace Capnp.Rpc var stream = _createLayers(_client.GetStream()); _pump = new FramePump(stream); _attachTracerAction?.Invoke(); - _outboundEndpoint = new OutboundTcpEndpoint(this, _pump); + _outboundEndpoint = new OutboundTcpEndpoint(_pump); _inboundEndpoint = _rpcEngine.AddEndpoint(_outboundEndpoint); _pumpThread = new Thread(() => { diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index 4490ada..9824afc 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -39,7 +39,6 @@ namespace Capnp internal int ListElementCount { get; set; } internal ushort StructDataCount { get; set; } internal ushort StructPtrCount { get; set; } - internal ObjectKind Kind { get; set; } internal uint CapabilityIndex { get; set; } SerializerState[]? _linkedStates; @@ -93,7 +92,7 @@ namespace Capnp if (Kind != ObjectKind.Nil) { - InvalidOperationException InvalidWrap() => + static InvalidOperationException InvalidWrap() => new InvalidOperationException("Incompatible cast"); switch (ts.Kind) @@ -165,6 +164,11 @@ namespace Capnp /// public Span RawData => SegmentSpan.Slice(Offset, (int)WordsAllocated); + /// + /// The kind of object this state currently represents. + /// + public ObjectKind Kind { get; internal set; } + void AllocateWords(uint count) { if (count == 0) @@ -286,7 +290,7 @@ namespace Capnp Allocate(); } - WirePointer targetPtr = default(WirePointer); + WirePointer targetPtr = default; switch (target.Kind) { @@ -539,38 +543,16 @@ namespace Capnp /// negative or exceeding 2^29-1 protected void SetListOfValues(byte bitsPerElement, int totalCount) { - ObjectKind kind; - - switch (bitsPerElement) + var kind = bitsPerElement switch { - case 0: - kind = ObjectKind.ListOfEmpty; - break; - - case 1: - kind = ObjectKind.ListOfBits; - break; - - case 8: - kind = ObjectKind.ListOfBytes; - break; - - case 16: - kind = ObjectKind.ListOfShorts; - break; - - case 32: - kind = ObjectKind.ListOfInts; - break; - - case 64: - kind = ObjectKind.ListOfLongs; - break; - - default: - throw new ArgumentOutOfRangeException(nameof(bitsPerElement)); - } - + 0 => ObjectKind.ListOfEmpty, + 1 => ObjectKind.ListOfBits, + 8 => ObjectKind.ListOfBytes, + 16 => ObjectKind.ListOfShorts, + 32 => ObjectKind.ListOfInts, + 64 => ObjectKind.ListOfLongs, + _ => throw new ArgumentOutOfRangeException(nameof(bitsPerElement)), + }; if (Kind == ObjectKind.Nil) { if (totalCount < 0) @@ -702,8 +684,6 @@ namespace Capnp if (relBitOffset + bitCount > 64) throw new ArgumentOutOfRangeException(nameof(bitCount)); - ulong word = data[index]; - if (bitCount == 64) { data[index] = value; @@ -875,14 +855,14 @@ namespace Capnp /// If the underlying object is a struct: index into the struct's pointer section. /// If the underlying object is a list of pointers: Element index /// Text to encode - /// Default text of > is null + /// Default text if > is null /// Both and are null /// /// The underlying object was not determined to be a struct or list of pointers. /// Object at given position was already set. /// /// is out of bounds. - public void WriteText(int index, string? text, string defaultText) + public void WriteText(int index, string? text, string? defaultText) { BuildPointer(index).WriteText(text ?? defaultText); } diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs index 3a90610..e96c18b 100644 --- a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs +++ b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs @@ -321,7 +321,7 @@ namespace Capnproto_test.Capnp.Test public ulong UInt64Field => ctx.ReadDataULong(192UL, 0UL); public float Float32Field => ctx.ReadDataFloat(256UL, 0F); public double Float64Field => ctx.ReadDataDouble(320UL, 0); - public string TextField => ctx.ReadText(0, ""); + public string TextField => ctx.ReadText(0, null); public IReadOnlyList DataField => ctx.ReadList(1).CastByte(); public Capnproto_test.Capnp.Test.TestAllTypes.READER StructField => ctx.ReadStruct(2, Capnproto_test.Capnp.Test.TestAllTypes.READER.create); public Capnproto_test.Capnp.Test.TestEnum EnumField => (Capnproto_test.Capnp.Test.TestEnum)ctx.ReadDataUShort(288UL, (ushort)0); @@ -419,8 +419,8 @@ namespace Capnproto_test.Capnp.Test public string TextField { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public ListOfPrimitivesSerializer DataField @@ -1373,15 +1373,15 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Qux => ctx.ReadText(0, ""); - public string Grault => ctx.ReadText(1, ""); - public string Bar => ctx.ReadText(2, ""); - public string Foo => ctx.ReadText(3, ""); - public string Corge => ctx.ReadText(4, ""); - public string Waldo => ctx.ReadText(5, ""); - public string Quux => ctx.ReadText(6, ""); - public string Garply => ctx.ReadText(7, ""); - public string Baz => ctx.ReadText(8, ""); + public string Qux => ctx.ReadText(0, null); + public string Grault => ctx.ReadText(1, null); + public string Bar => ctx.ReadText(2, null); + public string Foo => ctx.ReadText(3, null); + public string Corge => ctx.ReadText(4, null); + public string Waldo => ctx.ReadText(5, null); + public string Quux => ctx.ReadText(6, null); + public string Garply => ctx.ReadText(7, null); + public string Baz => ctx.ReadText(8, null); } public class WRITER : SerializerState @@ -1393,56 +1393,56 @@ namespace Capnproto_test.Capnp.Test public string Qux { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public string Grault { - get => this.ReadText(1, ""); - set => this.WriteText(1, value, ""); + get => this.ReadText(1, null); + set => this.WriteText(1, value, null); } public string Bar { - get => this.ReadText(2, ""); - set => this.WriteText(2, value, ""); + get => this.ReadText(2, null); + set => this.WriteText(2, value, null); } public string Foo { - get => this.ReadText(3, ""); - set => this.WriteText(3, value, ""); + get => this.ReadText(3, null); + set => this.WriteText(3, value, null); } public string Corge { - get => this.ReadText(4, ""); - set => this.WriteText(4, value, ""); + get => this.ReadText(4, null); + set => this.WriteText(4, value, null); } public string Waldo { - get => this.ReadText(5, ""); - set => this.WriteText(5, value, ""); + get => this.ReadText(5, null); + set => this.WriteText(5, value, null); } public string Quux { - get => this.ReadText(6, ""); - set => this.WriteText(6, value, ""); + get => this.ReadText(6, null); + set => this.WriteText(6, value, null); } public string Garply { - get => this.ReadText(7, ""); - set => this.WriteText(7, value, ""); + get => this.ReadText(7, null); + set => this.WriteText(7, value, null); } public string Baz { - get => this.ReadText(8, ""); - set => this.WriteText(8, value, ""); + get => this.ReadText(8, null); + set => this.WriteText(8, value, null); } } } @@ -1992,13 +1992,13 @@ namespace Capnproto_test.Capnp.Test public short U0f0s16 => which == WHICH.U0f0s16 ? ctx.ReadDataShort(64UL, (short)0) : default; public int U0f0s32 => which == WHICH.U0f0s32 ? ctx.ReadDataInt(64UL, 0) : default; public long U0f0s64 => which == WHICH.U0f0s64 ? ctx.ReadDataLong(64UL, 0L) : default; - public string U0f0sp => which == WHICH.U0f0sp ? ctx.ReadText(0, "") : default; + public string U0f0sp => which == WHICH.U0f0sp ? ctx.ReadText(0, null) : default; public bool U0f1s1 => which == WHICH.U0f1s1 ? ctx.ReadDataBool(64UL, false) : default; public sbyte U0f1s8 => which == WHICH.U0f1s8 ? ctx.ReadDataSByte(64UL, (sbyte)0) : default; public short U0f1s16 => which == WHICH.U0f1s16 ? ctx.ReadDataShort(64UL, (short)0) : default; public int U0f1s32 => which == WHICH.U0f1s32 ? ctx.ReadDataInt(64UL, 0) : default; public long U0f1s64 => which == WHICH.U0f1s64 ? ctx.ReadDataLong(64UL, 0L) : default; - public string U0f1sp => which == WHICH.U0f1sp ? ctx.ReadText(0, "") : default; + public string U0f1sp => which == WHICH.U0f1sp ? ctx.ReadText(0, null) : default; } public class WRITER : SerializerState @@ -2045,8 +2045,8 @@ namespace Capnproto_test.Capnp.Test public string U0f0sp { - get => which == WHICH.U0f0sp ? this.ReadText(0, "") : default; - set => this.WriteText(0, value, ""); + get => which == WHICH.U0f0sp ? this.ReadText(0, null) : default; + set => this.WriteText(0, value, null); } public bool U0f1s1 @@ -2081,8 +2081,8 @@ namespace Capnproto_test.Capnp.Test public string U0f1sp { - get => which == WHICH.U0f1sp ? this.ReadText(0, "") : default; - set => this.WriteText(0, value, ""); + get => which == WHICH.U0f1sp ? this.ReadText(0, null) : default; + set => this.WriteText(0, value, null); } } } @@ -2537,14 +2537,14 @@ namespace Capnproto_test.Capnp.Test public int U1f1s32 => which == WHICH.U1f1s32 ? ctx.ReadDataInt(160UL, 0) : default; public long U1f0s64 => which == WHICH.U1f0s64 ? ctx.ReadDataLong(192UL, 0L) : default; public long U1f1s64 => which == WHICH.U1f1s64 ? ctx.ReadDataLong(192UL, 0L) : default; - public string U1f0sp => which == WHICH.U1f0sp ? ctx.ReadText(1, "") : default; - public string U1f1sp => which == WHICH.U1f1sp ? ctx.ReadText(1, "") : default; + public string U1f0sp => which == WHICH.U1f0sp ? ctx.ReadText(1, null) : default; + public string U1f1sp => which == WHICH.U1f1sp ? ctx.ReadText(1, null) : default; public bool U1f2s1 => which == WHICH.U1f2s1 ? ctx.ReadDataBool(129UL, false) : default; public sbyte U1f2s8 => which == WHICH.U1f2s8 ? ctx.ReadDataSByte(136UL, (sbyte)0) : default; public short U1f2s16 => which == WHICH.U1f2s16 ? ctx.ReadDataShort(144UL, (short)0) : default; public int U1f2s32 => which == WHICH.U1f2s32 ? ctx.ReadDataInt(160UL, 0) : default; public long U1f2s64 => which == WHICH.U1f2s64 ? ctx.ReadDataLong(192UL, 0L) : default; - public string U1f2sp => which == WHICH.U1f2sp ? ctx.ReadText(1, "") : default; + public string U1f2sp => which == WHICH.U1f2sp ? ctx.ReadText(1, null) : default; } public class WRITER : SerializerState @@ -2621,14 +2621,14 @@ namespace Capnproto_test.Capnp.Test public string U1f0sp { - get => which == WHICH.U1f0sp ? this.ReadText(1, "") : default; - set => this.WriteText(1, value, ""); + get => which == WHICH.U1f0sp ? this.ReadText(1, null) : default; + set => this.WriteText(1, value, null); } public string U1f1sp { - get => which == WHICH.U1f1sp ? this.ReadText(1, "") : default; - set => this.WriteText(1, value, ""); + get => which == WHICH.U1f1sp ? this.ReadText(1, null) : default; + set => this.WriteText(1, value, null); } public bool U1f2s1 @@ -2663,8 +2663,8 @@ namespace Capnproto_test.Capnp.Test public string U1f2sp { - get => which == WHICH.U1f2sp ? this.ReadText(1, "") : default; - set => this.WriteText(1, value, ""); + get => which == WHICH.U1f2sp ? this.ReadText(1, null) : default; + set => this.WriteText(1, value, null); } } } @@ -3229,11 +3229,11 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public WHICH which => (WHICH)ctx.ReadDataUShort(32U, (ushort)0); - public string Before => ctx.ReadText(0, ""); + public string Before => ctx.ReadText(0, null); public ushort Foo => which == WHICH.Foo ? ctx.ReadDataUShort(0UL, (ushort)0) : default; public ushort Middle => ctx.ReadDataUShort(16UL, (ushort)0); public uint Bar => which == WHICH.Bar ? ctx.ReadDataUInt(64UL, 0U) : default; - public string After => ctx.ReadText(1, ""); + public string After => ctx.ReadText(1, null); } public class WRITER : SerializerState @@ -3251,8 +3251,8 @@ namespace Capnproto_test.Capnp.Test public string Before { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public ushort Foo @@ -3275,8 +3275,8 @@ namespace Capnproto_test.Capnp.Test public string After { - get => this.ReadText(1, ""); - set => this.WriteText(1, value, ""); + get => this.ReadText(1, null); + set => this.WriteText(1, value, null); } } } @@ -3882,7 +3882,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int Corge => ctx.ReadDataInt(0UL, 0); public long Grault => ctx.ReadDataLong(64UL, 0L); - public string Garply => ctx.ReadText(0, ""); + public string Garply => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -3905,8 +3905,8 @@ namespace Capnproto_test.Capnp.Test public string Garply { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -3970,8 +3970,8 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int Corge => ctx.ReadDataInt(0UL, 0); - public string Grault => ctx.ReadText(0, ""); - public string Garply => ctx.ReadText(1, ""); + public string Grault => ctx.ReadText(0, null); + public string Garply => ctx.ReadText(1, null); } public class WRITER : SerializerState @@ -3988,14 +3988,14 @@ namespace Capnproto_test.Capnp.Test public string Grault { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public string Garply { - get => this.ReadText(1, ""); - set => this.WriteText(1, value, ""); + get => this.ReadText(1, null); + set => this.WriteText(1, value, null); } } } @@ -4059,7 +4059,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int Corge => ctx.ReadDataInt(0UL, 0); - public string Grault => ctx.ReadText(0, ""); + public string Grault => ctx.ReadText(0, null); public long Garply => ctx.ReadDataLong(64UL, 0L); } @@ -4077,8 +4077,8 @@ namespace Capnproto_test.Capnp.Test public string Grault { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public long Garply @@ -4316,8 +4316,8 @@ namespace Capnproto_test.Capnp.Test public ulong Bar => ctx.ReadDataULong(64UL, 0UL); public ushort Qux => which == WHICH.Qux ? ctx.ReadDataUShort(192UL, (ushort)0) : default; public corge.READER Corge => which == WHICH.Corge ? new corge.READER(ctx) : default; - public string Waldo => ctx.ReadText(0, ""); - public string Fred => which == WHICH.Fred ? ctx.ReadText(2, "") : default; + public string Waldo => ctx.ReadText(0, null); + public string Fred => which == WHICH.Fred ? ctx.ReadText(2, null) : default; } public class WRITER : SerializerState @@ -4357,14 +4357,14 @@ namespace Capnproto_test.Capnp.Test public string Waldo { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public string Fred { - get => which == WHICH.Fred ? this.ReadText(2, "") : default; - set => this.WriteText(2, value, ""); + get => which == WHICH.Fred ? this.ReadText(2, null) : default; + set => this.WriteText(2, value, null); } } @@ -4436,8 +4436,8 @@ namespace Capnproto_test.Capnp.Test public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public ulong Grault => ctx.ReadDataULong(256UL, 0UL); public ushort Garply => ctx.ReadDataUShort(192UL, (ushort)0); - public string Plugh => ctx.ReadText(2, ""); - public string Xyzzy => ctx.ReadText(4, ""); + public string Plugh => ctx.ReadText(2, null); + public string Xyzzy => ctx.ReadText(4, null); } public class WRITER : SerializerState @@ -4460,14 +4460,14 @@ namespace Capnproto_test.Capnp.Test public string Plugh { - get => this.ReadText(2, ""); - set => this.WriteText(2, value, ""); + get => this.ReadText(2, null); + set => this.WriteText(2, value, null); } public string Xyzzy { - get => this.ReadText(4, ""); - set => this.WriteText(4, value, ""); + get => this.ReadText(4, null); + set => this.WriteText(4, value, null); } } } @@ -4626,8 +4626,8 @@ namespace Capnproto_test.Capnp.Test public ulong Bar => ctx.ReadDataULong(128UL, 0UL); public ushort Qux => which == WHICH.Qux ? ctx.ReadDataUShort(208UL, (ushort)0) : default; public corge.READER Corge => which == WHICH.Corge ? new corge.READER(ctx) : default; - public string Waldo => ctx.ReadText(1, ""); - public string Fred => which == WHICH.Fred ? ctx.ReadText(3, "") : default; + public string Waldo => ctx.ReadText(1, null); + public string Fred => which == WHICH.Fred ? ctx.ReadText(3, null) : default; } public class WRITER : SerializerState @@ -4667,14 +4667,14 @@ namespace Capnproto_test.Capnp.Test public string Waldo { - get => this.ReadText(1, ""); - set => this.WriteText(1, value, ""); + get => this.ReadText(1, null); + set => this.WriteText(1, value, null); } public string Fred { - get => which == WHICH.Fred ? this.ReadText(3, "") : default; - set => this.WriteText(3, value, ""); + get => which == WHICH.Fred ? this.ReadText(3, null) : default; + set => this.WriteText(3, value, null); } } @@ -4746,8 +4746,8 @@ namespace Capnproto_test.Capnp.Test public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public ulong Grault => ctx.ReadDataULong(320UL, 0UL); public ushort Garply => ctx.ReadDataUShort(208UL, (ushort)0); - public string Plugh => ctx.ReadText(3, ""); - public string Xyzzy => ctx.ReadText(5, ""); + public string Plugh => ctx.ReadText(3, null); + public string Xyzzy => ctx.ReadText(5, null); } public class WRITER : SerializerState @@ -4770,14 +4770,14 @@ namespace Capnproto_test.Capnp.Test public string Plugh { - get => this.ReadText(3, ""); - set => this.WriteText(3, value, ""); + get => this.ReadText(3, null); + set => this.WriteText(3, value, null); } public string Xyzzy { - get => this.ReadText(5, ""); - set => this.WriteText(5, value, ""); + get => this.ReadText(5, null); + set => this.WriteText(5, value, null); } } } @@ -5747,7 +5747,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string F => ctx.ReadText(0, ""); + public string F => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -5759,8 +5759,8 @@ namespace Capnproto_test.Capnp.Test public string F { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -5807,7 +5807,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -5819,8 +5819,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -5876,7 +5876,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public bool F => ctx.ReadDataBool(0UL, false); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -5894,8 +5894,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -5951,7 +5951,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public byte F => ctx.ReadDataByte(0UL, (byte)0); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -5969,8 +5969,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -6026,7 +6026,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public ushort F => ctx.ReadDataUShort(0UL, (ushort)0); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -6044,8 +6044,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -6101,7 +6101,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public uint F => ctx.ReadDataUInt(0UL, 0U); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -6119,8 +6119,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -6176,7 +6176,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public ulong F => ctx.ReadDataULong(0UL, 0UL); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -6194,8 +6194,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -6250,7 +6250,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string F => ctx.ReadText(0, ""); + public string F => ctx.ReadText(0, null); public ulong Pad => ctx.ReadDataULong(0UL, 0UL); } @@ -6263,8 +6263,8 @@ namespace Capnproto_test.Capnp.Test public string F { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public ulong Pad @@ -6527,7 +6527,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int Foo => ctx.ReadDataInt(0UL, 0); - public string Bar => ctx.ReadText(0, ""); + public string Bar => ctx.ReadText(0, null); public short Baz => ctx.ReadDataShort(32UL, (short)0); public theUnion.READER TheUnion => new theUnion.READER(ctx); public anotherUnion.READER AnotherUnion => new anotherUnion.READER(ctx); @@ -6548,8 +6548,8 @@ namespace Capnproto_test.Capnp.Test public string Bar { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public short Baz @@ -6693,7 +6693,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public WHICH which => (WHICH)ctx.ReadDataUShort(48U, (ushort)0); - public string Qux => which == WHICH.Qux ? ctx.ReadText(1, "") : default; + public string Qux => which == WHICH.Qux ? ctx.ReadText(1, null) : default; public IReadOnlyList Corge => which == WHICH.Corge ? ctx.ReadList(1).CastInt() : default; public float Grault => which == WHICH.Grault ? ctx.ReadDataFloat(64UL, 0F) : default; } @@ -6712,8 +6712,8 @@ namespace Capnproto_test.Capnp.Test public string Qux { - get => which == WHICH.Qux ? this.ReadText(1, "") : default; - set => this.WriteText(1, value, ""); + get => which == WHICH.Qux ? this.ReadText(1, null) : default; + set => this.WriteText(1, value, null); } public ListOfPrimitivesSerializer Corge @@ -6854,7 +6854,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public WHICH which => (WHICH)ctx.ReadDataUShort(96U, (ushort)0); - public string Qux => which == WHICH.Qux ? ctx.ReadText(2, "") : default; + public string Qux => which == WHICH.Qux ? ctx.ReadText(2, null) : default; public IReadOnlyList Corge => which == WHICH.Corge ? ctx.ReadList(2).CastInt() : default; public float Grault => which == WHICH.Grault ? ctx.ReadDataFloat(128UL, 0F) : default; } @@ -6873,8 +6873,8 @@ namespace Capnproto_test.Capnp.Test public string Qux { - get => which == WHICH.Qux ? this.ReadText(2, "") : default; - set => this.WriteText(2, value, ""); + get => which == WHICH.Qux ? this.ReadText(2, null) : default; + set => this.WriteText(2, value, null); } public ListOfPrimitivesSerializer Corge @@ -6951,7 +6951,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public long Old1 => ctx.ReadDataLong(0UL, 0L); - public string Old2 => ctx.ReadText(0, ""); + public string Old2 => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.TestOldVersion.READER Old3 => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestOldVersion.READER.create); } @@ -6970,8 +6970,8 @@ namespace Capnproto_test.Capnp.Test public string Old2 { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.TestOldVersion.WRITER Old3 @@ -7059,7 +7059,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public long Old1 => ctx.ReadDataLong(0UL, 0L); - public string Old2 => ctx.ReadText(0, ""); + public string Old2 => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.TestNewVersion.READER Old3 => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestNewVersion.READER.create); public long New1 => ctx.ReadDataLong(64UL, 987L); public string New2 => ctx.ReadText(2, "baz"); @@ -7080,8 +7080,8 @@ namespace Capnproto_test.Capnp.Test public string Old2 { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.TestNewVersion.WRITER Old3 @@ -7711,8 +7711,8 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string SomeText => ctx.ReadText(0, ""); - public string MoreText => ctx.ReadText(1, ""); + public string SomeText => ctx.ReadText(0, null); + public string MoreText => ctx.ReadText(1, null); } public class WRITER : SerializerState @@ -7724,14 +7724,14 @@ namespace Capnproto_test.Capnp.Test public string SomeText { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public string MoreText { - get => this.ReadText(1, ""); - set => this.WriteText(1, value, ""); + get => this.ReadText(1, null); + set => this.WriteText(1, value, null); } } } @@ -7787,7 +7787,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string SomeText => ctx.ReadText(0, ""); + public string SomeText => ctx.ReadText(0, null); public IReadOnlyList StructList => ctx.ReadList(1).Cast(Capnproto_test.Capnp.Test.TestPrintInlineStructs.InlineStruct.READER.create); } @@ -7800,8 +7800,8 @@ namespace Capnproto_test.Capnp.Test public string SomeText { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public ListOfStructsSerializer StructList @@ -7862,7 +7862,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int Int32Field => ctx.ReadDataInt(0UL, 0); - public string TextField => ctx.ReadText(0, ""); + public string TextField => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -7880,8 +7880,8 @@ namespace Capnproto_test.Capnp.Test public string TextField { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -10214,7 +10214,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string X => ctx.ReadText(0, ""); + public string X => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -10226,8 +10226,8 @@ namespace Capnproto_test.Capnp.Test public string X { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -11147,7 +11147,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string S => ctx.ReadText(0, ""); + public string S => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.TestPipeline.Box.READER OutBox => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestPipeline.Box.READER.create); } @@ -11160,8 +11160,8 @@ namespace Capnproto_test.Capnp.Test public string S { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.TestPipeline.Box.WRITER OutBox @@ -11432,7 +11432,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string S => ctx.ReadText(0, ""); + public string S => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.TestPipeline.AnyBox.READER OutBox => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestPipeline.AnyBox.READER.create); } @@ -11445,8 +11445,8 @@ namespace Capnproto_test.Capnp.Test public string S { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.TestPipeline.AnyBox.WRITER OutBox @@ -11731,7 +11731,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public uint I => ctx.ReadDataUInt(0UL, 0U); - public string T => ctx.ReadText(0, ""); + public string T => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.ITestCallOrder C => ctx.ReadCap(1); } @@ -11750,8 +11750,8 @@ namespace Capnproto_test.Capnp.Test public string T { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.ITestCallOrder C @@ -11813,7 +11813,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int I => ctx.ReadDataInt(0UL, 0); - public string T => ctx.ReadText(0, ""); + public string T => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -11831,8 +11831,8 @@ namespace Capnproto_test.Capnp.Test public string T { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -12448,7 +12448,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string S => ctx.ReadText(0, ""); + public string S => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -12460,8 +12460,8 @@ namespace Capnproto_test.Capnp.Test public string S { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -12568,7 +12568,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string S => ctx.ReadText(0, ""); + public string S => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -12580,8 +12580,8 @@ namespace Capnproto_test.Capnp.Test public string S { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -12898,7 +12898,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string S => ctx.ReadText(0, ""); + public string S => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -12910,8 +12910,8 @@ namespace Capnproto_test.Capnp.Test public string S { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -13306,7 +13306,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string A => ctx.ReadText(0, ""); + public string A => ctx.ReadText(0, null); public uint B => ctx.ReadDataUInt(0UL, 123U); public string C => ctx.ReadText(1, "foo"); } @@ -13320,8 +13320,8 @@ namespace Capnproto_test.Capnp.Test public string A { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public uint B @@ -13389,7 +13389,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string D => ctx.ReadText(0, ""); + public string D => ctx.ReadText(0, null); public string E => ctx.ReadText(1, "bar"); } @@ -13402,8 +13402,8 @@ namespace Capnproto_test.Capnp.Test public string D { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public string E @@ -13711,7 +13711,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Str => ctx.ReadText(0, ""); + public string Str => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -13723,8 +13723,8 @@ namespace Capnproto_test.Capnp.Test public string Str { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -13779,7 +13779,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string A => ctx.ReadText(0, ""); + public string A => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.ITestInterface B => ctx.ReadCap(1); } @@ -13792,8 +13792,8 @@ namespace Capnproto_test.Capnp.Test public string A { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.ITestInterface B @@ -14197,7 +14197,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Text => ctx.ReadText(0, ""); + public string Text => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -14209,8 +14209,8 @@ namespace Capnproto_test.Capnp.Test public string Text { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -14865,7 +14865,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Text => ctx.ReadText(0, ""); + public string Text => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.ITestInterface Cap => ctx.ReadCap(1); } @@ -14878,8 +14878,8 @@ namespace Capnproto_test.Capnp.Test public string Text { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.ITestInterface Cap @@ -15619,7 +15619,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Host => ctx.ReadText(0, ""); + public string Host => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -15631,8 +15631,8 @@ namespace Capnproto_test.Capnp.Test public string Host { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } diff --git a/CapnpC.CSharp.Generator/CodeGen/DomainClassSnippetGen.cs b/CapnpC.CSharp.Generator/CodeGen/DomainClassSnippetGen.cs index 17af353..fe7ba90 100644 --- a/CapnpC.CSharp.Generator/CodeGen/DomainClassSnippetGen.cs +++ b/CapnpC.CSharp.Generator/CodeGen/DomainClassSnippetGen.cs @@ -284,7 +284,8 @@ namespace CapnpC.CSharp.Generator.CodeGen value.Decode(); return ArrayCreationExpression(ArrayType( - _names.MakeTypeSyntax(value.Type.ElementType, scope, TypeUsage.DomainClass, Nullability.NullableRef)) + _names.MakeTypeSyntax(value.Type.ElementType, scope, TypeUsage.DomainClass, + _names.GetDefaultElementTypeNullability(value.Type.ElementType))) .WithRankSpecifiers( SingletonList( ArrayRankSpecifier( @@ -619,13 +620,14 @@ namespace CapnpC.CSharp.Generator.CodeGen IdentifierName(nameof(Capnp.ReadOnlyListExtensions.ToReadOnlyList)))) .AddArgumentListArguments(Argument( SimpleLambdaExpression(Parameter(Identifier("_")), - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nameof(Capnp.CapnpSerializable)), - GenericName(nameof(Capnp.CapnpSerializable.Create)) - .AddTypeArgumentListArguments(MakeNonNullableType(elementType)))) - .AddArgumentListArguments(Argument(IdentifierName("_"))))))); + _names.SuppressNullableWarning( + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName(nameof(Capnp.CapnpSerializable)), + GenericName(nameof(Capnp.CapnpSerializable.Create)) + .AddTypeArgumentListArguments(MakeNonNullableType(elementType)))) + .AddArgumentListArguments(Argument(IdentifierName("_")))))))); } ExpressionSyntax MakeStructListConversion(ExpressionSyntax context, TypeSyntax elementType, int rank) diff --git a/CapnpC.CSharp.Generator/CodeGen/GenNames.cs b/CapnpC.CSharp.Generator/CodeGen/GenNames.cs index b16ff99..afcdf19 100644 --- a/CapnpC.CSharp.Generator/CodeGen/GenNames.cs +++ b/CapnpC.CSharp.Generator/CodeGen/GenNames.cs @@ -387,6 +387,23 @@ namespace CapnpC.CSharp.Generator.CodeGen } } + public Nullability GetDefaultElementTypeNullability(Model.Type type) + { + switch (type.Tag) + { + case TypeTag.Data: + case TypeTag.Text: + case TypeTag.Interface: + case TypeTag.List: + case TypeTag.ListPointer: + case TypeTag.StructPointer: + return Nullability.NullableRef; + + default: + return Nullability.NonNullable; + } + } + public TypeSyntax MakeTypeSyntax(Model.Type type, TypeDefinition scope, TypeUsage usage, Nullability nullability) { switch (type.Tag) @@ -483,11 +500,13 @@ namespace CapnpC.CSharp.Generator.CodeGen case TypeUsage.Reader: return MaybeNullableRefType(GenericName(Identifier("IReadOnlyList")) - .AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, TypeUsage.Reader, Nullability.NonNullable)), nullability); + .AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, TypeUsage.Reader, + GetDefaultElementTypeNullability(type.ElementType))), nullability); case TypeUsage.DomainClass: return MaybeNullableRefType(GenericName(Identifier("IReadOnlyList")) - .AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, TypeUsage.DomainClass, Nullability.NullableRef)), nullability); + .AddTypeArgumentListArguments(MakeTypeSyntax(type.ElementType, scope, TypeUsage.DomainClass, + GetDefaultElementTypeNullability(type.ElementType))), nullability); default: throw new NotImplementedException(); From ce9260198ff324972193b760033728b0b6578105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 1 Mar 2020 14:12:20 +0100 Subject: [PATCH 06/76] added tests for CapnpSerializable --- Capnp.Net.Runtime.Tests/SerializationTests.cs | 224 ++++++++++++++++++ Capnp.Net.Runtime/CapnpSerializable.cs | 32 +-- .../ListOfPrimitivesSerializer.cs | 5 +- 3 files changed, 245 insertions(+), 16 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs index 75b1aa2..035d562 100644 --- a/Capnp.Net.Runtime.Tests/SerializationTests.cs +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -290,5 +290,229 @@ namespace Capnp.Net.Runtime.Tests Assert.IsNull(list3[2]); Assert.AreEqual("3", list3[3]); } + + [TestMethod] + public void CapnpSerializableListBool() + { + var expected = new bool[] { true, false, true }; + var b = MessageBuilder.Create(); + var list = b.CreateObject(); + list.Init(expected); + DeserializerState d = list; + var list2 = CapnpSerializable.Create>(d); + CollectionAssert.AreEqual(expected, list2.ToArray()); + } + + [TestMethod] + public void CapnpSerializableListByte() + { + var expected = new byte[] { 1, 2, 3 }; + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + list.Init(expected); + DeserializerState d = list; + var list2 = CapnpSerializable.Create>(d); + CollectionAssert.AreEqual(expected, list2.ToArray()); + } + + [TestMethod] + public void CapnpSerializableListSByte() + { + var expected = new sbyte[] { -1, -2, -3 }; + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + list.Init(expected); + DeserializerState d = list; + var list2 = CapnpSerializable.Create>(d); + CollectionAssert.AreEqual(expected, list2.ToArray()); + } + + [TestMethod] + public void CapnpSerializableListUShort() + { + var expected = new ushort[] { 1, 2, 3 }; + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + list.Init(expected); + DeserializerState d = list; + var list2 = CapnpSerializable.Create>(d); + CollectionAssert.AreEqual(expected, list2.ToArray()); + } + + [TestMethod] + public void CapnpSerializableListShort() + { + var expected = new short[] { -1, -2, -3 }; + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + list.Init(expected); + DeserializerState d = list; + var list2 = CapnpSerializable.Create>(d); + CollectionAssert.AreEqual(expected, list2.ToArray()); + } + + [TestMethod] + public void CapnpSerializableListInt() + { + var expected = new int[] { -1, -2, -3 }; + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + list.Init(expected); + DeserializerState d = list; + var list2 = CapnpSerializable.Create>(d); + CollectionAssert.AreEqual(expected, list2.ToArray()); + } + + [TestMethod] + public void CapnpSerializableListUInt() + { + var expected = new uint[] { 1, 2, 3 }; + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + list.Init(expected); + DeserializerState d = list; + var list2 = CapnpSerializable.Create>(d); + CollectionAssert.AreEqual(expected, list2.ToArray()); + } + + [TestMethod] + public void CapnpSerializableListLong() + { + var expected = new long[] { -1, -2, -3 }; + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + list.Init(expected); + DeserializerState d = list; + var list2 = CapnpSerializable.Create>(d); + CollectionAssert.AreEqual(expected, list2.ToArray()); + } + + [TestMethod] + public void CapnpSerializableListULong() + { + var expected = new ulong[] { 1, 2, 3 }; + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + list.Init(expected); + DeserializerState d = list; + var list2 = CapnpSerializable.Create>(d); + CollectionAssert.AreEqual(expected, list2.ToArray()); + } + + [TestMethod] + public void CapnpSerializableListFloat() + { + var expected = new float[] { -1.0f, 2.0f, -3.0f }; + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + list.Init(expected); + DeserializerState d = list; + var list2 = CapnpSerializable.Create>(d); + CollectionAssert.AreEqual(expected, list2.ToArray()); + } + + [TestMethod] + public void CapnpSerializableListDouble() + { + var expected = new double[] { -1, -2, -3 }; + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + list.Init(expected); + DeserializerState d = list; + var list2 = CapnpSerializable.Create>(d); + CollectionAssert.AreEqual(expected, list2.ToArray()); + } + + [TestMethod] + public void CapnpSerializableStruct() + { + var b = MessageBuilder.Create(); + var obj = b.CreateObject(); + obj.SomeText = "hello"; + obj.MoreText = "world"; + DeserializerState d = obj; + var obj2 = CapnpSerializable.Create(d); + Assert.AreEqual("hello", obj2.SomeText); + Assert.AreEqual("world", obj2.MoreText); + } + + [TestMethod] + public void CapnpSerializableCapList() + { + var b = MessageBuilder.Create(); + b.InitCapTable(); + var wr = b.CreateObject>(); + var c1 = new Counters(); + var cap1 = new TestInterfaceImpl(c1); + var c2 = new Counters(); + var cap2 = new TestInterfaceImpl(c2); + wr.Init(new ITestInterface[] { null, cap1, cap2 }); + DeserializerState d = wr; + var list = CapnpSerializable.Create>(d); + list[1].Foo(123u, true); + Assert.AreEqual(1, c1.CallCount); + list[2].Foo(123u, true); + Assert.AreEqual(1, c2.CallCount); + } + + [TestMethod] + public void CapnpSerializableString() + { + string expected = "1, 2, 3"; + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + var bytes = Encoding.UTF8.GetBytes(expected); + list.Init(bytes.Length + 1); + bytes.CopyTo(list.Data); + DeserializerState d = list; + var str = CapnpSerializable.Create(d); + Assert.AreEqual(expected, str); + } + + class Unconstructible1 : ICapnpSerializable + { + public Unconstructible1(int annoyingParameter) + { + + } + + public void Deserialize(DeserializerState state) + { + throw new NotImplementedException(); + } + + public void Serialize(SerializerState state) + { + throw new NotImplementedException(); + } + } + + class Unconstructible2 : ICapnpSerializable + { + public Unconstructible2() + { + throw new NotImplementedException(); + } + + public void Deserialize(DeserializerState state) + { + throw new NotImplementedException(); + } + + public void Serialize(SerializerState state) + { + throw new NotImplementedException(); + } + } + + [TestMethod] + public void CapnpSerializableWrongUse() + { + var d = default(DeserializerState); + Assert.ThrowsException(() => CapnpSerializable.Create(d)); + Assert.ThrowsException(() => CapnpSerializable.Create>(d)); + Assert.ThrowsException(() => CapnpSerializable.Create(d)); + Assert.ThrowsException(() => CapnpSerializable.Create(d)); + } } } diff --git a/Capnp.Net.Runtime/CapnpSerializable.cs b/Capnp.Net.Runtime/CapnpSerializable.cs index 631f869..9f33940 100644 --- a/Capnp.Net.Runtime/CapnpSerializable.cs +++ b/Capnp.Net.Runtime/CapnpSerializable.cs @@ -36,7 +36,8 @@ namespace Capnp public FromList() { - _elementSerializer = (Func)GetSerializer(typeof(T)); + var deser = GetSerializer(typeof(T)); + _elementSerializer = d => (deser(d) as T)!; } public object Create(DeserializerState state) @@ -147,28 +148,29 @@ namespace Capnp /// /// Type implementing . The type must must have a public parameterless constructor. /// A capability interface ( for further explanation) - /// - /// IReadOnlyList{Boolean} - /// IReadOnlyList{SByte}" - /// IReadOnlyList{Byte}" - /// IReadOnlyList{Int16}" - /// IReadOnlyList{UInt16}" - /// IReadOnlyList{Int32}" - /// IReadOnlyList{UInt32}" - /// IReadOnlyList{Int64}" - /// IReadOnlyList{UInt64}" - /// IReadOnlyList{Single}" - /// IReadOnlyList{Double}" - /// IReadOnlyList{T} whereby T is one of the things listed here. + /// + /// IReadOnlyList<bool>, IReadOnlyList<sbyte>, IReadOnlyList<byte> + /// IReadOnlyList<short>, IReadOnlyList<ushort>, IReadOnlyList<int> + /// IReadOnlyList<uint>, IReadOnlyList<long>, IReadOnlyList<ulong> + /// IReadOnlyList<float>, IReadOnlyList<double> + /// IReadOnlyList<T> whereby T is one of the things listed here. /// /// /// deserializer state to construct from /// The domain object instance. Nullability note: The returned reference may be null if /// represents the nil object. + /// Cannot construct object of type public static T? Create(DeserializerState state) where T: class { - return (T?)GetSerializer(typeof(T))(state); + try + { + return (T?)GetSerializer(typeof(T))(state); + } + catch (TargetInvocationException ex) + { + throw new ArgumentException("Failed to construct domain object", ex); + } } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs b/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs index 7f53839..3ff7219 100644 --- a/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs +++ b/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs @@ -28,7 +28,10 @@ namespace Capnp } } - Span Data => MemoryMarshal.Cast(RawData); + /// + /// The list's data + /// + public Span Data => MemoryMarshal.Cast(RawData); /// /// Gets or sets the value at given index. From 768999b66625c2f90f3df9c97d178efbf624d96a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 1 Mar 2020 14:17:34 +0100 Subject: [PATCH 07/76] coveralls cmd line --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 67656b3..28c9e1b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -91,7 +91,7 @@ test_script: vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll - ps: | .\scripts\measure-coverage.ps1 - csmacnz.Coveralls --reportgenerator -i coverage/report --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID + csmacnz.Coveralls --multiple -i "opencover=coverage\cov-Capnp.Net.Runtime-dnc21.xml;opencover=coverage\cov-Capnp.Net.Runtime-net471.xml;opencover=coverage\cov-CapnpC.CSharp.Generator.xml" --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID on_finish : # any cleanup in here deploy: From 6a87cb7daccbbbe36faeb2bb92daee0c1d527e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 1 Mar 2020 17:18:25 +0100 Subject: [PATCH 08/76] added tests for DynamicSerializerState --- Capnp.Net.Runtime.Tests/SerializationTests.cs | 210 ++++++++++++++++++ Capnp.Net.Runtime.Tests/TcpRpcInterop.cs | 1 + Capnp.Net.Runtime/DynamicSerializerState.cs | 33 +-- Capnp.Net.Runtime/PrimitiveCoder.cs | 45 ---- Capnp.Net.Runtime/SerializerState.cs | 33 ++- 5 files changed, 244 insertions(+), 78 deletions(-) delete mode 100644 Capnp.Net.Runtime/PrimitiveCoder.cs 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. From 89a9e7b5ac7105c8e0383b0b35d2045a7dfdb858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 1 Mar 2020 17:56:14 +0100 Subject: [PATCH 09/76] more tests for improved coverage --- .../DeserializationTests.cs | 40 ++++++++++++++++++- Capnp.Net.Runtime.Tests/SerializationTests.cs | 17 ++++++++ Capnp.Net.Runtime/EmptyList.cs | 6 +-- Capnp.Net.Runtime/ListDeserializer.cs | 13 +++--- Capnp.Net.Runtime/ListOfBitsSerializer.cs | 37 ++++------------- 5 files changed, 72 insertions(+), 41 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/DeserializationTests.cs b/Capnp.Net.Runtime.Tests/DeserializationTests.cs index 647799b..5d543bb 100644 --- a/Capnp.Net.Runtime.Tests/DeserializationTests.cs +++ b/Capnp.Net.Runtime.Tests/DeserializationTests.cs @@ -1,4 +1,7 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Capnproto_test.Capnp.Test; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Linq; namespace Capnp.Net.Runtime.Tests { @@ -354,5 +357,40 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(double.NegativeInfinity, asListOfDoubles[0]); Assert.AreEqual(double.MaxValue, asListOfDoubles[1]); } + + [TestMethod] + public void NestedLists() + { + var expected = new int[][] { + new int[] { 1, 2, 3 }, + new int[] { 4, 5 }, + new int[] { 6 } }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + var ld = d.RequireList(); + var result = ld.Cast2D(); + Assert.AreEqual(3, result.Count); + for (int i = 0; i < result.Count; i++) + { + CollectionAssert.AreEqual(expected[i], result[i].ToArray()); + } + + Assert.ThrowsException(() => ld.Cast2D()); + } + + [TestMethod] + public void LinearListWrongUse() + { + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(new int[] { 1, 2, 3 }); + DeserializerState d = dss; + var ld = d.RequireList(); + Assert.ThrowsException(() => ld.CastList()); + Assert.ThrowsException(() => ld.CastCapList()); + } } } diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs index f719dc6..153feb8 100644 --- a/Capnp.Net.Runtime.Tests/SerializationTests.cs +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -79,6 +79,8 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => { list[0] = null; }); list.Init(5); Assert.ThrowsException(() => list.Init(1)); + Assert.ThrowsException(() => { var _ = list[5]; }); + Assert.ThrowsException(() => { list[-1] = null; }); var c1 = new Counters(); var cap1 = new TestInterfaceImpl(c1); var c2 = new Counters(); @@ -152,6 +154,8 @@ namespace Capnp.Net.Runtime.Tests list.Init(7); Assert.ThrowsException(() => list.Init(1)); Assert.AreEqual(7, list.Count); + Assert.ThrowsException(() => { var _ = list[-1]; }); + Assert.ThrowsException(() => { list[7] = null; }); var c1 = new Counters(); var cap1 = new TestInterfaceImpl(c1); var obj1 = b.CreateObject(); @@ -234,6 +238,7 @@ namespace Capnp.Net.Runtime.Tests list.Init(4); Assert.ThrowsException(() => list.Init(1)); Assert.AreEqual(4, list.Count); + Assert.ThrowsException(() => { var _ = list[5]; }); list[0].SomeText = "0"; list[1].SomeText = "1"; list[2].SomeText = "2"; @@ -265,6 +270,8 @@ namespace Capnp.Net.Runtime.Tests list.Init(4); Assert.ThrowsException(() => list.Init(1)); Assert.AreEqual(4, list.Count); + Assert.ThrowsException(() => { var _ = list[5]; }); + Assert.ThrowsException(() => { list[-1] = null; }); list[0] = "0"; list[2] = null; list[3] = "3"; @@ -724,5 +731,15 @@ namespace Capnp.Net.Runtime.Tests DeserializerState d2 = dss; CollectionAssert.AreEqual(expected, d2.RequireList().CastText2().ToArray()); } + + [TestMethod] + public void EmptyListContract() + { + var list = new EmptyList(); + Assert.AreEqual(0, list.Count); + Assert.ThrowsException(() => { var _ = list[-1]; }); + Assert.ThrowsException(() => { var _ = list[0]; }); + Assert.AreEqual(0, list.ToArray().Length); + } } } diff --git a/Capnp.Net.Runtime/EmptyList.cs b/Capnp.Net.Runtime/EmptyList.cs index 0c1ebc6..c719551 100644 --- a/Capnp.Net.Runtime/EmptyList.cs +++ b/Capnp.Net.Runtime/EmptyList.cs @@ -8,14 +8,14 @@ namespace Capnp /// /// Implements an empty . /// - /// + /// list element type public class EmptyList : IReadOnlyList { /// - /// Always throws an . + /// Always throws an . /// /// Ignored - public T this[int index] => throw new ArgumentOutOfRangeException(nameof(index)); + public T this[int index] => throw new IndexOutOfRangeException(nameof(index)); /// /// Always 0. diff --git a/Capnp.Net.Runtime/ListDeserializer.cs b/Capnp.Net.Runtime/ListDeserializer.cs index 6d28ab9..e8499a6 100644 --- a/Capnp.Net.Runtime/ListDeserializer.cs +++ b/Capnp.Net.Runtime/ListDeserializer.cs @@ -11,6 +11,9 @@ namespace Capnp static class GenericCasts { public static Func? CastFunc; + + public static Func GetCastFunc() => CastFunc ?? + throw new NotSupportedException("Requested cast is not supported"); } static ListDeserializer() @@ -45,12 +48,7 @@ namespace Capnp T Cast() { - var func = GenericCasts.CastFunc; - - if (func == null) - throw new NotSupportedException("Requested cast is not supported"); - - return func(this); + return GenericCasts.GetCastFunc()(this); } /// @@ -91,7 +89,7 @@ namespace Capnp /// If does not qualify as capability interface. public virtual IReadOnlyList CastCapList() where T: class { - throw new NotSupportedException("This kind of list does not contain nested lists"); + throw new NotSupportedException("This kind of list cannot be represented as list of capabilities"); } object CastND(int n, Func func) @@ -158,6 +156,7 @@ namespace Capnp /// If this list cannot be represented in the desired manner. public IReadOnlyList> Cast2D() { + GenericCasts>.GetCastFunc(); // Probe to avoid lazy NotSupportedException return CastList().LazyListSelect(ld => ld.Cast>()); } diff --git a/Capnp.Net.Runtime/ListOfBitsSerializer.cs b/Capnp.Net.Runtime/ListOfBitsSerializer.cs index 2e5a94f..3e90aa8 100644 --- a/Capnp.Net.Runtime/ListOfBitsSerializer.cs +++ b/Capnp.Net.Runtime/ListOfBitsSerializer.cs @@ -11,35 +11,6 @@ namespace Capnp /// public class ListOfBitsSerializer: SerializerState, IReadOnlyList { - class Enumerator : IEnumerator - { - readonly ListOfBitsSerializer _self; - int _pos = -1; - - public Enumerator(ListOfBitsSerializer self) - { - _self = self; - } - - public bool Current => _pos >= 0 && _pos < _self.Count ? _self[_pos] : false; - - object IEnumerator.Current => Current; - - public void Dispose() - { - } - - public bool MoveNext() - { - return ++_pos < _self.Count; - } - - public void Reset() - { - _pos = -1; - } - } - /// /// Gets or sets the element at given index. /// @@ -121,10 +92,16 @@ namespace Capnp } } + IEnumerable Enumerate() + { + for (int i = 0; i < Count; i++) + yield return this[i]; + } + /// /// Implements /// - public IEnumerator GetEnumerator() => new Enumerator(this); + public IEnumerator GetEnumerator() => Enumerate().GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } From e1abf7b61cb32035d19997c4799d2c9dbb28dce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 1 Mar 2020 17:56:51 +0100 Subject: [PATCH 10/76] cmd line tweak --- appveyor.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 28c9e1b..90cb83c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -89,9 +89,8 @@ test_script: vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Release\net471\Capnp.Net.Runtime.Tests.Std20.dll vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Debug\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll - - ps: | - .\scripts\measure-coverage.ps1 - csmacnz.Coveralls --multiple -i "opencover=coverage\cov-Capnp.Net.Runtime-dnc21.xml;opencover=coverage\cov-Capnp.Net.Runtime-net471.xml;opencover=coverage\cov-CapnpC.CSharp.Generator.xml" --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID + powershell -File .\scripts\measure-coverage.ps1 + csmacnz.Coveralls --multiple -i "opencover=coverage\cov-Capnp.Net.Runtime-dnc21.xml;opencover=coverage\cov-Capnp.Net.Runtime-net471.xml;opencover=coverage\cov-CapnpC.CSharp.Generator.xml" --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID on_finish : # any cleanup in here deploy: From 15a11391e04ac8262079509adf1711120e7c1073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Mon, 2 Mar 2020 18:03:46 +0100 Subject: [PATCH 11/76] added nested lists test appveyor coverage upload fix --- .../DeserializationTests.cs | 39 +++++++++++++++++++ appveyor.yml | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Capnp.Net.Runtime.Tests/DeserializationTests.cs b/Capnp.Net.Runtime.Tests/DeserializationTests.cs index 5d543bb..75536a6 100644 --- a/Capnp.Net.Runtime.Tests/DeserializationTests.cs +++ b/Capnp.Net.Runtime.Tests/DeserializationTests.cs @@ -1,6 +1,7 @@ using Capnproto_test.Capnp.Test; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; +using System.Collections.Generic; using System.Linq; namespace Capnp.Net.Runtime.Tests @@ -392,5 +393,43 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => ld.CastList()); Assert.ThrowsException(() => ld.CastCapList()); } + + [TestMethod] + public void NestedListsND() + { + var expected = new int[][][] { + new int[][] + { + new int[] { 1, 2, 3 }, + new int[] { 4, 5 }, + new int[] { 6 } + }, + new int[][] + { + new int[] { 1, 2, 3 }, + new int[0] + }, + new int[0][] + }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + var ld = d.RequireList(); + var result = (IReadOnlyList)ld.CastND(3); + Assert.AreEqual(3, result.Count); + for (int i = 0; i < result.Count; i++) + { + var inner = (IReadOnlyList)result[i]; + Assert.AreEqual(expected[i].Length, inner.Count); + + for (int j = 0; j < expected[i].Length; i++) + { + var inner2 = (IReadOnlyList)inner[j]; + CollectionAssert.AreEqual(expected[i][j], inner2.ToArray()); + } + } + } } } diff --git a/appveyor.yml b/appveyor.yml index 90cb83c..fff160f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -90,7 +90,7 @@ test_script: vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Debug\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll powershell -File .\scripts\measure-coverage.ps1 - csmacnz.Coveralls --multiple -i "opencover=coverage\cov-Capnp.Net.Runtime-dnc21.xml;opencover=coverage\cov-Capnp.Net.Runtime-net471.xml;opencover=coverage\cov-CapnpC.CSharp.Generator.xml" --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID + csmacnz.Coveralls --multiple -i "opencover=coverage\cov-Capnp.Net.Runtime-dnc21.xml;opencover=coverage\cov-Capnp.Net.Runtime-net471.xml;opencover=coverage\cov-CapnpC.CSharp.Generator.xml" --repoToken %COVERALLS_REPO_TOKEN% on_finish : # any cleanup in here deploy: From b5cd48e3fccfdec239d601933b59d6848318a65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 3 Mar 2020 21:42:53 +0100 Subject: [PATCH 12/76] more tests --- .../DeserializationTests.cs | 338 +++++++++++++++++- 1 file changed, 337 insertions(+), 1 deletion(-) diff --git a/Capnp.Net.Runtime.Tests/DeserializationTests.cs b/Capnp.Net.Runtime.Tests/DeserializationTests.cs index 75536a6..51e50b8 100644 --- a/Capnp.Net.Runtime.Tests/DeserializationTests.cs +++ b/Capnp.Net.Runtime.Tests/DeserializationTests.cs @@ -3,6 +3,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.Linq; +using static Capnproto_test.Capnp.Test.TestStructUnion; namespace Capnp.Net.Runtime.Tests { @@ -212,6 +213,22 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(double.PositiveInfinity, asListOfStructs[5].ReadDataDouble(0)); } + [TestMethod] + public void ListOfStructsAsListOfBools() + { + var ds = new DynamicSerializerState(MessageBuilder.Create(128)); + ds.SetListOfStructs(3, 1, 0); + ds.ListBuildStruct(1).WriteData(0, false); + ds.ListBuildStruct(2).WriteData(0, true); + + DeserializerState d = ds; + var asListOfBools = d.RequireList().CastBool(); + Assert.AreEqual(3, asListOfBools.Count); + Assert.AreEqual(false, asListOfBools[0]); + Assert.AreEqual(false, asListOfBools[1]); + Assert.AreEqual(true, asListOfBools[2]); + } + [TestMethod] public void ListOfStructsAsListOfBytes() { @@ -372,6 +389,7 @@ namespace Capnp.Net.Runtime.Tests dss.SetObject(expected); DeserializerState d = dss; var ld = d.RequireList(); + Assert.ThrowsException(() => ld.CastText()); var result = ld.Cast2D(); Assert.AreEqual(3, result.Count); for (int i = 0; i < result.Count; i++) @@ -394,6 +412,44 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => ld.CastCapList()); } + [TestMethod] + public void NestedLists3D() + { + var expected = new int[][][] { + new int[][] + { + new int[] { 1, 2, 3 }, + new int[] { 4, 5 }, + new int[] { 6 } + }, + new int[][] + { + new int[] { 1, 2, 3 }, + new int[0] + }, + new int[0][] + }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + var ld = d.RequireList(); + var result = ld.Cast3D(); + Assert.AreEqual(3, result.Count); + for (int i = 0; i < result.Count; i++) + { + var inner = result[i]; + Assert.AreEqual(expected[i].Length, inner.Count); + + for (int j = 0; j < expected[i].Length; j++) + { + var inner2 = inner[j]; + CollectionAssert.AreEqual(expected[i][j], inner2.ToArray()); + } + } + } + [TestMethod] public void NestedListsND() { @@ -424,12 +480,292 @@ namespace Capnp.Net.Runtime.Tests var inner = (IReadOnlyList)result[i]; Assert.AreEqual(expected[i].Length, inner.Count); - for (int j = 0; j < expected[i].Length; i++) + for (int j = 0; j < expected[i].Length; j++) { var inner2 = (IReadOnlyList)inner[j]; CollectionAssert.AreEqual(expected[i][j], inner2.ToArray()); } } } + + [TestMethod] + public void NestedLists3DStruct() + { + var expected = new List>>(); + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + for (int i = 0; i < 3; i++) + { + expected.Add(new List>()); + + for (int j = 0; j <= i; j++) + { + expected[i].Add(new List()); + + for (int k = 0; k <= j; k++) + { + var x = b.CreateObject(); + x.SomeText = $"{i}, {j}, {k}"; + expected[i][j].Add(x); + } + } + } + + dss.SetObject(expected); + DeserializerState d = dss; + var ld = d.RequireList(); + var result = ld.Cast3D(_ => new SomeStruct.READER(_)); + Assert.AreEqual(3, result.Count); + for (int i = 0; i < result.Count; i++) + { + var inner = result[i]; + Assert.AreEqual(i + 1, inner.Count); + + for (int j = 0; j < inner.Count; j++) + { + var inner2 = inner[j]; + Assert.AreEqual(j + 1, inner2.Count); + + for (int k = 0; k < inner2.Count; k++) + { + Assert.AreEqual($"{i}, {j}, {k}", inner2[k].SomeText); + } + } + } + } + + [TestMethod] + public void NestedListsNDStruct() + { + var expected = new List>>(); + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + for (int i = 0; i < 3; i++) + { + expected.Add(new List>()); + + for (int j = 0; j <= i; j++) + { + expected[i].Add(new List()); + + for (int k = 0; k <= j; k++) + { + var x = b.CreateObject(); + x.SomeText = $"{i}, {j}, {k}"; + expected[i][j].Add(x); + } + } + } + + dss.SetObject(expected); + DeserializerState d = dss; + var ld = d.RequireList(); + var result = (IReadOnlyList)ld.CastND(3, _ => new SomeStruct.READER(_)); + Assert.AreEqual(3, result.Count); + for (int i = 0; i < result.Count; i++) + { + var inner = (IReadOnlyList)result[i]; + Assert.AreEqual(i + 1, inner.Count); + + for (int j = 0; j < inner.Count; j++) + { + var inner2 = (IReadOnlyList)inner[j]; + Assert.AreEqual(j + 1, inner2.Count); + + for (int k = 0; k < inner2.Count; k++) + { + Assert.AreEqual($"{i}, {j}, {k}", inner2[k].SomeText); + } + } + } + } + + [TestMethod] + public void NestedLists2DStruct() + { + var expected = new List>(); + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + for (int i = 0; i < 3; i++) + { + expected.Add(new List()); + + for (int j = 0; j <= i; j++) + { + var x = b.CreateObject(); + x.SomeText = $"{i}, {j}"; + expected[i].Add(x); + } + } + + dss.SetObject(expected); + DeserializerState d = dss; + var ld = d.RequireList(); + var result = ld.Cast2D(_ => new SomeStruct.READER(_)); + Assert.AreEqual(3, result.Count); + for (int i = 0; i < result.Count; i++) + { + var inner = result[i]; + Assert.AreEqual(i + 1, inner.Count); + + for (int j = 0; j < inner.Count; j++) + { + Assert.AreEqual($"{i}, {j}", inner[j].SomeText); + } + } + } + + [TestMethod] + public void ListOfEnums() + { + var expected = new TestEnum[] { TestEnum.bar, TestEnum.baz, TestEnum.corge }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + var ld = d.RequireList(); + var result = ld.CastEnums(_ => (TestEnum)_); + CollectionAssert.AreEqual(expected, result.ToArray()); + } + + [TestMethod] + public void NestedLists2DEnum() + { + var expected = new TestEnum[][] + { + new TestEnum[] { TestEnum.bar, TestEnum.baz, TestEnum.corge }, + new TestEnum[] { TestEnum.corge, TestEnum.foo, TestEnum.garply } + }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + var ld = d.RequireList(); + var result = ld.CastEnums2D(_ => (TestEnum)_); + Assert.AreEqual(expected.Length, result.Count); + for (int i = 0; i < result.Count; i++) + { + CollectionAssert.AreEqual(expected[i], result[i].ToArray()); + } + } + + [TestMethod] + public void NestedLists3DEnum() + { + var expected = new TestEnum[][][] { + new TestEnum[][] + { + new TestEnum[] { TestEnum.qux, TestEnum.quux, TestEnum.grault }, + new TestEnum[] { TestEnum.garply, TestEnum.foo }, + new TestEnum[] { TestEnum.corge } + }, + new TestEnum[][] + { + new TestEnum[] { TestEnum.baz, TestEnum.bar }, + new TestEnum[0] + }, + new TestEnum[0][] + }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + var ld = d.RequireList(); + var result = ld.CastEnums3D(_ => (TestEnum)_); + Assert.AreEqual(3, result.Count); + for (int i = 0; i < result.Count; i++) + { + var inner = result[i]; + Assert.AreEqual(expected[i].Length, inner.Count); + + for (int j = 0; j < expected[i].Length; j++) + { + var inner2 = inner[j]; + CollectionAssert.AreEqual(expected[i][j], inner2.ToArray()); + } + } + } + + [TestMethod] + public void NestedListsNDEnum() + { + var expected = new TestEnum[][][] { + new TestEnum[][] + { + new TestEnum[] { TestEnum.qux, TestEnum.quux, TestEnum.grault }, + new TestEnum[] { TestEnum.garply, TestEnum.foo }, + new TestEnum[] { TestEnum.corge } + }, + new TestEnum[][] + { + new TestEnum[] { TestEnum.baz, TestEnum.bar }, + new TestEnum[0] + }, + new TestEnum[0][] + }; + + var b = MessageBuilder.Create(); + var dss = b.CreateObject(); + dss.SetObject(expected); + DeserializerState d = dss; + var ld = d.RequireList(); + var result = (IReadOnlyList)ld.CastEnumsND(3, _ => (TestEnum)_); + Assert.AreEqual(3, result.Count); + for (int i = 0; i < result.Count; i++) + { + var inner = (IReadOnlyList)result[i]; + Assert.AreEqual(expected[i].Length, inner.Count); + + for (int j = 0; j < expected[i].Length; j++) + { + var inner2 = (IReadOnlyList)inner[j]; + CollectionAssert.AreEqual(expected[i][j], inner2.ToArray()); + } + } + } + + [TestMethod] + public void NestedLists2DVoid() + { + var b = MessageBuilder.Create(); + var s = b.CreateObject>(); + s.Init(3); + s[0].Init(4); + s[1].Init(5); + s[2].Init(6); + DeserializerState d = s; + var voids = d.RequireList().CastVoid2D(); + CollectionAssert.AreEqual(new int[] { 4, 5, 6 }, voids.ToArray()); + } + + [TestMethod] + public void NestedLists3DVoid() + { + var expected = new int[][] { + new int[] { 1, 2, 3 }, + new int[] { 4, 5 }, + new int[] { 6 } }; + + var b = MessageBuilder.Create(); + var s = b.CreateObject>>(); + s.Init(expected.Length); + for (int i = 0; i < expected.Length; i++) + { + s[i].Init(expected[i], (l, j) => l.Init(j)); + } + DeserializerState d = s; + var voids = d.RequireList().CastVoid3D(); + Assert.AreEqual(expected.Length, voids.Count); + for (int i = 0; i < expected.Length; i++) + { + CollectionAssert.AreEqual(expected[i], voids[i].ToArray()); + } + } } } From e5902bf2424aa0019f156b960b37cd94a481c707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 3 Mar 2020 21:56:31 +0100 Subject: [PATCH 13/76] tuning coverage measurement --- CapnpC.CSharp.Generator/CodeGen/SkeletonWorder.cs | 4 +--- scripts/measure-coverage.ps1 | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/CapnpC.CSharp.Generator/CodeGen/SkeletonWorder.cs b/CapnpC.CSharp.Generator/CodeGen/SkeletonWorder.cs index 703ee3b..6887804 100644 --- a/CapnpC.CSharp.Generator/CodeGen/SkeletonWorder.cs +++ b/CapnpC.CSharp.Generator/CodeGen/SkeletonWorder.cs @@ -2,10 +2,8 @@ namespace CapnpC.CSharp.Generator.CodeGen { - class SkeletonWorder : Capnp.Rpc.Skeleton + abstract class SkeletonWorder : Capnp.Rpc.Skeleton { - public override ulong InterfaceId => throw new NotImplementedException(); - public const string SetMethodTableName = nameof(SkeletonWorder.SetMethodTable); public const string ImplName = nameof(SkeletonWorder.Impl); } diff --git a/scripts/measure-coverage.ps1 b/scripts/measure-coverage.ps1 index 8b9f809..0f3fa03 100644 --- a/scripts/measure-coverage.ps1 +++ b/scripts/measure-coverage.ps1 @@ -40,7 +40,7 @@ If(!(test-path $coverageReportDir)) & $openCover -target:"$vsTestConsole" ` -targetArgs:"/inIsolation $generatorTests" ` - -filter:"+[CapnpC.CSharp.Generator]*" ` + -filter:"+[CapnpC.CSharp.Generator]CapnpC.CSharp.Generator.* -[CapnpC.CSharp.Generator]CapnpC.CSharp.Generator.Schema.*" ` -excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" ` -output:"$coverageOutputGenerator" ` -mergebyhash -register:user -oldStyle From 04665f080a9b5af0b4d154b1b9154631e9d74fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 7 Mar 2020 19:37:30 +0100 Subject: [PATCH 14/76] error handling tests --- .../Capnp.Net.Runtime.Tests.Core21.csproj | 3 + .../Capnp.Net.Runtime.Tests.Std20.csproj | 1 + Capnp.Net.Runtime.Tests/LocalRpc.cs | 31 + .../TcpRpcErrorHandling.cs | 608 ++++++++++++++++++ .../TestCapImplementations.cs | 62 ++ Capnp.Net.Runtime/Rpc/RpcEngine.cs | 127 ++-- .../Rpc/RpcProtocolErrorException.cs | 9 + Capnp.Net.Runtime/Rpc/TcpRpcServer.cs | 2 +- 8 files changed, 788 insertions(+), 55 deletions(-) create mode 100644 Capnp.Net.Runtime.Tests/LocalRpc.cs create mode 100644 Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs create mode 100644 Capnp.Net.Runtime/Rpc/RpcProtocolErrorException.cs 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 b72dab4..42ee749 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 @@ -19,6 +19,7 @@ + @@ -28,6 +29,7 @@ + @@ -44,6 +46,7 @@ + diff --git a/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj b/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj index 1fdeec0..cb369cc 100644 --- a/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj +++ b/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj @@ -24,6 +24,7 @@ + diff --git a/Capnp.Net.Runtime.Tests/LocalRpc.cs b/Capnp.Net.Runtime.Tests/LocalRpc.cs new file mode 100644 index 0000000..232313b --- /dev/null +++ b/Capnp.Net.Runtime.Tests/LocalRpc.cs @@ -0,0 +1,31 @@ +using Capnp.Net.Runtime.Tests.GenImpls; +using Capnp.Rpc; +using Capnproto_test.Capnp.Test; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Capnp.Net.Runtime.Tests +{ + [TestClass] + public class LocalRpc + { + [TestMethod] + public void DeferredLocalAnswer() + { + var tcs = new TaskCompletionSource(); + var impl = new TestPipelineImpl2(tcs.Task); + var bproxy = BareProxy.FromImpl(impl); + var proxy = bproxy.Cast(true); + var cap = proxy.GetCap(0, null).OutBox_Cap(); + var foo = cap.Foo(123, true); + tcs.SetResult(0); + Assert.IsTrue(foo.Wait(TestBase.MediumNonDbgTimeout)); + Assert.AreEqual("bar", foo.Result); + } + } +} diff --git a/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs b/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs new file mode 100644 index 0000000..163d85e --- /dev/null +++ b/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs @@ -0,0 +1,608 @@ +using Capnp; +using Capnp.Net.Runtime.Tests.GenImpls; +using Capnp.Rpc; +using Capnproto_test.Capnp.Test; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Pipelines; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Capnp.Net.Runtime.Tests +{ + [TestClass] + public class TcpRpcErrorHandling: TestBase + { + class MemStreamEndpoint : IEndpoint + { + readonly FramePump _fromEnginePump; + readonly BinaryReader _reader; + + public bool Dismissed { get; private set; } + + public MemStreamEndpoint() + { + var pipe = new Pipe(); + _fromEnginePump = new FramePump(pipe.Writer.AsStream()); + _reader = new BinaryReader(pipe.Reader.AsStream()); + } + + public void Dismiss() + { + Dismissed = true; + } + + public void Forward(WireFrame frame) + { + _fromEnginePump.Send(frame); + } + + public WireFrame ReadNextFrame() + { + return _reader.ReadWireFrame(); + } + } + + class RpcEngineTester + { + readonly MemStreamEndpoint _fromEngine; + + public RpcEngineTester() + { + Engine = new RpcEngine(); + _fromEngine = new MemStreamEndpoint(); + RealEnd = Engine.AddEndpoint(_fromEngine); + } + + public RpcEngine Engine { get; } + public RpcEngine.RpcEndpoint RealEnd { get; } + public bool IsDismissed => _fromEngine.Dismissed; + + public void Send(Action build) + { + var mb = MessageBuilder.Create(); + mb.InitCapTable(); + build(mb.BuildRoot()); + RealEnd.Forward(mb.Frame); + } + + public void Recv(Action verify) + { + var task = Task.Run(() => DeserializerState.CreateRoot(_fromEngine.ReadNextFrame())); + Assert.IsTrue(task.Wait(MediumNonDbgTimeout), "reception timeout"); + verify(new Message.READER(task.Result)); + } + + public void ExpectAbort() + { + Recv(_ => { Assert.AreEqual(Message.WHICH.Abort, _.which); }); + Assert.IsTrue(IsDismissed); + Assert.ThrowsException( + () => Send(_ => { _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 33; })); + } + } + + [TestMethod] + public void DuplicateQuestion1() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + uint bootCapId = 0; + + tester.Send(_ => { _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 99; }); + tester.Send(_ => { _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 99; }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void DuplicateQuestion2() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + uint bootCapId = 0; + + tester.Send(_ => { _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 99; }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => { + _.which = Message.WHICH.Call; + _.Call.QuestionId = 99; + _.Call.Target.which = MessageTarget.WHICH.ImportedCap; + _.Call.Target.ImportedCap = bootCapId; + _.Call.InterfaceId = ((TypeIdAttribute)typeof(ITestInterface).GetCustomAttributes(typeof(TypeIdAttribute), false)[0]).Id; + _.Call.MethodId = 0; + _.Call.Params.Content.Rewrap(); + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void DuplicateQuestion3() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + uint bootCapId = 0; + + tester.Send(_ => { _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 99; }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => { + _.which = Message.WHICH.Call; + _.Call.QuestionId = 42; + _.Call.Target.which = MessageTarget.WHICH.ImportedCap; + _.Call.Target.ImportedCap = bootCapId; + _.Call.InterfaceId = ((TypeIdAttribute)typeof(ITestInterface).GetCustomAttributes(typeof(TypeIdAttribute), false)[0]).Id; + _.Call.MethodId = 0; + var wr = _.Call.Params.Content.Rewrap(); + wr.I = 123u; + wr.J = true; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + }); + tester.Send(_ => { + _.which = Message.WHICH.Call; + _.Call.QuestionId = 42; + _.Call.Target.which = MessageTarget.WHICH.ImportedCap; + _.Call.Target.ImportedCap = bootCapId; + _.Call.InterfaceId = ((TypeIdAttribute)typeof(ITestInterface).GetCustomAttributes(typeof(TypeIdAttribute), false)[0]).Id; + _.Call.MethodId = 0; + _.Call.Params.Content.Rewrap(); + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void NoBootstrap() + { + var tester = new RpcEngineTester(); + + tester.Send(_ => { _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 0; }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Exception, _.Return.which); + }); + Assert.IsFalse(tester.IsDismissed); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + tester.Send(_ => { _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 1; }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + }); + } + + [TestMethod] + public void DuplicateFinish() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + uint bootCapId = 0; + + tester.Send(_ => { + _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 99; }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => { + _.which = Message.WHICH.Finish; + _.Finish.QuestionId = 99; + }); + tester.Send(_ => { + _.which = Message.WHICH.Finish; + _.Finish.QuestionId = 99; + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void DuplicateAnswer() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.Results; + _.Return.Results.CapTable.Init(1); + _.Return.Results.CapTable[0].which = CapDescriptor.WHICH.SenderHosted; + _.Return.Results.CapTable[0].SenderHosted = 1; + }); + Assert.IsTrue(proxy.WhenResolved.IsCompleted); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Finish, _.which); + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.Results; + _.Return.Results.CapTable.Init(1); + _.Return.Results.CapTable[0].which = CapDescriptor.WHICH.SenderHosted; + _.Return.Results.CapTable[0].SenderHosted = 1; + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void InvalidReceiverHosted() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.Results; + _.Return.Results.CapTable.Init(1); + _.Return.Results.CapTable[0].which = CapDescriptor.WHICH.ReceiverHosted; + _.Return.Results.CapTable[0].ReceiverHosted = 0; + }); + Assert.IsTrue(proxy.WhenResolved.IsCompleted); + tester.ExpectAbort(); + } + + [TestMethod] + public void InvalidReceiverAnswer() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.Results; + _.Return.Results.CapTable.Init(1); + _.Return.Results.CapTable[0].which = CapDescriptor.WHICH.ReceiverAnswer; + _.Return.Results.CapTable[0].ReceiverAnswer.QuestionId = 0; + _.Return.Results.CapTable[0].ReceiverAnswer.Transform.Init(1); + _.Return.Results.CapTable[0].ReceiverAnswer.Transform[0].which = PromisedAnswer.Op.WHICH.GetPointerField; + _.Return.Results.CapTable[0].ReceiverAnswer.Transform[0].GetPointerField = 0; + }); + Assert.IsTrue(proxy.WhenResolved.IsCompleted); + tester.ExpectAbort(); + } + + [TestMethod] + public void DuplicateResolve() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.Results; + _.Return.Results.CapTable.Init(1); + _.Return.Results.CapTable[0].which = CapDescriptor.WHICH.SenderPromise; + _.Return.Results.CapTable[0].SenderPromise = 0; + }); + tester.Send(_ => { + _.which = Message.WHICH.Resolve; + _.Resolve.which = Resolve.WHICH.Cap; + _.Resolve.Cap.which = CapDescriptor.WHICH.SenderHosted; + _.Resolve.Cap.SenderHosted = 1; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Finish, _.which); + }); + tester.Send(_ => { + _.which = Message.WHICH.Resolve; + _.Resolve.which = Resolve.WHICH.Exception; + _.Resolve.Exception.Reason = "problem"; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Release, _.which); + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void DuplicateRelease1() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + uint bootCapId = 0; + + tester.Send(_ => { + _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 99; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => { + _.which = Message.WHICH.Release; + _.Release.Id = bootCapId; + _.Release.ReferenceCount = 1; + }); + tester.Send(_ => { + _.which = Message.WHICH.Release; + _.Release.Id = bootCapId; + _.Release.ReferenceCount = 1; + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void DuplicateRelease2() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + uint bootCapId = 0; + + tester.Send(_ => { + _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 99; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => { + _.which = Message.WHICH.Release; + _.Release.Id = bootCapId; + _.Release.ReferenceCount = 2; + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void UnimplementedAccept() + { + var tester = new RpcEngineTester(); + + tester.Send(_ => { + _.which = Message.WHICH.Accept; + _.Accept.Embargo = true; + _.Accept.QuestionId = 47; + _.Accept.Provision.SetStruct(1, 0); + _.Accept.Provision.Allocate(); + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + Assert.AreEqual(Message.WHICH.Accept, _.Unimplemented.which); + Assert.IsTrue(_.Unimplemented.Accept.Embargo); + Assert.AreEqual(47u, _.Unimplemented.Accept.QuestionId); + Assert.AreEqual(1, _.Unimplemented.Accept.Provision.StructDataCount); + Assert.AreEqual(0, _.Unimplemented.Accept.Provision.StructPtrCount); + }); + Assert.IsFalse(tester.IsDismissed); + } + + [TestMethod] + public void UnimplementedJoin() + { + var tester = new RpcEngineTester(); + + tester.Send(_ => { + _.which = Message.WHICH.Join; + _.Join.QuestionId = 74; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + Assert.AreEqual(Message.WHICH.Join, _.Unimplemented.which); + Assert.AreEqual(74u, _.Unimplemented.Join.QuestionId); + }); + Assert.IsFalse(tester.IsDismissed); + } + + [TestMethod] + public void UnimplementedProvide() + { + var tester = new RpcEngineTester(); + + tester.Send(_ => { + _.which = Message.WHICH.Provide; + _.Provide.QuestionId = 666; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + Assert.AreEqual(Message.WHICH.Provide, _.Unimplemented.which); + Assert.AreEqual(666u, _.Unimplemented.Provide.QuestionId); + }); + Assert.IsFalse(tester.IsDismissed); + } + + [TestMethod] + public void UnimplementedObsoleteDelete() + { + var tester = new RpcEngineTester(); + + tester.Send(_ => { + _.which = Message.WHICH.ObsoleteDelete; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + Assert.AreEqual(Message.WHICH.ObsoleteDelete, _.Unimplemented.which); + }); + Assert.IsFalse(tester.IsDismissed); + } + + [TestMethod] + public void UnimplementedObsoleteSave() + { + var tester = new RpcEngineTester(); + + tester.Send(_ => { + _.which = Message.WHICH.ObsoleteSave; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + Assert.AreEqual(Message.WHICH.ObsoleteSave, _.Unimplemented.which); + }); + Assert.IsFalse(tester.IsDismissed); + } + + [TestMethod] + public void UnimplementedUnknown() + { + var tester = new RpcEngineTester(); + + tester.Send(_ => { + _.which = (Message.WHICH)123; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + Assert.AreEqual((Message.WHICH)123, _.Unimplemented.which); + }); + Assert.IsFalse(tester.IsDismissed); + } + + class TestPipelineImpl3 : ITestPipeline + { + readonly TestPipelineImpl2 _impl; + readonly ITestPipeline _proxy; + + public TestPipelineImpl3(Task complete) + { + _impl = new TestPipelineImpl2(complete); + var bproxy = BareProxy.FromImpl(_impl); + _proxy = bproxy.Cast(true); + } + + public void Dispose() + { + } + + public bool IsGrandsonCapDisposed => _impl.IsChildCapDisposed; + + public Task<(string, TestPipeline.AnyBox)> GetAnyCap(uint n, BareProxy inCap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task<(string, TestPipeline.Box)> GetCap(uint n, ITestInterface inCap, CancellationToken cancellationToken_ = default) + { + return Task.FromResult(("foo", new TestPipeline.Box() { Cap = _proxy.GetCap(0, null).OutBox_Cap() })); + } + + public Task TestPointers(ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + } + + [TestMethod] + public void UnimplementedResolve() + { + var tcs = new TaskCompletionSource(); + var tester = new RpcEngineTester(); + var impl = new TestPipelineImpl3(tcs.Task); + tester.Engine.Main = impl; + + uint bootCapId = 0; + + tester.Send(_ => { + _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 99; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => { + _.which = Message.WHICH.Call; + _.Call.QuestionId = 42; + _.Call.Target.which = MessageTarget.WHICH.ImportedCap; + _.Call.Target.ImportedCap = bootCapId; + _.Call.InterfaceId = ((TypeIdAttribute)typeof(ITestPipeline).GetCustomAttributes(typeof(TypeIdAttribute), false)[0]).Id; + _.Call.MethodId = 0; + var wr = _.Call.Params.Content.Rewrap(); + wr.InCap = null; + _.Call.Params.CapTable.Init(1); + _.Call.Params.CapTable[0].which = CapDescriptor.WHICH.ReceiverHosted; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + Assert.AreEqual(CapDescriptor.WHICH.SenderPromise, _.Return.Results.CapTable[0].which); + }); + tcs.SetResult(0); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Resolve, _.which); + Assert.AreEqual(Resolve.WHICH.Cap, _.Resolve.which); + Assert.AreEqual(CapDescriptor.WHICH.SenderHosted, _.Resolve.Cap.which); + + Assert.IsFalse(impl.IsGrandsonCapDisposed); + + tester.Send(_1 => + { + _1.which = Message.WHICH.Unimplemented; + _1.Unimplemented.which = Message.WHICH.Resolve; + Reserializing.DeepCopy(_, _1.Unimplemented.Resolve); + }); + + Assert.IsFalse(impl.IsGrandsonCapDisposed); + + tester.Send(_1 => + { + _1.which = Message.WHICH.Finish; + _1.Finish.QuestionId = 42; + _1.Finish.ReleaseResultCaps = true; + }); + + Assert.IsTrue(impl.IsGrandsonCapDisposed); + }); + Assert.IsFalse(tester.IsDismissed); + } + } +} diff --git a/Capnp.Net.Runtime.Tests/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/TestCapImplementations.cs index 029ac0f..44cfde2 100644 --- a/Capnp.Net.Runtime.Tests/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/TestCapImplementations.cs @@ -432,6 +432,33 @@ namespace Capnp.Net.Runtime.Tests.GenImpls } } + class TestInterfaceImpl2 : ITestInterface + { + public Task Bar(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task Baz(TestAllTypes s, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + IsDisposed = true; + } + + public bool IsDisposed { get; private set; } + + public Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default) + { + Assert.AreEqual(123u, i); + Assert.IsTrue(j); + return Task.FromResult("bar"); + } + } + #endregion TestInterface #region TestExtends @@ -506,6 +533,41 @@ namespace Capnp.Net.Runtime.Tests.GenImpls throw new NotImplementedException(); } } + + class TestPipelineImpl2 : ITestPipeline + { + readonly Task _deblock; + readonly TestInterfaceImpl2 _timpl2; + + public TestPipelineImpl2(Task deblock) + { + _deblock = deblock; + _timpl2 = new TestInterfaceImpl2(); + } + + public void Dispose() + { + } + + public bool IsChildCapDisposed => _timpl2.IsDisposed; + + public Task<(string, TestPipeline.AnyBox)> GetAnyCap(uint n, BareProxy inCap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public async Task<(string, TestPipeline.Box)> GetCap(uint n, ITestInterface inCap, CancellationToken cancellationToken_ = default) + { + await _deblock; + return ("hello", new TestPipeline.Box() { Cap = _timpl2 }); + } + + public Task TestPointers(ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + } + #endregion TestPipeline #region TestCallOrder diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 2378959..a11677d 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -60,8 +60,14 @@ namespace Capnp.Rpc } } - internal class RpcEndpoint : IEndpoint, IRpcEndpoint + public class RpcEndpoint : IEndpoint, IRpcEndpoint { + public enum EndpointState + { + Active, + Dismissed + } + static readonly ThreadLocal _exportCapTablePostActions = new ThreadLocal(); static readonly ThreadLocal _tailCall = new ThreadLocal(); static readonly ThreadLocal _canDeferCalls = new ThreadLocal(); @@ -87,8 +93,11 @@ namespace Capnp.Rpc { _host = host; _tx = tx; + State = EndpointState.Active; } + public EndpointState State { get; private set; } + public void Dismiss() { lock (_reentrancyBlocker) @@ -105,6 +114,8 @@ namespace Capnp.Rpc _answerTable.Clear(); _pendingDisembargos.Clear(); + + State = EndpointState.Dismissed; } _tx.Dismiss(); @@ -112,6 +123,9 @@ namespace Capnp.Rpc public void Forward(WireFrame frame) { + if (State == EndpointState.Dismissed) + throw new InvalidOperationException("Endpoint is in dismissed state and doesn't accept frames anymore"); + Interlocked.Increment(ref _recvCount); ProcessFrame(frame); } @@ -327,6 +341,7 @@ namespace Capnp.Rpc if (!added) { Logger.LogWarning("Incoming bootstrap request: Peer specified duplicate (not yet released?) answer ID."); + throw new RpcProtocolErrorException("Duplicate question ID"); } @@ -390,9 +405,7 @@ namespace Capnp.Rpc pendingAnswer.Cancel(); pendingAnswer.Dispose(); - SendAbort($"There is another pending answer for the same question ID {req.QuestionId}."); - - return; + throw new RpcProtocolErrorException($"There is another pending answer for the same question ID {req.QuestionId}."); } switch (req.SendResultsTo.which) @@ -553,8 +566,7 @@ namespace Capnp.Rpc { Logger.LogWarning("Incoming RPC call: Peer asked for invalid (already released?) capability ID."); - SendAbort($"Requested capability with ID {req.Target.ImportedCap} does not exist."); - return; + throw new RpcProtocolErrorException($"Requested capability with ID {req.Target.ImportedCap} does not exist."); } } @@ -606,8 +618,7 @@ namespace Capnp.Rpc else { Logger.LogWarning("Incoming RPC call: Peer asked for non-existing answer ID."); - SendAbort($"Did not find a promised answer for given ID {req.Target.PromisedAnswer.QuestionId}"); - return; + throw new RpcProtocolErrorException($"Did not find a promised answer for given ID {req.Target.PromisedAnswer.QuestionId}"); } } break; @@ -637,7 +648,7 @@ namespace Capnp.Rpc { Logger.LogWarning("Incoming RPC return: Unknown answer ID."); - return; + throw new RpcProtocolErrorException("Unknown answer ID"); } } @@ -722,7 +733,7 @@ namespace Capnp.Rpc if (!_importTable.TryGetValue(resolve.PromiseId, out var rcw)) { Logger.LogWarning("Received a resolve message with invalid ID"); - return; + throw new RpcProtocolErrorException($"Invalid ID {resolve.PromiseId}"); } if (!rcw.Cap.TryGetTarget(out var cap)) @@ -734,28 +745,33 @@ namespace Capnp.Rpc if (!(cap is PromisedCapability resolvableCap)) { Logger.LogWarning("Received a resolve message for a capability which is not a promise"); - return; + throw new RpcProtocolErrorException($"Not a promise {resolve.PromiseId}"); } - switch (resolve.which) + try { - case Resolve.WHICH.Cap: - lock (_reentrancyBlocker) - { - var resolvedCap = ImportCap(resolve.Cap); - if (resolvedCap == null) - resolvedCap = LazyCapability.CreateBrokenCap("Failed to resolve this capability"); - resolvableCap.ResolveTo(resolvedCap); - } - break; + switch (resolve.which) + { + case Resolve.WHICH.Cap: + lock (_reentrancyBlocker) + { + var resolvedCap = ImportCap(resolve.Cap); + resolvableCap.ResolveTo(resolvedCap); + } + break; - case Resolve.WHICH.Exception: - resolvableCap.Break(resolve.Exception.Reason); - break; + case Resolve.WHICH.Exception: + resolvableCap.Break(resolve.Exception.Reason); + break; - default: - Logger.LogWarning("Received a resolve message with unknown category."); - throw new RpcUnimplementedException(); + default: + Logger.LogWarning("Received a resolve message with unknown category."); + throw new RpcUnimplementedException(); + } + } + catch (InvalidOperationException) + { + throw new RpcProtocolErrorException($"Capability {resolve.PromiseId} was already resolved"); } } @@ -777,10 +793,7 @@ namespace Capnp.Rpc { Logger.LogWarning("Sender loopback request: Peer asked for invalid (already released?) capability ID."); - SendAbort("'Disembargo': Invalid capability ID"); - Dismiss(); - - return; + throw new RpcProtocolErrorException("'Disembargo': Invalid capability ID"); } reply.Target.which = MessageTarget.WHICH.ImportedCap; @@ -830,8 +843,7 @@ namespace Capnp.Rpc { Logger.LogWarning("Sender loopback request: Peer asked for disembargoing an answer which does not resolve back to the sender."); - SendAbort("'Disembargo': Answer does not resolve back to me"); - Dismiss(); + throw new RpcProtocolErrorException("'Disembargo': Answer does not resolve back to me"); } } finally @@ -844,9 +856,7 @@ namespace Capnp.Rpc { Logger.LogWarning($"Sender loopback request: Peer asked for disembargoing an answer which either has not yet returned, was canceled, or faulted: {exception.Message}"); - SendAbort($"'Disembargo' failure: {exception}"); - Dismiss(); - + throw new RpcProtocolErrorException($"'Disembargo' failure: {exception}"); } }); } @@ -854,10 +864,7 @@ namespace Capnp.Rpc { Logger.LogWarning("Sender loopback request: Peer asked for non-existing answer ID."); - SendAbort("'Disembargo': Invalid answer ID"); - Dismiss(); - - return; + throw new RpcProtocolErrorException("'Disembargo': Invalid answer ID"); } break; @@ -966,6 +973,8 @@ namespace Capnp.Rpc else { Logger.LogWarning("Peer sent 'finish' message with unknown question ID"); + + throw new RpcProtocolErrorException("unknown question ID"); } } @@ -994,6 +1003,8 @@ namespace Capnp.Rpc catch (System.Exception exception) { Logger.LogWarning($"Attempting to release capability with invalid reference count: {exception.Message}"); + + throw new RpcProtocolErrorException("Invalid reference count"); } } } @@ -1001,6 +1012,8 @@ namespace Capnp.Rpc if (!exists) { Logger.LogWarning("Attempting to release unknown capability ID"); + + throw new RpcProtocolErrorException("Invalid export ID"); } } @@ -1056,9 +1069,7 @@ namespace Capnp.Rpc //# In cases where there is no sensible way to react to an `unimplemented` message (without //# resource leaks or other serious problems), the connection may need to be aborted. This is //# a gray area; different implementations may take different approaches. - SendAbort("It's hopeless if you don't implement the bootstrap message"); - Dismiss(); - break; + throw new RpcProtocolErrorException("It's hopeless if you don't implement the bootstrap message"); default: // Looking at the various message types it feels OK to just not care about other 'unimplemented' @@ -1156,6 +1167,11 @@ namespace Capnp.Rpc Tx(mb.Frame); } + catch (RpcProtocolErrorException error) + { + SendAbort(error.Message); + Dismiss(); + } catch (System.Exception exception) { Logger.LogError(exception, "Uncaught exception during message processing."); @@ -1164,12 +1180,11 @@ namespace Capnp.Rpc // First, we send implementation specific details of a - maybe internal - error, not very valuable for the // receiver. But worse: From a security point of view, we might even reveil a secret here. SendAbort("Uncaught exception during RPC processing. This may also happen due to invalid input."); - Dismiss(); } } - ConsumedCapability? ImportCap(CapDescriptor.READER capDesc) + ConsumedCapability ImportCap(CapDescriptor.READER capDesc) { lock (_reentrancyBlocker) { @@ -1198,7 +1213,6 @@ namespace Capnp.Rpc rcw = new RefCounted>( new WeakReference(newCap)); _importTable.Add(capDesc.SenderHosted, rcw); - Debug.Assert(newCap != null); return newCap; } @@ -1217,7 +1231,6 @@ namespace Capnp.Rpc rcwp.Cap.SetTarget(impCap); } - Debug.Assert(impCap != null); return impCap; } else @@ -1226,7 +1239,6 @@ namespace Capnp.Rpc rcw = new RefCounted>( new WeakReference(newCap)); _importTable.Add(capDesc.SenderPromise, rcw); - Debug.Assert(newCap != null); return newCap; } @@ -1238,7 +1250,7 @@ namespace Capnp.Rpc else { Logger.LogWarning("Peer refers to receiver-hosted capability which does not exist."); - return null; + throw new RpcProtocolErrorException($"Receiver-hosted capability {capDesc.ReceiverHosted} does not exist."); } case CapDescriptor.WHICH.ReceiverAnswer: @@ -1270,7 +1282,7 @@ namespace Capnp.Rpc else { Logger.LogWarning("Peer refers to pending answer which does not exist."); - return null; + throw new RpcProtocolErrorException($"Invalid question ID {capDesc.ReceiverAnswer.QuestionId}"); } case CapDescriptor.WHICH.ThirdPartyHosted: @@ -1288,7 +1300,6 @@ namespace Capnp.Rpc rcv.Cap.SetTarget(impCap); } - Debug.Assert(impCap != null); return impCap; } else @@ -1296,7 +1307,6 @@ namespace Capnp.Rpc var newCap = new ImportedCapability(this, capDesc.ThirdPartyHosted.VineId); rcv = new RefCounted>( new WeakReference(newCap)); - Debug.Assert(newCap != null); return newCap; } @@ -1307,7 +1317,7 @@ namespace Capnp.Rpc } } - public IList ImportCapTable(Payload.READER payload) + internal IList ImportCapTable(Payload.READER payload) { var list = new List(); @@ -1481,7 +1491,7 @@ namespace Capnp.Rpc readonly ConcurrentBag _inboundEndpoints = new ConcurrentBag(); - internal RpcEndpoint AddEndpoint(IEndpoint outboundEndpoint) + public RpcEndpoint AddEndpoint(IEndpoint outboundEndpoint) { var inboundEndpoint = new RpcEndpoint(this, outboundEndpoint); _inboundEndpoints.Add(inboundEndpoint); @@ -1503,5 +1513,14 @@ namespace Capnp.Rpc _bootstrapCap = value; } } + + /// + /// Sets the bootstrap capability. It must be an object which implements a valid capability interface + /// (). + /// + public object Main + { + set { BootstrapCap = Skeleton.GetOrCreateSkeleton(value, false); } + } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/RpcProtocolErrorException.cs b/Capnp.Net.Runtime/Rpc/RpcProtocolErrorException.cs new file mode 100644 index 0000000..6b4885d --- /dev/null +++ b/Capnp.Net.Runtime/Rpc/RpcProtocolErrorException.cs @@ -0,0 +1,9 @@ +namespace Capnp.Rpc +{ + class RpcProtocolErrorException : System.Exception + { + public RpcProtocolErrorException(string reason): base(reason) + { + } + } +} \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs b/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs index dcdb9fb..75ad222 100644 --- a/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs +++ b/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs @@ -325,7 +325,7 @@ namespace Capnp.Rpc /// public object Main { - set { _rpcEngine.BootstrapCap = Skeleton.GetOrCreateSkeleton(value, false); } + set { _rpcEngine.Main = value; } } /// From f58464293bc5356f961110234cbe85652ff4218d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 10 Mar 2020 21:55:34 +0100 Subject: [PATCH 15/76] WIP --- .../TcpRpcErrorHandling.cs | 4 +- Capnp.Net.Runtime.Tests/test.cs | 6 +- Capnp.Net.Runtime/DeserializerState.cs | 5 + Capnp.Net.Runtime/DynamicSerializerState.cs | 4 + .../ListOfPrimitivesSerializer.cs | 16 +- Capnp.Net.Runtime/Rpc/ConsumedCapability.cs | 1 + Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs | 2 + Capnp.Net.Runtime/Rpc/IResolvingCapability.cs | 2 +- .../Rpc/Interception/CallContext.cs | 25 +- .../Rpc/Interception/CensorCapability.cs | 2 +- Capnp.Net.Runtime/Rpc/LazyCapability.cs | 52 ++-- Capnp.Net.Runtime/Rpc/LocalAnswer.cs | 30 +- .../Rpc/LocalAnswerCapability.cs | 48 ++-- .../Rpc/LocalAnswerCapabilityDeprecated.cs | 83 ++++++ Capnp.Net.Runtime/Rpc/LocalCapability.cs | 15 +- Capnp.Net.Runtime/Rpc/PendingAnswer.cs | 5 +- Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 40 ++- Capnp.Net.Runtime/Rpc/PromisedCapability.cs | 28 +- Capnp.Net.Runtime/Rpc/Proxy.cs | 32 +-- .../Rpc/RefCountingCapability.cs | 29 +- .../Rpc/RemoteAnswerCapability.cs | 58 ++-- .../Rpc/RemoteAnswerCapabilityDeprecated.cs | 265 ++++++++++++++++++ .../Rpc/RemoteResolvingCapability.cs | 12 +- .../Rpc/ResolvingCapabilityExtensions.cs | 19 +- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 68 +++-- Capnp.Net.Runtime/Rpc/Vine.cs | 12 +- Capnp.Net.Runtime/SerializerState.cs | 26 +- 27 files changed, 661 insertions(+), 228 deletions(-) create mode 100644 Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs create mode 100644 Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs diff --git a/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs b/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs index 163d85e..300320d 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs @@ -563,7 +563,7 @@ namespace Capnp.Net.Runtime.Tests _.Call.QuestionId = 42; _.Call.Target.which = MessageTarget.WHICH.ImportedCap; _.Call.Target.ImportedCap = bootCapId; - _.Call.InterfaceId = ((TypeIdAttribute)typeof(ITestPipeline).GetCustomAttributes(typeof(TypeIdAttribute), false)[0]).Id; + _.Call.InterfaceId = new TestPipeline_Skeleton().InterfaceId; _.Call.MethodId = 0; var wr = _.Call.Params.Content.Rewrap(); wr.InCap = null; @@ -588,7 +588,7 @@ namespace Capnp.Net.Runtime.Tests { _1.which = Message.WHICH.Unimplemented; _1.Unimplemented.which = Message.WHICH.Resolve; - Reserializing.DeepCopy(_, _1.Unimplemented.Resolve); + Reserializing.DeepCopy(_.Resolve, _1.Unimplemented.Resolve); }); Assert.IsFalse(impl.IsGrandsonCapDisposed); diff --git a/Capnp.Net.Runtime.Tests/test.cs b/Capnp.Net.Runtime.Tests/test.cs index e56b8ff..db23211 100644 --- a/Capnp.Net.Runtime.Tests/test.cs +++ b/Capnp.Net.Runtime.Tests/test.cs @@ -17255,7 +17255,11 @@ namespace Capnproto_test.Capnp.Test static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap = new MemberAccessPath(1U, 0U); public static Capnproto_test.Capnp.Test.ITestInterface OutBox_Cap(this Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> task) { - return (Capnproto_test.Capnp.Test.ITestInterface)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap)); + async Task AwaitProxy() => (await task).Item2.Cap; + + return (Capnproto_test.Capnp.Test.ITestInterface)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access( + Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap, + AwaitProxy())); } static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap = new MemberAccessPath(1U, 0U); diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs index 440df25..b420725 100644 --- a/Capnp.Net.Runtime/DeserializerState.cs +++ b/Capnp.Net.Runtime/DeserializerState.cs @@ -106,6 +106,11 @@ namespace Capnp case ObjectKind.ListOfStructs: case ObjectKind.Nil: case ObjectKind.Struct: + if (state.Caps != null) + { + foreach (var cap in state.Caps) + cap?.Release(true); + } return new DeserializerState(state.Allocator!.Segments) { CurrentSegmentIndex = state.SegmentIndex, diff --git a/Capnp.Net.Runtime/DynamicSerializerState.cs b/Capnp.Net.Runtime/DynamicSerializerState.cs index a58c688..edf3d15 100644 --- a/Capnp.Net.Runtime/DynamicSerializerState.cs +++ b/Capnp.Net.Runtime/DynamicSerializerState.cs @@ -42,7 +42,11 @@ namespace Capnp { var mb = MessageBuilder.Create(); if (state.Caps != null) + { mb.InitCapTable(); + foreach (var cap in state.Caps) + cap?.AddRef(); + } var sstate = mb.CreateObject(); Reserializing.DeepCopy(state, sstate); diff --git a/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs b/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs index cd86024..18477f4 100644 --- a/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs +++ b/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs @@ -92,19 +92,19 @@ namespace Capnp switch (items) { case T[] array: - array.CopyTo(Span); + array.CopyTo(Data); break; case ArraySegment segment: - segment.AsSpan().CopyTo(Span); + segment.AsSpan().CopyTo(Data); break; case ListOfPrimitivesDeserializer deser: - deser.Span.CopyTo(Span); + deser.Span.CopyTo(Data); break; case ListOfPrimitivesSerializer ser: - ser.Span.CopyTo(Span); + ser.Data.CopyTo(Data); break; default: @@ -116,12 +116,18 @@ namespace Capnp } } + IEnumerable Enumerate() + { + for (int i = 0; i < Data.Length; i++) + yield return Data[i]; + } + /// /// Implements . /// /// public IEnumerator GetEnumerator() => Enumerate().GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => Span.ToArray().GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs index 1035f0b..1204fa0 100644 --- a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs @@ -19,6 +19,7 @@ internal abstract void AddRef(); internal abstract void Release( + bool keepAlive, [System.Runtime.CompilerServices.CallerMemberName] string methodName = "", [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0); diff --git a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs index 250aa18..7b774f8 100644 --- a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs @@ -23,5 +23,7 @@ namespace Capnp.Rpc /// Path to the desired capability inside the result struct. /// Pipelined low-level capability ConsumedCapability? Access(MemberAccessPath access); + + ConsumedCapability? Access(MemberAccessPath access, Task proxyTask); } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs b/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs index 36f8bf0..cc26602 100644 --- a/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs @@ -10,6 +10,6 @@ namespace Capnp.Rpc /// /// Will eventually give the resolved capability. /// - Task WhenResolved { get; } + Task WhenResolved { get; } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs index c8ea190..36b95d6 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs @@ -25,10 +25,10 @@ namespace Capnp.Rpc.Interception public Task WhenReturned => _futureResult.Task; public CancellationToken CancelFromAlice => _cancelFromAlice.Token; - async Task AccessWhenReturned(MemberAccessPath access) + async Task AccessWhenReturned(MemberAccessPath access) { await WhenReturned; - return new Proxy(Access(access)); + return Access(access); } public ConsumedCapability? Access(MemberAccessPath access) @@ -50,6 +50,27 @@ namespace Capnp.Rpc.Interception } } + public ConsumedCapability? Access(MemberAccessPath _, Task task) + { + var proxyTask = task.AsProxyTask(); + + if (proxyTask.IsCompleted) + { + try + { + return proxyTask.Result?.ConsumedCap; + } + catch (AggregateException exception) + { + throw exception.InnerException!; + } + } + else + { + return new LazyCapability(proxyTask); + } + } + public void Dispose() { try diff --git a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs index 89573ba..bd66f9b 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs @@ -16,7 +16,7 @@ protected override void ReleaseRemotely() { - InterceptedCapability.Release(); + InterceptedCapability.Release(false); } internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index 965d054..d56297c 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -8,32 +8,45 @@ namespace Capnp.Rpc { public static LazyCapability CreateBrokenCap(string message) { - var cap = new LazyCapability(Task.FromException(new RpcException(message))); + var cap = new LazyCapability(Task.FromException(new RpcException(message))); cap.AddRef(); // Instance shall be persistent return cap; } public static LazyCapability CreateCanceledCap(CancellationToken token) { - var cap = new LazyCapability(Task.FromCanceled(token)); + var cap = new LazyCapability(Task.FromCanceled(token)); cap.AddRef(); // Instance shall be persistent return cap; } public static LazyCapability Null { get; } = CreateBrokenCap("Null capability"); - public LazyCapability(Task capabilityTask) + readonly Task? _proxyTask; + + public LazyCapability(Task capabilityTask) { WhenResolved = capabilityTask; } + public LazyCapability(Task proxyTask) + { + _proxyTask = proxyTask; + + async Task AwaitCap() => (await _proxyTask!).ConsumedCap; + + WhenResolved = AwaitCap(); + } + internal override void Freeze(out IRpcEndpoint? boundEndpoint) { if (WhenResolved.IsCompleted) { + boundEndpoint = null; + try { - WhenResolved.Result.Freeze(out boundEndpoint); + WhenResolved.Result?.Freeze(out boundEndpoint); } catch (AggregateException exception) { @@ -54,7 +67,8 @@ namespace Capnp.Rpc { if (WhenResolved.ReplacementTaskIsCompletedSuccessfully()) { - WhenResolved.Result.Export(endpoint, writer); + using var proxy = new Proxy(WhenResolved.Result); + proxy.Export(endpoint, writer); } else { @@ -62,24 +76,21 @@ namespace Capnp.Rpc } } - async void DisposeProxyWhenResolved() - { - try - { - var cap = await WhenResolved; - if (cap != null) cap.Dispose(); - } - catch - { - } - } - protected override void ReleaseRemotely() { - DisposeProxyWhenResolved(); + if (_proxyTask != null) + { + async void DisposeProxyWhenResolved() + { + try { using var _ = await _proxyTask!; } + catch { } + } + + DisposeProxyWhenResolved(); + } } - public Task WhenResolved { get; } + public Task WhenResolved { get; } async Task CallImpl(ulong interfaceId, ushort methodId, DynamicSerializerState args, CancellationToken cancellationToken) { @@ -90,7 +101,8 @@ namespace Capnp.Rpc if (cap == null) throw new RpcException("Broken capability"); - var call = cap.Call(interfaceId, methodId, args, default); + using var proxy = new Proxy(cap); + var call = proxy.Call(interfaceId, methodId, args, default); var whenReturned = call.WhenReturned; using (var registration = cancellationToken.Register(call.Dispose)) diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswer.cs b/Capnp.Net.Runtime/Rpc/LocalAnswer.cs index 8744cb6..a90166f 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswer.cs @@ -18,35 +18,27 @@ namespace Capnp.Rpc async void CleanupAfterReturn() { - try - { - await WhenReturned; - } - catch - { - } - finally - { - _cts.Dispose(); - } + try { await WhenReturned; } + catch { } + finally { _cts.Dispose(); } } public Task WhenReturned { get; } public ConsumedCapability Access(MemberAccessPath access) { - return new LocalAnswerCapability(WhenReturned, access); + return new LocalAnswerCapabilityDeprecated(WhenReturned, access); + } + + public ConsumedCapability Access(MemberAccessPath _, Task task) + { + return new LocalAnswerCapability(task.AsProxyTask()); } public void Dispose() { - try - { - _cts.Cancel(); - } - catch (ObjectDisposedException) - { - } + try { _cts.Cancel(); } + catch (ObjectDisposedException) { } } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs index 195d139..fdd8ad4 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs @@ -4,15 +4,17 @@ using System.Threading.Tasks; namespace Capnp.Rpc { + class LocalAnswerCapability : RefCountingCapability, IResolvingCapability { - readonly Task _answer; - readonly MemberAccessPath _access; + readonly Task _whenResolvedProxy; - public LocalAnswerCapability(Task answer, MemberAccessPath access) + public LocalAnswerCapability(Task proxyTask) { - _answer = answer; - _access = access; + _whenResolvedProxy = proxyTask; + + async Task AwaitResolved() => (await _whenResolvedProxy).ConsumedCap; + WhenResolved = AwaitResolved(); } internal override void Freeze(out IRpcEndpoint? boundEndpoint) @@ -24,31 +26,20 @@ namespace Capnp.Rpc { } - async Task AwaitResolved() - { - var state = await _answer; - return new Proxy(_access.Eval(state)); - } - public Task WhenResolved => AwaitResolved(); + public Task WhenResolved { get; private set; } internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { - if (_answer.IsCompleted) + if (_whenResolvedProxy.IsCompleted) { - DeserializerState result; try { - result = _answer.Result; + _whenResolvedProxy.Result.Export(endpoint, writer); } catch (AggregateException exception) { - throw exception.InnerException!; - } - - using (var proxy = new Proxy(_access.Eval(result))) - { - proxy.Export(endpoint, writer); + throw exception.InnerException; } } else @@ -59,20 +50,18 @@ namespace Capnp.Rpc async Task CallImpl(ulong interfaceId, ushort methodId, DynamicSerializerState args, CancellationToken cancellationToken) { - var cap = await AwaitResolved(); + var proxy = await _whenResolvedProxy; cancellationToken.ThrowIfCancellationRequested(); - if (cap == null) + if (proxy.IsNull) throw new RpcException("Broken capability"); - var call = cap.Call(interfaceId, methodId, args, default); + var call = proxy.Call(interfaceId, methodId, args, default); var whenReturned = call.WhenReturned; - using (var registration = cancellationToken.Register(() => call.Dispose())) - { - return await whenReturned; - } + using var registration = cancellationToken.Register(() => call.Dispose()); + return await whenReturned; } internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) @@ -81,9 +70,10 @@ namespace Capnp.Rpc return new LocalAnswer(cts, CallImpl(interfaceId, methodId, args, cts.Token)); } - protected override void ReleaseRemotely() + protected async override void ReleaseRemotely() { - this.DisposeWhenResolved(); + try { using var _ = await _whenResolvedProxy; } + catch { } } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs new file mode 100644 index 0000000..f78788d --- /dev/null +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs @@ -0,0 +1,83 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Capnp.Rpc +{ + class LocalAnswerCapabilityDeprecated : RefCountingCapability, IResolvingCapability + { + readonly Task _answer; + readonly MemberAccessPath _access; + + public LocalAnswerCapabilityDeprecated(Task answer, MemberAccessPath access) + { + _answer = answer; + _access = access; + + async Task AwaitResolved() => access.Eval(await _answer); + WhenResolved = AwaitResolved(); + } + + internal override void Freeze(out IRpcEndpoint? boundEndpoint) + { + boundEndpoint = null; + } + + internal override void Unfreeze() + { + } + + + public Task WhenResolved { get; private set; } + + internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) + { + if (_answer.IsCompleted) + { + DeserializerState result; + try + { + result = _answer.Result; + } + catch (AggregateException exception) + { + throw exception.InnerException!; + } + + using var proxy = new Proxy(_access.Eval(result)); + proxy.Export(endpoint, writer); + } + else + { + this.ExportAsSenderPromise(endpoint, writer); + } + } + + async Task CallImpl(ulong interfaceId, ushort methodId, DynamicSerializerState args, CancellationToken cancellationToken) + { + var cap = await WhenResolved; + + cancellationToken.ThrowIfCancellationRequested(); + + if (cap == null) + throw new RpcException("Broken capability"); + + using var proxy = new Proxy(cap); + var call = proxy.Call(interfaceId, methodId, args, default); + var whenReturned = call.WhenReturned; + + using var registration = cancellationToken.Register(() => call.Dispose()); + return await whenReturned; + } + + internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) + { + var cts = new CancellationTokenSource(); + return new LocalAnswer(cts, CallImpl(interfaceId, methodId, args, cts.Token)); + } + + protected override void ReleaseRemotely() + { + } + } +} \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/LocalCapability.cs b/Capnp.Net.Runtime/Rpc/LocalCapability.cs index 23b0ced..d0dc90f 100644 --- a/Capnp.Net.Runtime/Rpc/LocalCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalCapability.cs @@ -7,15 +7,12 @@ namespace Capnp.Rpc { class LocalCapability : ConsumedCapability { - static readonly ConditionalWeakTable _localCaps = - new ConditionalWeakTable(); - public static ConsumedCapability Create(Skeleton skeleton) { if (skeleton is Vine vine) return vine.Proxy.ConsumedCap!; else - return _localCaps.GetValue(skeleton, _ => new LocalCapability(_)); + return new LocalCapability(skeleton); } static async Task AwaitAnswer(Task call) @@ -25,6 +22,7 @@ namespace Capnp.Rpc } public Skeleton ProvidedCap { get; } + int _releaseFlag; LocalCapability(Skeleton providedCap) { @@ -33,15 +31,20 @@ namespace Capnp.Rpc internal override void AddRef() { - ProvidedCap.Claim(); + if (0 == Interlocked.CompareExchange(ref _releaseFlag, 0, 1)) + ProvidedCap.Claim(); } internal override void Release( + bool keepAlive, [System.Runtime.CompilerServices.CallerMemberName] string methodName = "", [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0) { - ProvidedCap.Relinquish(); + if (keepAlive) + Interlocked.Exchange(ref _releaseFlag, 1); + else + ProvidedCap.Relinquish(); } internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) diff --git a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs index 5959b7e..ed51a34 100644 --- a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -27,6 +28,8 @@ namespace Capnp.Rpc public CancellationToken CancellationToken => _cts?.Token ?? CancellationToken.None; + public IReadOnlyList CapTable { get; set; } + public void Cancel() { _cts?.Cancel(); @@ -96,7 +99,7 @@ namespace Capnp.Rpc else { var path = MemberAccessPath.Deserialize(rd); - var cap = new RemoteAnswerCapability(aorcq.Counterquestion!, path); + var cap = new RemoteAnswerCapabilityDeprecated(aorcq.Counterquestion!, path); return new Proxy(cap); } } diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index 227f189..cf7a900 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -252,7 +252,39 @@ namespace Capnp.Rpc } else { - return new RemoteAnswerCapability(this, access); + return new RemoteAnswerCapabilityDeprecated(this, access); + } + } + } + + /// + /// Refer to a (possibly nested) member of this question's (possibly future) result and return + /// it as a capability. + /// + /// promises the cap whose ownership is transferred to this object + /// Low-level capability + /// The referenced member does not exist or does not resolve to a capability pointer. + public ConsumedCapability? Access(MemberAccessPath access, Task task) + { + var proxyTask = task.AsProxyTask(); + + lock (ReentrancyBlocker) + { + if (proxyTask.IsCompleted && !StateFlags.HasFlag(State.TailCall)) + { + try + { + using var proxy = proxyTask.Result; + return proxy.ConsumedCap; + } + catch (AggregateException exception) + { + throw exception.InnerException!; + } + } + else + { + return new RemoteAnswerCapabilityDeprecated(this, access); } } } @@ -263,13 +295,13 @@ namespace Capnp.Rpc { foreach (var cap in inParams.Caps!) { - cap?.Release(); + cap?.Release(false); } } if (target != null) { - target.Release(); + target.Release(false); } } @@ -277,7 +309,7 @@ namespace Capnp.Rpc { foreach (var cap in outParams.Caps!) { - cap?.Release(); + cap?.Release(false); } } diff --git a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs index 083a13d..27a23f4 100644 --- a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs @@ -8,15 +8,19 @@ namespace Capnp.Rpc { readonly uint _remoteId; readonly object _reentrancyBlocker = new object(); - readonly TaskCompletionSource _resolvedCap = new TaskCompletionSource(); + readonly TaskCompletionSource _resolvedCap = new TaskCompletionSource(); + readonly Task _whenResolvedProxy; bool _released; public PromisedCapability(IRpcEndpoint ep, uint remoteId): base(ep) { _remoteId = remoteId; + + async Task AwaitProxy() => new Proxy(await WhenResolved); + _whenResolvedProxy = AwaitProxy(); } - public override Task WhenResolved => _resolvedCap.Task; + public override Task WhenResolved => _resolvedCap.Task; internal override void Freeze(out IRpcEndpoint? boundEndpoint) { @@ -24,9 +28,11 @@ namespace Capnp.Rpc { if (_resolvedCap.Task.IsCompleted && _pendingCallsOnPromise == 0) { + boundEndpoint = null; + try { - _resolvedCap.Task.Result.Freeze(out boundEndpoint); + _resolvedCap.Task.Result?.Freeze(out boundEndpoint); } catch (AggregateException exception) { @@ -51,7 +57,7 @@ namespace Capnp.Rpc { if (_pendingCallsOnPromise == 0) { - _resolvedCap.Task.Result.Unfreeze(); + _resolvedCap.Task.Result?.Unfreeze(); } else { @@ -79,7 +85,8 @@ namespace Capnp.Rpc if (_resolvedCap.Task.ReplacementTaskIsCompletedSuccessfully()) { - _resolvedCap.Task.Result.Export(endpoint, writer); + using var proxy = new Proxy(_resolvedCap.Task.Result); + proxy.Export(endpoint, writer); } else { @@ -147,7 +154,7 @@ namespace Capnp.Rpc } } - protected override Proxy? ResolvedCap + protected override ConsumedCapability? ResolvedCap { get { @@ -194,7 +201,7 @@ namespace Capnp.Rpc lock (_reentrancyBlocker) { - _resolvedCap.SetResult(new Proxy(resolvedCap)); + _resolvedCap.SetResult(resolvedCap); if (_pendingCallsOnPromise == 0) { @@ -218,7 +225,7 @@ namespace Capnp.Rpc #if false _resolvedCap.SetException(new RpcException(message)); #else - _resolvedCap.SetResult(new Proxy(LazyCapability.CreateBrokenCap(message))); + _resolvedCap.SetResult(LazyCapability.CreateBrokenCap(message)); #endif if (_pendingCallsOnPromise == 0) @@ -234,7 +241,7 @@ namespace Capnp.Rpc } } - protected override void ReleaseRemotely() + protected async override void ReleaseRemotely() { if (!_released) { @@ -243,7 +250,8 @@ namespace Capnp.Rpc _ep.ReleaseImport(_remoteId); - this.DisposeWhenResolved(); + try { using var _ = await _whenResolvedProxy; } + catch { } } protected override Call.WRITER SetupMessage(DynamicSerializerState args, ulong interfaceId, ushort methodId) diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index ed0a976..18ab5f4 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -10,6 +10,14 @@ namespace Capnp.Rpc /// public class Proxy : IDisposable, IResolvingCapability { + public static T Share(T obj) where T: class + { + if (obj is Proxy proxy) + return proxy.Cast(false); + else + return BareProxy.FromImpl(obj).Cast(true); + } + #if DebugFinalizers ILogger Logger { get; } = Logging.CreateLogger(); #endif @@ -19,18 +27,13 @@ namespace Capnp.Rpc /// /// Will eventually give the resolved capability, if this is a promised capability. /// - public Task WhenResolved + public Task WhenResolved { get { - if (ConsumedCap is IResolvingCapability resolving) - { - return resolving.WhenResolved; - } - else - { - return Task.FromResult(this); - } + return ConsumedCap is IResolvingCapability resolving ? + resolving.WhenResolved : + Task.FromResult(ConsumedCap); } } @@ -139,20 +142,15 @@ namespace Capnp.Rpc { if (disposing) { - ConsumedCap?.Release(); + ConsumedCap?.Release(false); } else { // When called from the Finalizer, we must not throw. // But when reference counting goes wrong, ConsumedCapability.Release() will throw an InvalidOperationException. // The only option here is to suppress that exception. - try - { - ConsumedCap?.Release(); - } - catch - { - } + try { ConsumedCap?.Release(false); } + catch { } } _disposedValue = true; diff --git a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs index e64378c..240fc9e 100644 --- a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs @@ -46,13 +46,8 @@ namespace Capnp.Rpc { if (disposing) { - try - { - ReleaseRemotely(); - } - catch - { - } + try { ReleaseRemotely(); } + catch { } } else { @@ -60,13 +55,8 @@ namespace Capnp.Rpc { Task.Run(() => { - try - { - ReleaseRemotely(); - } - catch - { - } + try { ReleaseRemotely(); } + catch { } }); } } @@ -76,7 +66,11 @@ namespace Capnp.Rpc { lock (_reentrancyBlocker) { - if (++_refCount <= 1) + if (_refCount == int.MinValue) + { + _refCount = 2; + } + else if (++_refCount <= 1) { --_refCount; @@ -91,6 +85,7 @@ namespace Capnp.Rpc } internal sealed override void Release( + bool keepAlive, [System.Runtime.CompilerServices.CallerMemberName] string methodName = "", [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0) @@ -99,6 +94,10 @@ namespace Capnp.Rpc { switch (_refCount) { + case 2 when keepAlive: + _refCount = int.MinValue; + break; + case 1: // initial state, actually ref. count 0 case 2: // actually ref. count 1 _refCount = 0; diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index e3269e6..328e8e3 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -16,14 +16,25 @@ namespace Capnp.Rpc readonly PendingQuestion _question; readonly MemberAccessPath _access; - Proxy? _resolvedCap; + readonly Task _whenResolvedProxy; - public RemoteAnswerCapability(PendingQuestion question, MemberAccessPath access): base(question.RpcEndpoint) + public RemoteAnswerCapability(PendingQuestion question, MemberAccessPath access, Task proxyTask) : base(question.RpcEndpoint) { _question = question ?? throw new ArgumentNullException(nameof(question)); _access = access ?? throw new ArgumentNullException(nameof(access)); + _whenResolvedProxy = proxyTask ?? throw new ArgumentNullException(nameof(proxyTask)); - _ = AwaitWhenResolved(); + async Task AwaitWhenResolved() + { + var proxy = await _whenResolvedProxy; + + if (_question.IsTailCall) + throw new InvalidOperationException("Question is a tail call, so won't resolve back."); + + return proxy.ConsumedCap; + } + + WhenResolved = AwaitWhenResolved(); } async void ReAllowFinishWhenDone(Task task) @@ -47,52 +58,32 @@ namespace Capnp.Rpc } } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - lock (_question.ReentrancyBlocker) - { - _resolvedCap?.Dispose(); - } - } - - protected override Proxy? ResolvedCap + protected override ConsumedCapability? ResolvedCap { get { lock (_question.ReentrancyBlocker) { - if (_resolvedCap == null && !_question.IsTailCall && _question.IsReturned) + if (!_question.IsTailCall && WhenResolved.IsCompleted) { - DeserializerState result; try { - result = _question.WhenReturned.Result; + return WhenResolved.Result; } catch (AggregateException exception) { throw exception.InnerException!; } - - _resolvedCap = new Proxy(_access.Eval(result)); } - return _resolvedCap; + else + { + return null; + } } } } - async Task AwaitWhenResolved() - { - await _question.WhenReturned; - - if (_question.IsTailCall) - throw new InvalidOperationException("Question is a tail call, so won't resolve back."); - - return ResolvedCap!; - } - - public override Task WhenResolved => AwaitWhenResolved(); + public override Task WhenResolved { get; } protected override void GetMessageTarget(MessageTarget.WRITER wr) { @@ -251,9 +242,10 @@ namespace Capnp.Rpc } } - protected override void ReleaseRemotely() + protected async override void ReleaseRemotely() { - this.DisposeWhenResolved(); + try { using var _ = await _whenResolvedProxy; } + catch { } } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs new file mode 100644 index 0000000..51e8ee5 --- /dev/null +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs @@ -0,0 +1,265 @@ +using System; +using System.Threading.Tasks; + +namespace Capnp.Rpc +{ + + class RemoteAnswerCapabilityDeprecated : RemoteResolvingCapability + { + // Set DebugEmbargos to true to get logging output for calls. RPC calls are expected to + // be on the critical path, hence very relevant for performance. We just can't afford + // additional stuff on this path. Even if the logger filters the outputs away, there is + // overhead for creating the Logger object, calling the Logger methods and deciding to + // filter the output. This justifies the precompiler switch. +#if DebugEmbargos + ILogger Logger { get; } = Logging.CreateLogger(); +#endif + + readonly PendingQuestion _question; + readonly MemberAccessPath _access; + readonly Task _whenResolvedProxy; + ConsumedCapability? _resolvedCap; + + public RemoteAnswerCapabilityDeprecated(PendingQuestion question, MemberAccessPath access): base(question.RpcEndpoint) + { + _question = question ?? throw new ArgumentNullException(nameof(question)); + _access = access ?? throw new ArgumentNullException(nameof(access)); + + async Task AwaitWhenResolved() + { + await _question.WhenReturned; + + if (_question.IsTailCall) + throw new InvalidOperationException("Question is a tail call, so won't resolve back."); + + return ResolvedCap!; + } + + WhenResolved = AwaitWhenResolved(); + + async Task AwaitProxy() => new Proxy(await WhenResolved); + _whenResolvedProxy = AwaitProxy(); + } + + async void ReAllowFinishWhenDone(Task task) + { + try + { + ++_pendingCallsOnPromise; + + await task; + } + catch + { + } + finally + { + lock (_question.ReentrancyBlocker) + { + --_pendingCallsOnPromise; + _question.AllowFinish(); + } + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + lock (_question.ReentrancyBlocker) + { + using var _ = new Proxy(_resolvedCap); + } + } + + protected override ConsumedCapability? ResolvedCap + { + get + { + lock (_question.ReentrancyBlocker) + { + if (_resolvedCap == null && !_question.IsTailCall && _question.IsReturned) + { + DeserializerState result; + try + { + result = _question.WhenReturned.Result; + } + catch (AggregateException exception) + { + throw exception.InnerException!; + } + + _resolvedCap = _access.Eval(result); + } + return _resolvedCap; + } + } + } + + public override Task WhenResolved { get; } + + protected override void GetMessageTarget(MessageTarget.WRITER wr) + { + wr.which = MessageTarget.WHICH.PromisedAnswer; + wr.PromisedAnswer.QuestionId = _question.QuestionId; + _access.Serialize(wr.PromisedAnswer); + } + + internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) + { + lock (_question.ReentrancyBlocker) + { + if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned) && + !_question.StateFlags.HasFlag(PendingQuestion.State.TailCall)) + { + if (ResolvedCap == null) + { + throw new RpcException("Answer did not resolve to expected capability"); + } + + return CallOnResolution(interfaceId, methodId, args); + } + else + { +#if DebugEmbargos + Logger.LogDebug("Call by proxy"); +#endif + if (_question.StateFlags.HasFlag(PendingQuestion.State.Disposed)) + { + throw new ObjectDisposedException(nameof(PendingQuestion)); + } + + if (_question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested)) + { + throw new InvalidOperationException("Finish request was already sent"); + } + + _question.DisallowFinish(); + ++_pendingCallsOnPromise; + var promisedAnswer = base.DoCall(interfaceId, methodId, args); + ReAllowFinishWhenDone(promisedAnswer.WhenReturned); + + async void DecrementPendingCallsOnPromiseWhenReturned() + { + try + { + await promisedAnswer.WhenReturned; + } + catch + { + } + finally + { + lock (_question.ReentrancyBlocker) + { + --_pendingCallsOnPromise; + } + } + } + + DecrementPendingCallsOnPromiseWhenReturned(); + return promisedAnswer; + } + } + } + + protected override Call.WRITER SetupMessage(DynamicSerializerState args, ulong interfaceId, ushort methodId) + { + var call = base.SetupMessage(args, interfaceId, methodId); + + call.Target.which = MessageTarget.WHICH.PromisedAnswer; + call.Target.PromisedAnswer.QuestionId = _question.QuestionId; + _access.Serialize(call.Target.PromisedAnswer); + + return call; + } + + internal override void Freeze(out IRpcEndpoint? boundEndpoint) + { + lock (_question.ReentrancyBlocker) + { + if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned) && + _pendingCallsOnPromise == 0) + { + if (ResolvedCap == null) + { + throw new RpcException("Answer did not resolve to expected capability"); + } + + ResolvedCap.Freeze(out boundEndpoint); + } + else + { + ++_pendingCallsOnPromise; + _question.DisallowFinish(); + boundEndpoint = _ep; + } + } + } + + internal override void Unfreeze() + { + lock (_question.ReentrancyBlocker) + { + if (_pendingCallsOnPromise > 0) + { + --_pendingCallsOnPromise; + _question.AllowFinish(); + } + else + { + ResolvedCap?.Unfreeze(); + } + } + } + + internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) + { + lock (_question.ReentrancyBlocker) + { + if (_question.StateFlags.HasFlag(PendingQuestion.State.Disposed)) + throw new ObjectDisposedException(nameof(PendingQuestion)); + + if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned)) + { + ResolvedCap?.Export(endpoint, writer); + } + else + { + if (_question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested)) + throw new InvalidOperationException("Finish request was already sent"); + + if (endpoint == _ep) + { + writer.which = CapDescriptor.WHICH.ReceiverAnswer; + _access.Serialize(writer.ReceiverAnswer); + writer.ReceiverAnswer.QuestionId = _question.QuestionId; + } + else if (_question.IsTailCall) + { + // FIXME: Resource management! We should prevent finishing this + // cap as long as it is exported. Unfortunately, we cannot determine + // when it gets removed from the export table. + + var vine = Vine.Create(this); + uint id = endpoint.AllocateExport(vine, out bool first); + + writer.which = CapDescriptor.WHICH.SenderHosted; + writer.SenderHosted = id; + } + else + { + this.ExportAsSenderPromise(endpoint, writer); + } + } + } + } + + protected async override void ReleaseRemotely() + { + try { using var _ = await _whenResolvedProxy; } + catch { } + } + } +} \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs index 225c8e1..868e775 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs @@ -16,7 +16,7 @@ namespace Capnp.Rpc ILogger Logger { get; } = Logging.CreateLogger(); #endif - public abstract Task WhenResolved { get; } + public abstract Task WhenResolved { get; } protected RemoteResolvingCapability(IRpcEndpoint ep) : base(ep) { @@ -25,7 +25,7 @@ namespace Capnp.Rpc protected int _pendingCallsOnPromise; Task? _disembargo; - protected abstract Proxy? ResolvedCap { get; } + protected abstract ConsumedCapability? ResolvedCap { get; } protected abstract void GetMessageTarget(MessageTarget.WRITER wr); @@ -46,7 +46,7 @@ namespace Capnp.Rpc throw new NotImplementedException("Sorry, level 3 RPC is not yet supported."); } - if (ResolvedCap.IsNull || + if (ResolvedCap == null || // If the capability resolves to null, disembargo must not be requested. // Take the direct path, well-knowing that the call will result in an exception. @@ -65,7 +65,8 @@ namespace Capnp.Rpc #if DebugEmbargos Logger.LogDebug("Direct call"); #endif - return ResolvedCap.Call(interfaceId, methodId, args, default); + using var proxy = new Proxy(ResolvedCap); + return proxy.Call(interfaceId, methodId, args, default); } else { @@ -93,7 +94,8 @@ namespace Capnp.Rpc cancellationTokenSource.Token.ThrowIfCancellationRequested(); - return ResolvedCap.Call(interfaceId, methodId, args, default); + using var proxy = new Proxy(ResolvedCap); + return proxy.Call(interfaceId, methodId, args, default); }, TaskContinuationOptions.ExecuteSynchronously); diff --git a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs index 9b68f7e..36d0ae2 100644 --- a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs @@ -1,4 +1,7 @@ -namespace Capnp.Rpc +using System; +using System.Threading.Tasks; + +namespace Capnp.Rpc { static class ResolvingCapabilityExtensions { @@ -18,8 +21,7 @@ try { var resolvedCap = await cap.WhenResolved; - - endpoint.Resolve(preliminaryId, vine, () => resolvedCap.ConsumedCap!); + endpoint.Resolve(preliminaryId, vine, () => resolvedCap!); } catch (System.Exception exception) { @@ -30,15 +32,10 @@ } } - public static async void DisposeWhenResolved(this IResolvingCapability cap) + public static async Task AsProxyTask(this Task task) { - try - { - (await cap.WhenResolved)?.Dispose(); - } - catch - { - } + var obj = await task; + return obj is Proxy proxy ? proxy : BareProxy.FromImpl(obj); } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 0e66b88..0b1ad55 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -433,6 +433,7 @@ namespace Capnp.Rpc ret.Results.Content = results.Rewrap(); ret.ReleaseParamCaps = releaseParamCaps; ExportCapTableAndSend(results, ret.Results); + pendingAnswer.CapTable = ret.Results.CapTable; break; case Call.sendResultsTo.WHICH.Yourself: @@ -592,11 +593,9 @@ namespace Capnp.Rpc { try { - using (var proxy = await t) - { - cap = proxy?.GetProvider(); - CreateAnswerAwaitItAndReply(); - } + using var proxy = await t; + cap = proxy?.GetProvider(); + CreateAnswerAwaitItAndReply(); } catch (TaskCanceledException) { @@ -825,31 +824,29 @@ namespace Capnp.Rpc { try { - using (var proxy = await t) - { - proxy.Freeze(out var boundEndpoint); + using var proxy = await t; + proxy.Freeze(out var boundEndpoint); - try + try + { + if (boundEndpoint == this) { - if (boundEndpoint == this) - { #if DebugEmbargos Logger.LogDebug($"Sender loopback disembargo. Thread = {Thread.CurrentThread.Name}"); #endif - Tx(mb.Frame); - } - else - { - Logger.LogWarning("Sender loopback request: Peer asked for disembargoing an answer which does not resolve back to the sender."); - - throw new RpcProtocolErrorException("'Disembargo': Answer does not resolve back to me"); - } + Tx(mb.Frame); } - finally + else { - proxy.Unfreeze(); + Logger.LogWarning("Sender loopback request: Peer asked for disembargoing an answer which does not resolve back to the sender."); + + throw new RpcProtocolErrorException("'Disembargo': Answer does not resolve back to me"); } } + finally + { + proxy.Unfreeze(); + } } catch (System.Exception exception) { @@ -933,15 +930,32 @@ namespace Capnp.Rpc try { var aorcq = await t; - var results = aorcq.Answer; + var caps = answer.CapTable; - if (results != null && results.Caps != null) + if (caps != null) { - foreach (var cap in results.Caps) + foreach (var capDesc in caps) { - cap?.Release(); + switch (capDesc.which) + { + case CapDescriptor.WHICH.SenderHosted: + ReleaseExport(capDesc.SenderHosted, 1); + break; + + case CapDescriptor.WHICH.SenderPromise: + ReleaseExport(capDesc.SenderPromise, 1); + break; + } } } + + //if (results != null && results.Caps != null) + //{ + // foreach (var cap in results.Caps) + // { + // cap?.Release(); + // } + //} } catch { @@ -1091,7 +1105,7 @@ namespace Capnp.Rpc Tx(mb.Frame); - var main = new RemoteAnswerCapability( + var main = new RemoteAnswerCapabilityDeprecated( pendingBootstrap, MemberAccessPath.BootstrapAccess); @@ -1360,7 +1374,7 @@ namespace Capnp.Rpc else { cap.Export(this, capDesc); - cap.Release(); + cap.Release(false); } } diff --git a/Capnp.Net.Runtime/Rpc/Vine.cs b/Capnp.Net.Runtime/Rpc/Vine.cs index 52f10c1..db63d0c 100644 --- a/Capnp.Net.Runtime/Rpc/Vine.cs +++ b/Capnp.Net.Runtime/Rpc/Vine.cs @@ -38,10 +38,8 @@ namespace Capnp.Rpc { try { - using (var registration = cancellationToken.Register(promisedAnswer.Dispose)) - { - await promisedAnswer.WhenReturned; - } + using var registration = cancellationToken.Register(promisedAnswer.Dispose); + await promisedAnswer.WhenReturned; } catch { @@ -54,10 +52,8 @@ namespace Capnp.Rpc } else { - using (var registration = cancellationToken.Register(promisedAnswer.Dispose)) - { - return (DynamicSerializerState)await promisedAnswer.WhenReturned; - } + using var registration = cancellationToken.Register(promisedAnswer.Dispose); + return (DynamicSerializerState)await promisedAnswer.WhenReturned; } } diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index f52cc18..7bdb9e2 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -1259,7 +1259,8 @@ namespace Capnp /// /// The capability, in one of the following forms: /// Low-level capability object (Rpc.ConsumedCapability) - /// Proxy object (Rpc.Proxy) + /// Proxy object (Rpc.Proxy). Note that the provision has "move semantics": SerializerState + /// takes ownership, so the Proxy object will be disposed. /// Skeleton object (Rpc.Skeleton) /// Capability interface implementation /// @@ -1267,16 +1268,19 @@ namespace Capnp /// The underlying message builder was not configured for capability table support. public uint ProvideCapability(object? obj) { - if (obj == null) - return ProvideCapability(default(Rpc.ConsumedCapability)); - else if (obj is Rpc.Proxy proxy) - return ProvideCapability(proxy.ConsumedCap); - else if (obj is Rpc.ConsumedCapability consumedCapability) - return ProvideCapability(consumedCapability); - else if (obj is Rpc.Skeleton providedCapability) - return ProvideCapability(providedCapability); - else - return ProvideCapability(Rpc.Skeleton.GetOrCreateSkeleton(obj, false)); + switch (obj) + { + case null: + return ProvideCapability(default(Rpc.ConsumedCapability)); + case Rpc.Proxy proxy: using (proxy) + return ProvideCapability(proxy.ConsumedCap); + case Rpc.ConsumedCapability consumedCapability: + return ProvideCapability(consumedCapability); + case Rpc.Skeleton providedCapability: + return ProvideCapability(providedCapability); + default: + return ProvideCapability(Rpc.Skeleton.GetOrCreateSkeleton(obj, false)); + } } /// From e0d8f70cfc564b439d315130215b659b575b26fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 21 Mar 2020 13:27:46 +0100 Subject: [PATCH 16/76] some refactoring. all tests green again --- .../Capnp.Net.Runtime.Tests.Std20.csproj | 2 +- Capnp.Net.Runtime.Tests/Dtbdct.cs | 96 + Capnp.Net.Runtime.Tests/Interception.cs | 14 +- Capnp.Net.Runtime.Tests/LocalRpc.cs | 14 +- .../{ => Mock}/TestCapImplementations.cs | 22 +- Capnp.Net.Runtime.Tests/{ => Mock}/test.cs | 2314 +++++++++-------- .../TcpRpcErrorHandling.cs | 8 +- Capnp.Net.Runtime.Tests/TcpRpcInterop.cs | 2 +- Capnp.Net.Runtime.Tests/TcpRpcPorted.cs | 528 +--- Capnp.Net.Runtime.Tests/TcpRpcStress.cs | 61 +- Capnp.Net.Runtime.Tests/TestBase.cs | 130 - Capnp.Net.Runtime.Tests/Testsuite.cs | 523 ++++ Capnp.Net.Runtime.Tests/Util/DecisionTree.cs | 98 + Capnp.Net.Runtime.Tests/{ => Util}/JobUtil.cs | 0 .../{ => Util}/ScatteringStream.cs | 0 Capnp.Net.Runtime.Tests/Util/TestBase.cs | 350 +++ Capnp.Net.Runtime/Capnp.Net.Runtime.csproj | 2 +- Capnp.Net.Runtime/CapnpSerializable.cs | 1 + Capnp.Net.Runtime/DeserializerState.cs | 27 +- Capnp.Net.Runtime/DynamicSerializerState.cs | 2 - Capnp.Net.Runtime/Rpc/CapabilityReflection.cs | 16 +- Capnp.Net.Runtime/Rpc/ConsumedCapability.cs | 12 +- Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs | 2 +- Capnp.Net.Runtime/Rpc/IRpcEndpoint.cs | 1 - Capnp.Net.Runtime/Rpc/Impatient.cs | 31 +- Capnp.Net.Runtime/Rpc/ImportedCapability.cs | 7 +- .../Rpc/Interception/CallContext.cs | 2 +- .../Rpc/Interception/CensorCapability.cs | 7 +- Capnp.Net.Runtime/Rpc/LazyCapability.cs | 15 +- Capnp.Net.Runtime/Rpc/LocalAnswer.cs | 2 +- .../Rpc/LocalAnswerCapability.cs | 8 +- .../Rpc/LocalAnswerCapabilityDeprecated.cs | 5 +- Capnp.Net.Runtime/Rpc/LocalCapability.cs | 3 +- Capnp.Net.Runtime/Rpc/MemberAccessPath.cs | 2 +- Capnp.Net.Runtime/Rpc/PendingAnswer.cs | 53 +- Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 73 +- Capnp.Net.Runtime/Rpc/PromisedCapability.cs | 8 +- Capnp.Net.Runtime/Rpc/Proxy.cs | 16 +- .../Rpc/RefCountingCapability.cs | 19 +- .../Rpc/RemoteAnswerCapability.cs | 30 +- .../Rpc/RemoteAnswerCapabilityDeprecated.cs | 18 +- .../Rpc/ResolvingCapabilityExtensions.cs | 17 +- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 49 +- Capnp.Net.Runtime/Rpc/Vine.cs | 19 +- Capnp.Net.sln | 6 - .../Embedded Resources/test.cs | 1030 +++++--- CapnpC.CSharp.Generator/CodeGen/GenNames.cs | 2 + .../CodeGen/GeneratorOptions.cs | 1 + .../CodeGen/InterfaceSnippetGen.cs | 94 +- 49 files changed, 3418 insertions(+), 2324 deletions(-) create mode 100644 Capnp.Net.Runtime.Tests/Dtbdct.cs rename Capnp.Net.Runtime.Tests/{ => Mock}/TestCapImplementations.cs (98%) rename Capnp.Net.Runtime.Tests/{ => Mock}/test.cs (89%) delete mode 100644 Capnp.Net.Runtime.Tests/TestBase.cs create mode 100644 Capnp.Net.Runtime.Tests/Testsuite.cs create mode 100644 Capnp.Net.Runtime.Tests/Util/DecisionTree.cs rename Capnp.Net.Runtime.Tests/{ => Util}/JobUtil.cs (100%) rename Capnp.Net.Runtime.Tests/{ => Util}/ScatteringStream.cs (100%) create mode 100644 Capnp.Net.Runtime.Tests/Util/TestBase.cs diff --git a/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj b/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj index cb369cc..0b26467 100644 --- a/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj +++ b/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj @@ -1,7 +1,7 @@  - net471 + netcoreapp2.1;net471 false diff --git a/Capnp.Net.Runtime.Tests/Dtbdct.cs b/Capnp.Net.Runtime.Tests/Dtbdct.cs new file mode 100644 index 0000000..75d2a93 --- /dev/null +++ b/Capnp.Net.Runtime.Tests/Dtbdct.cs @@ -0,0 +1,96 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Capnp.Net.Runtime.Tests +{ + [TestClass] + [TestCategory("Coverage")] + public class Dtbdct: TestBase + { + [TestMethod] + public void Embargo() + { + NewDtbdctTestbed().RunTest(Testsuite.Embargo); + } + + [TestMethod] + public void EmbargoError() + { + NewDtbdctTestbed().RunTest(Testsuite.EmbargoError); + } + + [TestMethod] + public void EmbargoNull() + { + NewDtbdctTestbed().RunTest(Testsuite.EmbargoNull); + } + + [TestMethod] + public void CallBrokenPromise() + { + NewDtbdctTestbed().RunTest(Testsuite.CallBrokenPromise); + } + + [TestMethod] + public void TailCall() + { + NewDtbdctTestbed().RunTest(Testsuite.TailCall); + } + + [TestMethod] + public void SendTwice() + { + NewDtbdctTestbed().RunTest(Testsuite.SendTwice); + } + + [TestMethod] + public void Cancel() + { + NewDtbdctTestbed().RunTest(Testsuite.Cancel); + } + + [TestMethod] + public void RetainAndRelease() + { + NewDtbdctTestbed().RunTest(Testsuite.RetainAndRelease); + } + + [TestMethod] + public void PromiseResolve() + { + NewDtbdctTestbed().RunTest(Testsuite.PromiseResolve); + } + + [TestMethod] + public void Cancelation() + { + NewDtbdctTestbed().RunTest(Testsuite.Cancelation); + } + + [TestMethod] + public void ReleaseOnCancel() + { + NewDtbdctTestbed().RunTest(Testsuite.ReleaseOnCancel); + } + + [TestMethod] + public void Release() + { + NewDtbdctTestbed().RunTest(Testsuite.Release); + } + + [TestMethod] + public void Pipeline() + { + NewDtbdctTestbed().RunTest(Testsuite.Pipeline); + } + + [TestMethod] + public void Basic() + { + NewDtbdctTestbed().RunTest(Testsuite.Basic); + } + } +} diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index ac0ea63..3008723 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -78,13 +78,13 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(fcc.Wait(MediumNonDbgTimeout)); var cc = fcc.Result; - var pr = new Capnproto_test.Capnp.Test.TestInterface.Params_foo.READER(cc.InArgs); + var pr = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo.READER(cc.InArgs); Assert.AreEqual(123u, pr.I); cc.ForwardToBob(); Assert.IsTrue(policy.Returns.ReceiveAsync().Wait(MediumNonDbgTimeout)); - var rr = new Capnproto_test.Capnp.Test.TestInterface.Result_foo.READER(cc.OutArgs); + var rr = new Capnproto_test.Capnp.Test.TestInterface.Result_Foo.READER(cc.OutArgs); Assert.AreEqual("foo", rr.X); cc.ReturnToAlice(); @@ -117,11 +117,11 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(InterceptionState.RequestedFromAlice, cc.State); - var pr = new Capnproto_test.Capnp.Test.TestInterface.Params_foo.READER(cc.InArgs); + var pr = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo.READER(cc.InArgs); Assert.AreEqual(321u, pr.I); Assert.AreEqual(false, pr.J); - var pw = cc.InArgs.Rewrap(); + var pw = cc.InArgs.Rewrap(); pw.I = 123u; pw.J = true; @@ -133,12 +133,12 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(cc.State == InterceptionState.ForwardedToBob || rx.IsCompleted); Assert.IsTrue(rx.Wait(MediumNonDbgTimeout)); - var rr = new Capnproto_test.Capnp.Test.TestInterface.Result_foo.READER(cc.OutArgs); + var rr = new Capnproto_test.Capnp.Test.TestInterface.Result_Foo.READER(cc.OutArgs); Assert.AreEqual("foo", rr.X); Assert.IsFalse(request1.IsCompleted); - var rw = ((DynamicSerializerState)cc.OutArgs).Rewrap(); + var rw = ((DynamicSerializerState)cc.OutArgs).Rewrap(); rw.X = "bar"; cc.OutArgs = rw; @@ -174,7 +174,7 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(policy.Calls.TryReceive(out var cc)); Assert.IsFalse(request1.IsCompleted); - var rw = SerializerState.CreateForRpc(); + var rw = SerializerState.CreateForRpc(); rw.X = "bar"; cc.OutArgs = rw; diff --git a/Capnp.Net.Runtime.Tests/LocalRpc.cs b/Capnp.Net.Runtime.Tests/LocalRpc.cs index 232313b..fd4f87b 100644 --- a/Capnp.Net.Runtime.Tests/LocalRpc.cs +++ b/Capnp.Net.Runtime.Tests/LocalRpc.cs @@ -20,12 +20,14 @@ namespace Capnp.Net.Runtime.Tests var tcs = new TaskCompletionSource(); var impl = new TestPipelineImpl2(tcs.Task); var bproxy = BareProxy.FromImpl(impl); - var proxy = bproxy.Cast(true); - var cap = proxy.GetCap(0, null).OutBox_Cap(); - var foo = cap.Foo(123, true); - tcs.SetResult(0); - Assert.IsTrue(foo.Wait(TestBase.MediumNonDbgTimeout)); - Assert.AreEqual("bar", foo.Result); + using (var proxy = bproxy.Cast(true)) + using (var cap = proxy.GetCap(0, null).OutBox_Cap()) + { + var foo = cap.Foo(123, true); + tcs.SetResult(0); + Assert.IsTrue(foo.Wait(TestBase.MediumNonDbgTimeout)); + Assert.AreEqual("bar", foo.Result); + } } } } diff --git a/Capnp.Net.Runtime.Tests/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs similarity index 98% rename from Capnp.Net.Runtime.Tests/TestCapImplementations.cs rename to Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs index 44cfde2..34fd9fe 100644 --- a/Capnp.Net.Runtime.Tests/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs @@ -574,18 +574,17 @@ namespace Capnp.Net.Runtime.Tests.GenImpls class TestCallOrderImpl : ITestCallOrder { readonly object _lock = new object(); + uint _counter; ILogger Logger { get; } = Logging.CreateLogger(); - public uint Count { get; set; } - public uint? CountToDispose { get; set; } public void Dispose() { lock (_lock) - { - Assert.IsTrue(!CountToDispose.HasValue || Count == CountToDispose, "Must not dispose at this point"); + { + Assert.IsTrue(!CountToDispose.HasValue || _counter == CountToDispose, $"Must not dispose at this point: {_counter} {Thread.CurrentThread.Name}"); } } @@ -593,7 +592,18 @@ namespace Capnp.Net.Runtime.Tests.GenImpls { lock (_lock) { - return Task.FromResult(Count++); + return Task.FromResult(_counter++); + } + } + + public uint Count + { + get + { + lock (_lock) + { + return _counter; + } } } } @@ -749,7 +759,7 @@ namespace Capnp.Net.Runtime.Tests.GenImpls public Task GetHeld(CancellationToken cancellationToken_) { Interlocked.Increment(ref _counters.CallCount); - return Task.FromResult(ClientToHold); + return Task.FromResult(Proxy.Share(ClientToHold)); } public Task GetNull(CancellationToken cancellationToken_) diff --git a/Capnp.Net.Runtime.Tests/test.cs b/Capnp.Net.Runtime.Tests/Mock/test.cs similarity index 89% rename from Capnp.Net.Runtime.Tests/test.cs rename to Capnp.Net.Runtime.Tests/Mock/test.cs index db23211..f7930f2 100644 --- a/Capnp.Net.Runtime.Tests/test.cs +++ b/Capnp.Net.Runtime.Tests/Mock/test.cs @@ -56,7 +56,7 @@ namespace Capnproto_test.Capnp.Test Float64List = reader.Float64List; TextList = reader.TextList; DataList = reader.DataList; - StructList = reader.StructList.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + StructList = reader.StructList?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); EnumList = reader.EnumList; InterfaceList = reader.InterfaceList; applyDefaults(); @@ -321,7 +321,7 @@ namespace Capnproto_test.Capnp.Test public ulong UInt64Field => ctx.ReadDataULong(192UL, 0UL); public float Float32Field => ctx.ReadDataFloat(256UL, 0F); public double Float64Field => ctx.ReadDataDouble(320UL, 0); - public string TextField => ctx.ReadText(0, ""); + public string TextField => ctx.ReadText(0, null); public IReadOnlyList DataField => ctx.ReadList(1).CastByte(); public Capnproto_test.Capnp.Test.TestAllTypes.READER StructField => ctx.ReadStruct(2, Capnproto_test.Capnp.Test.TestAllTypes.READER.create); public Capnproto_test.Capnp.Test.TestEnum EnumField => (Capnproto_test.Capnp.Test.TestEnum)ctx.ReadDataUShort(288UL, (ushort)0); @@ -419,8 +419,8 @@ namespace Capnproto_test.Capnp.Test public string TextField { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public ListOfPrimitivesSerializer DataField @@ -581,7 +581,7 @@ namespace Capnproto_test.Capnp.Test Float64List = reader.Float64List; TextList = reader.TextList; DataList = reader.DataList; - StructList = reader.StructList.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + StructList = reader.StructList?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); EnumList = reader.EnumList; InterfaceList = reader.InterfaceList; applyDefaults(); @@ -1284,7 +1284,7 @@ namespace Capnproto_test.Capnp.Test { var reader = READER.create(arg_); AnyStructField = CapnpSerializable.Create(reader.AnyStructField); - AnyListField = reader.AnyListField.ToReadOnlyList(_ => (object)_); + AnyListField = reader.AnyListField?.ToReadOnlyList(_ => (object)_); CapabilityField = reader.CapabilityField; applyDefaults(); } @@ -1472,15 +1472,15 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Qux => ctx.ReadText(0, ""); - public string Grault => ctx.ReadText(1, ""); - public string Bar => ctx.ReadText(2, ""); - public string Foo => ctx.ReadText(3, ""); - public string Corge => ctx.ReadText(4, ""); - public string Waldo => ctx.ReadText(5, ""); - public string Quux => ctx.ReadText(6, ""); - public string Garply => ctx.ReadText(7, ""); - public string Baz => ctx.ReadText(8, ""); + public string Qux => ctx.ReadText(0, null); + public string Grault => ctx.ReadText(1, null); + public string Bar => ctx.ReadText(2, null); + public string Foo => ctx.ReadText(3, null); + public string Corge => ctx.ReadText(4, null); + public string Waldo => ctx.ReadText(5, null); + public string Quux => ctx.ReadText(6, null); + public string Garply => ctx.ReadText(7, null); + public string Baz => ctx.ReadText(8, null); } public class WRITER : SerializerState @@ -1492,56 +1492,56 @@ namespace Capnproto_test.Capnp.Test public string Qux { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public string Grault { - get => this.ReadText(1, ""); - set => this.WriteText(1, value, ""); + get => this.ReadText(1, null); + set => this.WriteText(1, value, null); } public string Bar { - get => this.ReadText(2, ""); - set => this.WriteText(2, value, ""); + get => this.ReadText(2, null); + set => this.WriteText(2, value, null); } public string Foo { - get => this.ReadText(3, ""); - set => this.WriteText(3, value, ""); + get => this.ReadText(3, null); + set => this.WriteText(3, value, null); } public string Corge { - get => this.ReadText(4, ""); - set => this.WriteText(4, value, ""); + get => this.ReadText(4, null); + set => this.WriteText(4, value, null); } public string Waldo { - get => this.ReadText(5, ""); - set => this.WriteText(5, value, ""); + get => this.ReadText(5, null); + set => this.WriteText(5, value, null); } public string Quux { - get => this.ReadText(6, ""); - set => this.WriteText(6, value, ""); + get => this.ReadText(6, null); + set => this.WriteText(6, value, null); } public string Garply { - get => this.ReadText(7, ""); - set => this.WriteText(7, value, ""); + get => this.ReadText(7, null); + set => this.WriteText(7, value, null); } public string Baz { - get => this.ReadText(8, ""); - set => this.WriteText(8, value, ""); + get => this.ReadText(8, null); + set => this.WriteText(8, value, null); } } } @@ -1553,10 +1553,10 @@ namespace Capnproto_test.Capnp.Test void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); - Union0 = CapnpSerializable.Create(reader.Union0); - Union1 = CapnpSerializable.Create(reader.Union1); - Union2 = CapnpSerializable.Create(reader.Union2); - Union3 = CapnpSerializable.Create(reader.Union3); + Union0 = CapnpSerializable.Create(reader.Union0); + Union1 = CapnpSerializable.Create(reader.Union1); + Union2 = CapnpSerializable.Create(reader.Union2); + Union3 = CapnpSerializable.Create(reader.Union3); Bit0 = reader.Bit0; Bit2 = reader.Bit2; Bit3 = reader.Bit3; @@ -1593,25 +1593,25 @@ namespace Capnproto_test.Capnp.Test { } - public Capnproto_test.Capnp.Test.TestUnion.@union0 Union0 + public Capnproto_test.Capnp.Test.TestUnion.union0 Union0 { get; set; } - public Capnproto_test.Capnp.Test.TestUnion.@union1 Union1 + public Capnproto_test.Capnp.Test.TestUnion.union1 Union1 { get; set; } - public Capnproto_test.Capnp.Test.TestUnion.@union2 Union2 + public Capnproto_test.Capnp.Test.TestUnion.union2 Union2 { get; set; } - public Capnproto_test.Capnp.Test.TestUnion.@union3 Union3 + public Capnproto_test.Capnp.Test.TestUnion.union3 Union3 { get; set; @@ -1676,10 +1676,10 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public @union0.READER Union0 => new @union0.READER(ctx); - public @union1.READER Union1 => new @union1.READER(ctx); - public @union2.READER Union2 => new @union2.READER(ctx); - public @union3.READER Union3 => new @union3.READER(ctx); + public union0.READER Union0 => new union0.READER(ctx); + public union1.READER Union1 => new union1.READER(ctx); + public union2.READER Union2 => new union2.READER(ctx); + public union3.READER Union3 => new union3.READER(ctx); public bool Bit0 => ctx.ReadDataBool(128UL, false); public bool Bit2 => ctx.ReadDataBool(130UL, false); public bool Bit3 => ctx.ReadDataBool(131UL, false); @@ -1697,24 +1697,24 @@ namespace Capnproto_test.Capnp.Test this.SetStruct(8, 2); } - public @union0.WRITER Union0 + public union0.WRITER Union0 { - get => Rewrap<@union0.WRITER>(); + get => Rewrap(); } - public @union1.WRITER Union1 + public union1.WRITER Union1 { - get => Rewrap<@union1.WRITER>(); + get => Rewrap(); } - public @union2.WRITER Union2 + public union2.WRITER Union2 { - get => Rewrap<@union2.WRITER>(); + get => Rewrap(); } - public @union3.WRITER Union3 + public union3.WRITER Union3 { - get => Rewrap<@union3.WRITER>(); + get => Rewrap(); } public bool Bit0 @@ -1767,7 +1767,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xfc76a82eecb7a718UL)] - public class @union0 : ICapnpSerializable + public class union0 : ICapnpSerializable { public const UInt64 typeId = 0xfc76a82eecb7a718UL; public enum WHICH : ushort @@ -2091,13 +2091,13 @@ namespace Capnproto_test.Capnp.Test public short U0f0s16 => which == WHICH.U0f0s16 ? ctx.ReadDataShort(64UL, (short)0) : default; public int U0f0s32 => which == WHICH.U0f0s32 ? ctx.ReadDataInt(64UL, 0) : default; public long U0f0s64 => which == WHICH.U0f0s64 ? ctx.ReadDataLong(64UL, 0L) : default; - public string U0f0sp => which == WHICH.U0f0sp ? ctx.ReadText(0, "") : default; + public string U0f0sp => which == WHICH.U0f0sp ? ctx.ReadText(0, null) : default; public bool U0f1s1 => which == WHICH.U0f1s1 ? ctx.ReadDataBool(64UL, false) : default; public sbyte U0f1s8 => which == WHICH.U0f1s8 ? ctx.ReadDataSByte(64UL, (sbyte)0) : default; public short U0f1s16 => which == WHICH.U0f1s16 ? ctx.ReadDataShort(64UL, (short)0) : default; public int U0f1s32 => which == WHICH.U0f1s32 ? ctx.ReadDataInt(64UL, 0) : default; public long U0f1s64 => which == WHICH.U0f1s64 ? ctx.ReadDataLong(64UL, 0L) : default; - public string U0f1sp => which == WHICH.U0f1sp ? ctx.ReadText(0, "") : default; + public string U0f1sp => which == WHICH.U0f1sp ? ctx.ReadText(0, null) : default; } public class WRITER : SerializerState @@ -2144,8 +2144,8 @@ namespace Capnproto_test.Capnp.Test public string U0f0sp { - get => which == WHICH.U0f0sp ? this.ReadText(0, "") : default; - set => this.WriteText(0, value, ""); + get => which == WHICH.U0f0sp ? this.ReadText(0, null) : default; + set => this.WriteText(0, value, null); } public bool U0f1s1 @@ -2180,14 +2180,14 @@ namespace Capnproto_test.Capnp.Test public string U0f1sp { - get => which == WHICH.U0f1sp ? this.ReadText(0, "") : default; - set => this.WriteText(0, value, ""); + get => which == WHICH.U0f1sp ? this.ReadText(0, null) : default; + set => this.WriteText(0, value, null); } } } [TypeId(0xee0a6b99b7dc7ab2UL)] - public class @union1 : ICapnpSerializable + public class union1 : ICapnpSerializable { public const UInt64 typeId = 0xee0a6b99b7dc7ab2UL; public enum WHICH : ushort @@ -2636,14 +2636,14 @@ namespace Capnproto_test.Capnp.Test public int U1f1s32 => which == WHICH.U1f1s32 ? ctx.ReadDataInt(160UL, 0) : default; public long U1f0s64 => which == WHICH.U1f0s64 ? ctx.ReadDataLong(192UL, 0L) : default; public long U1f1s64 => which == WHICH.U1f1s64 ? ctx.ReadDataLong(192UL, 0L) : default; - public string U1f0sp => which == WHICH.U1f0sp ? ctx.ReadText(1, "") : default; - public string U1f1sp => which == WHICH.U1f1sp ? ctx.ReadText(1, "") : default; + public string U1f0sp => which == WHICH.U1f0sp ? ctx.ReadText(1, null) : default; + public string U1f1sp => which == WHICH.U1f1sp ? ctx.ReadText(1, null) : default; public bool U1f2s1 => which == WHICH.U1f2s1 ? ctx.ReadDataBool(129UL, false) : default; public sbyte U1f2s8 => which == WHICH.U1f2s8 ? ctx.ReadDataSByte(136UL, (sbyte)0) : default; public short U1f2s16 => which == WHICH.U1f2s16 ? ctx.ReadDataShort(144UL, (short)0) : default; public int U1f2s32 => which == WHICH.U1f2s32 ? ctx.ReadDataInt(160UL, 0) : default; public long U1f2s64 => which == WHICH.U1f2s64 ? ctx.ReadDataLong(192UL, 0L) : default; - public string U1f2sp => which == WHICH.U1f2sp ? ctx.ReadText(1, "") : default; + public string U1f2sp => which == WHICH.U1f2sp ? ctx.ReadText(1, null) : default; } public class WRITER : SerializerState @@ -2720,14 +2720,14 @@ namespace Capnproto_test.Capnp.Test public string U1f0sp { - get => which == WHICH.U1f0sp ? this.ReadText(1, "") : default; - set => this.WriteText(1, value, ""); + get => which == WHICH.U1f0sp ? this.ReadText(1, null) : default; + set => this.WriteText(1, value, null); } public string U1f1sp { - get => which == WHICH.U1f1sp ? this.ReadText(1, "") : default; - set => this.WriteText(1, value, ""); + get => which == WHICH.U1f1sp ? this.ReadText(1, null) : default; + set => this.WriteText(1, value, null); } public bool U1f2s1 @@ -2762,14 +2762,14 @@ namespace Capnproto_test.Capnp.Test public string U1f2sp { - get => which == WHICH.U1f2sp ? this.ReadText(1, "") : default; - set => this.WriteText(1, value, ""); + get => which == WHICH.U1f2sp ? this.ReadText(1, null) : default; + set => this.WriteText(1, value, null); } } } [TypeId(0xafc5fd419f0d66d4UL)] - public class @union2 : ICapnpSerializable + public class union2 : ICapnpSerializable { public const UInt64 typeId = 0xafc5fd419f0d66d4UL; public enum WHICH : ushort @@ -2984,7 +2984,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xa2fb022ec7f30053UL)] - public class @union3 : ICapnpSerializable + public class union3 : ICapnpSerializable { public const UInt64 typeId = 0xa2fb022ec7f30053UL; public enum WHICH : ushort @@ -3328,11 +3328,11 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public WHICH which => (WHICH)ctx.ReadDataUShort(32U, (ushort)0); - public string Before => ctx.ReadText(0, ""); + public string Before => ctx.ReadText(0, null); public ushort Foo => which == WHICH.Foo ? ctx.ReadDataUShort(0UL, (ushort)0) : default; public ushort Middle => ctx.ReadDataUShort(16UL, (ushort)0); public uint Bar => which == WHICH.Bar ? ctx.ReadDataUInt(64UL, 0U) : default; - public string After => ctx.ReadText(1, ""); + public string After => ctx.ReadText(1, null); } public class WRITER : SerializerState @@ -3350,8 +3350,8 @@ namespace Capnproto_test.Capnp.Test public string Before { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public ushort Foo @@ -3374,8 +3374,8 @@ namespace Capnproto_test.Capnp.Test public string After { - get => this.ReadText(1, ""); - set => this.WriteText(1, value, ""); + get => this.ReadText(1, null); + set => this.WriteText(1, value, null); } } } @@ -3387,7 +3387,7 @@ namespace Capnproto_test.Capnp.Test void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); - Outer = CapnpSerializable.Create(reader.Outer); + Outer = CapnpSerializable.Create(reader.Outer); applyDefaults(); } @@ -3405,7 +3405,7 @@ namespace Capnproto_test.Capnp.Test { } - public Capnproto_test.Capnp.Test.TestUnionInUnion.@outer Outer + public Capnproto_test.Capnp.Test.TestUnionInUnion.outer Outer { get; set; @@ -3422,7 +3422,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public @outer.READER Outer => new @outer.READER(ctx); + public outer.READER Outer => new outer.READER(ctx); } public class WRITER : SerializerState @@ -3432,14 +3432,14 @@ namespace Capnproto_test.Capnp.Test this.SetStruct(2, 0); } - public @outer.WRITER Outer + public outer.WRITER Outer { - get => Rewrap<@outer.WRITER>(); + get => Rewrap(); } } [TypeId(0xd005f6c63707670cUL)] - public class @outer : ICapnpSerializable + public class outer : ICapnpSerializable { public const UInt64 typeId = 0xd005f6c63707670cUL; public enum WHICH : ushort @@ -3455,7 +3455,7 @@ namespace Capnproto_test.Capnp.Test switch (reader.which) { case WHICH.Inner: - Inner = CapnpSerializable.Create(reader.Inner); + Inner = CapnpSerializable.Create(reader.Inner); break; case WHICH.Baz: Baz = reader.Baz; @@ -3510,9 +3510,9 @@ namespace Capnproto_test.Capnp.Test { } - public Capnproto_test.Capnp.Test.TestUnionInUnion.@outer.@inner Inner + public Capnproto_test.Capnp.Test.TestUnionInUnion.outer.inner Inner { - get => _which == WHICH.Inner ? (Capnproto_test.Capnp.Test.TestUnionInUnion.@outer.@inner)_content : null; + get => _which == WHICH.Inner ? (Capnproto_test.Capnp.Test.TestUnionInUnion.outer.inner)_content : null; set { _which = WHICH.Inner; @@ -3542,7 +3542,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public WHICH which => (WHICH)ctx.ReadDataUShort(64U, (ushort)0); - public @inner.READER Inner => which == WHICH.Inner ? new @inner.READER(ctx) : default; + public inner.READER Inner => which == WHICH.Inner ? new inner.READER(ctx) : default; public int Baz => which == WHICH.Baz ? ctx.ReadDataInt(0UL, 0) : default; } @@ -3558,9 +3558,9 @@ namespace Capnproto_test.Capnp.Test set => this.WriteData(64U, (ushort)value, (ushort)0); } - public @inner.WRITER Inner + public inner.WRITER Inner { - get => which == WHICH.Inner ? Rewrap<@inner.WRITER>() : default; + get => which == WHICH.Inner ? Rewrap() : default; } public int Baz @@ -3571,7 +3571,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xff9ce111c6f8e5dbUL)] - public class @inner : ICapnpSerializable + public class inner : ICapnpSerializable { public const UInt64 typeId = 0xff9ce111c6f8e5dbUL; public enum WHICH : ushort @@ -3713,7 +3713,7 @@ namespace Capnproto_test.Capnp.Test void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); - Groups = CapnpSerializable.Create(reader.Groups); + Groups = CapnpSerializable.Create(reader.Groups); applyDefaults(); } @@ -3731,7 +3731,7 @@ namespace Capnproto_test.Capnp.Test { } - public Capnproto_test.Capnp.Test.TestGroups.@groups Groups + public Capnproto_test.Capnp.Test.TestGroups.groups Groups { get; set; @@ -3748,7 +3748,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public @groups.READER Groups => new @groups.READER(ctx); + public groups.READER Groups => new groups.READER(ctx); } public class WRITER : SerializerState @@ -3758,14 +3758,14 @@ namespace Capnproto_test.Capnp.Test this.SetStruct(2, 2); } - public @groups.WRITER Groups + public groups.WRITER Groups { - get => Rewrap<@groups.WRITER>(); + get => Rewrap(); } } [TypeId(0xe22ae74ff9113268UL)] - public class @groups : ICapnpSerializable + public class groups : ICapnpSerializable { public const UInt64 typeId = 0xe22ae74ff9113268UL; public enum WHICH : ushort @@ -3782,13 +3782,13 @@ namespace Capnproto_test.Capnp.Test switch (reader.which) { case WHICH.Foo: - Foo = CapnpSerializable.Create(reader.Foo); + Foo = CapnpSerializable.Create(reader.Foo); break; case WHICH.Baz: - Baz = CapnpSerializable.Create(reader.Baz); + Baz = CapnpSerializable.Create(reader.Baz); break; case WHICH.Bar: - Bar = CapnpSerializable.Create(reader.Bar); + Bar = CapnpSerializable.Create(reader.Bar); break; } @@ -3846,9 +3846,9 @@ namespace Capnproto_test.Capnp.Test { } - public Capnproto_test.Capnp.Test.TestGroups.@groups.@foo Foo + public Capnproto_test.Capnp.Test.TestGroups.groups.foo Foo { - get => _which == WHICH.Foo ? (Capnproto_test.Capnp.Test.TestGroups.@groups.@foo)_content : null; + get => _which == WHICH.Foo ? (Capnproto_test.Capnp.Test.TestGroups.groups.foo)_content : null; set { _which = WHICH.Foo; @@ -3856,9 +3856,9 @@ namespace Capnproto_test.Capnp.Test } } - public Capnproto_test.Capnp.Test.TestGroups.@groups.@baz Baz + public Capnproto_test.Capnp.Test.TestGroups.groups.baz Baz { - get => _which == WHICH.Baz ? (Capnproto_test.Capnp.Test.TestGroups.@groups.@baz)_content : null; + get => _which == WHICH.Baz ? (Capnproto_test.Capnp.Test.TestGroups.groups.baz)_content : null; set { _which = WHICH.Baz; @@ -3866,9 +3866,9 @@ namespace Capnproto_test.Capnp.Test } } - public Capnproto_test.Capnp.Test.TestGroups.@groups.@bar Bar + public Capnproto_test.Capnp.Test.TestGroups.groups.bar Bar { - get => _which == WHICH.Bar ? (Capnproto_test.Capnp.Test.TestGroups.@groups.@bar)_content : null; + get => _which == WHICH.Bar ? (Capnproto_test.Capnp.Test.TestGroups.groups.bar)_content : null; set { _which = WHICH.Bar; @@ -3888,9 +3888,9 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public WHICH which => (WHICH)ctx.ReadDataUShort(32U, (ushort)0); - public @foo.READER Foo => which == WHICH.Foo ? new @foo.READER(ctx) : default; - public @baz.READER Baz => which == WHICH.Baz ? new @baz.READER(ctx) : default; - public @bar.READER Bar => which == WHICH.Bar ? new @bar.READER(ctx) : default; + public foo.READER Foo => which == WHICH.Foo ? new foo.READER(ctx) : default; + public baz.READER Baz => which == WHICH.Baz ? new baz.READER(ctx) : default; + public bar.READER Bar => which == WHICH.Bar ? new bar.READER(ctx) : default; } public class WRITER : SerializerState @@ -3905,24 +3905,24 @@ namespace Capnproto_test.Capnp.Test set => this.WriteData(32U, (ushort)value, (ushort)0); } - public @foo.WRITER Foo + public foo.WRITER Foo { - get => which == WHICH.Foo ? Rewrap<@foo.WRITER>() : default; + get => which == WHICH.Foo ? Rewrap() : default; } - public @baz.WRITER Baz + public baz.WRITER Baz { - get => which == WHICH.Baz ? Rewrap<@baz.WRITER>() : default; + get => which == WHICH.Baz ? Rewrap() : default; } - public @bar.WRITER Bar + public bar.WRITER Bar { - get => which == WHICH.Bar ? Rewrap<@bar.WRITER>() : default; + get => which == WHICH.Bar ? Rewrap() : default; } } [TypeId(0xf5fcba89c0c1196fUL)] - public class @foo : ICapnpSerializable + public class foo : ICapnpSerializable { public const UInt64 typeId = 0xf5fcba89c0c1196fUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -3981,7 +3981,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int Corge => ctx.ReadDataInt(0UL, 0); public long Grault => ctx.ReadDataLong(64UL, 0L); - public string Garply => ctx.ReadText(0, ""); + public string Garply => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -4004,14 +4004,14 @@ namespace Capnproto_test.Capnp.Test public string Garply { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } [TypeId(0xf0fa30304066a4b3UL)] - public class @baz : ICapnpSerializable + public class baz : ICapnpSerializable { public const UInt64 typeId = 0xf0fa30304066a4b3UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -4069,8 +4069,8 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int Corge => ctx.ReadDataInt(0UL, 0); - public string Grault => ctx.ReadText(0, ""); - public string Garply => ctx.ReadText(1, ""); + public string Grault => ctx.ReadText(0, null); + public string Garply => ctx.ReadText(1, null); } public class WRITER : SerializerState @@ -4087,20 +4087,20 @@ namespace Capnproto_test.Capnp.Test public string Grault { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public string Garply { - get => this.ReadText(1, ""); - set => this.WriteText(1, value, ""); + get => this.ReadText(1, null); + set => this.WriteText(1, value, null); } } } [TypeId(0xb727c0d0091a001dUL)] - public class @bar : ICapnpSerializable + public class bar : ICapnpSerializable { public const UInt64 typeId = 0xb727c0d0091a001dUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -4158,7 +4158,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int Corge => ctx.ReadDataInt(0UL, 0); - public string Grault => ctx.ReadText(0, ""); + public string Grault => ctx.ReadText(0, null); public long Garply => ctx.ReadDataLong(64UL, 0L); } @@ -4176,8 +4176,8 @@ namespace Capnproto_test.Capnp.Test public string Grault { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public long Garply @@ -4197,8 +4197,8 @@ namespace Capnproto_test.Capnp.Test void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); - Group1 = CapnpSerializable.Create(reader.Group1); - Group2 = CapnpSerializable.Create(reader.Group2); + Group1 = CapnpSerializable.Create(reader.Group1); + Group2 = CapnpSerializable.Create(reader.Group2); applyDefaults(); } @@ -4217,13 +4217,13 @@ namespace Capnproto_test.Capnp.Test { } - public Capnproto_test.Capnp.Test.TestInterleavedGroups.@group1 Group1 + public Capnproto_test.Capnp.Test.TestInterleavedGroups.group1 Group1 { get; set; } - public Capnproto_test.Capnp.Test.TestInterleavedGroups.@group2 Group2 + public Capnproto_test.Capnp.Test.TestInterleavedGroups.group2 Group2 { get; set; @@ -4240,8 +4240,8 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public @group1.READER Group1 => new @group1.READER(ctx); - public @group2.READER Group2 => new @group2.READER(ctx); + public group1.READER Group1 => new group1.READER(ctx); + public group2.READER Group2 => new group2.READER(ctx); } public class WRITER : SerializerState @@ -4251,19 +4251,19 @@ namespace Capnproto_test.Capnp.Test this.SetStruct(6, 6); } - public @group1.WRITER Group1 + public group1.WRITER Group1 { - get => Rewrap<@group1.WRITER>(); + get => Rewrap(); } - public @group2.WRITER Group2 + public group2.WRITER Group2 { - get => Rewrap<@group2.WRITER>(); + get => Rewrap(); } } [TypeId(0xc7485a3516c7d3c8UL)] - public class @group1 : ICapnpSerializable + public class group1 : ICapnpSerializable { public const UInt64 typeId = 0xc7485a3516c7d3c8UL; public enum WHICH : ushort @@ -4283,7 +4283,7 @@ namespace Capnproto_test.Capnp.Test Qux = reader.Qux; break; case WHICH.Corge: - Corge = CapnpSerializable.Create(reader.Corge); + Corge = CapnpSerializable.Create(reader.Corge); break; case WHICH.Fred: Fred = reader.Fred; @@ -4373,9 +4373,9 @@ namespace Capnproto_test.Capnp.Test } } - public Capnproto_test.Capnp.Test.TestInterleavedGroups.@group1.@corge Corge + public Capnproto_test.Capnp.Test.TestInterleavedGroups.group1.corge Corge { - get => _which == WHICH.Corge ? (Capnproto_test.Capnp.Test.TestInterleavedGroups.@group1.@corge)_content : null; + get => _which == WHICH.Corge ? (Capnproto_test.Capnp.Test.TestInterleavedGroups.group1.corge)_content : null; set { _which = WHICH.Corge; @@ -4414,9 +4414,9 @@ namespace Capnproto_test.Capnp.Test public uint Foo => ctx.ReadDataUInt(0UL, 0U); public ulong Bar => ctx.ReadDataULong(64UL, 0UL); public ushort Qux => which == WHICH.Qux ? ctx.ReadDataUShort(192UL, (ushort)0) : default; - public @corge.READER Corge => which == WHICH.Corge ? new @corge.READER(ctx) : default; - public string Waldo => ctx.ReadText(0, ""); - public string Fred => which == WHICH.Fred ? ctx.ReadText(2, "") : default; + public corge.READER Corge => which == WHICH.Corge ? new corge.READER(ctx) : default; + public string Waldo => ctx.ReadText(0, null); + public string Fred => which == WHICH.Fred ? ctx.ReadText(2, null) : default; } public class WRITER : SerializerState @@ -4449,26 +4449,26 @@ namespace Capnproto_test.Capnp.Test set => this.WriteData(192UL, value, (ushort)0); } - public @corge.WRITER Corge + public corge.WRITER Corge { - get => which == WHICH.Corge ? Rewrap<@corge.WRITER>() : default; + get => which == WHICH.Corge ? Rewrap() : default; } public string Waldo { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public string Fred { - get => which == WHICH.Fred ? this.ReadText(2, "") : default; - set => this.WriteText(2, value, ""); + get => which == WHICH.Fred ? this.ReadText(2, null) : default; + set => this.WriteText(2, value, null); } } [TypeId(0xdb0afd413f4a313aUL)] - public class @corge : ICapnpSerializable + public class corge : ICapnpSerializable { public const UInt64 typeId = 0xdb0afd413f4a313aUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -4535,8 +4535,8 @@ namespace Capnproto_test.Capnp.Test public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public ulong Grault => ctx.ReadDataULong(256UL, 0UL); public ushort Garply => ctx.ReadDataUShort(192UL, (ushort)0); - public string Plugh => ctx.ReadText(2, ""); - public string Xyzzy => ctx.ReadText(4, ""); + public string Plugh => ctx.ReadText(2, null); + public string Xyzzy => ctx.ReadText(4, null); } public class WRITER : SerializerState @@ -4559,21 +4559,21 @@ namespace Capnproto_test.Capnp.Test public string Plugh { - get => this.ReadText(2, ""); - set => this.WriteText(2, value, ""); + get => this.ReadText(2, null); + set => this.WriteText(2, value, null); } public string Xyzzy { - get => this.ReadText(4, ""); - set => this.WriteText(4, value, ""); + get => this.ReadText(4, null); + set => this.WriteText(4, value, null); } } } } [TypeId(0xcc85a335569990e9UL)] - public class @group2 : ICapnpSerializable + public class group2 : ICapnpSerializable { public const UInt64 typeId = 0xcc85a335569990e9UL; public enum WHICH : ushort @@ -4593,7 +4593,7 @@ namespace Capnproto_test.Capnp.Test Qux = reader.Qux; break; case WHICH.Corge: - Corge = CapnpSerializable.Create(reader.Corge); + Corge = CapnpSerializable.Create(reader.Corge); break; case WHICH.Fred: Fred = reader.Fred; @@ -4683,9 +4683,9 @@ namespace Capnproto_test.Capnp.Test } } - public Capnproto_test.Capnp.Test.TestInterleavedGroups.@group2.@corge Corge + public Capnproto_test.Capnp.Test.TestInterleavedGroups.group2.corge Corge { - get => _which == WHICH.Corge ? (Capnproto_test.Capnp.Test.TestInterleavedGroups.@group2.@corge)_content : null; + get => _which == WHICH.Corge ? (Capnproto_test.Capnp.Test.TestInterleavedGroups.group2.corge)_content : null; set { _which = WHICH.Corge; @@ -4724,9 +4724,9 @@ namespace Capnproto_test.Capnp.Test public uint Foo => ctx.ReadDataUInt(32UL, 0U); public ulong Bar => ctx.ReadDataULong(128UL, 0UL); public ushort Qux => which == WHICH.Qux ? ctx.ReadDataUShort(208UL, (ushort)0) : default; - public @corge.READER Corge => which == WHICH.Corge ? new @corge.READER(ctx) : default; - public string Waldo => ctx.ReadText(1, ""); - public string Fred => which == WHICH.Fred ? ctx.ReadText(3, "") : default; + public corge.READER Corge => which == WHICH.Corge ? new corge.READER(ctx) : default; + public string Waldo => ctx.ReadText(1, null); + public string Fred => which == WHICH.Fred ? ctx.ReadText(3, null) : default; } public class WRITER : SerializerState @@ -4759,26 +4759,26 @@ namespace Capnproto_test.Capnp.Test set => this.WriteData(208UL, value, (ushort)0); } - public @corge.WRITER Corge + public corge.WRITER Corge { - get => which == WHICH.Corge ? Rewrap<@corge.WRITER>() : default; + get => which == WHICH.Corge ? Rewrap() : default; } public string Waldo { - get => this.ReadText(1, ""); - set => this.WriteText(1, value, ""); + get => this.ReadText(1, null); + set => this.WriteText(1, value, null); } public string Fred { - get => which == WHICH.Fred ? this.ReadText(3, "") : default; - set => this.WriteText(3, value, ""); + get => which == WHICH.Fred ? this.ReadText(3, null) : default; + set => this.WriteText(3, value, null); } } [TypeId(0xa017f0366827ee37UL)] - public class @corge : ICapnpSerializable + public class corge : ICapnpSerializable { public const UInt64 typeId = 0xa017f0366827ee37UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -4845,8 +4845,8 @@ namespace Capnproto_test.Capnp.Test public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public ulong Grault => ctx.ReadDataULong(320UL, 0UL); public ushort Garply => ctx.ReadDataUShort(208UL, (ushort)0); - public string Plugh => ctx.ReadText(3, ""); - public string Xyzzy => ctx.ReadText(5, ""); + public string Plugh => ctx.ReadText(3, null); + public string Xyzzy => ctx.ReadText(5, null); } public class WRITER : SerializerState @@ -4869,14 +4869,14 @@ namespace Capnproto_test.Capnp.Test public string Plugh { - get => this.ReadText(3, ""); - set => this.WriteText(3, value, ""); + get => this.ReadText(3, null); + set => this.WriteText(3, value, null); } public string Xyzzy { - get => this.ReadText(5, ""); - set => this.WriteText(5, value, ""); + get => this.ReadText(5, null); + set => this.WriteText(5, value, null); } } } @@ -4914,13 +4914,13 @@ namespace Capnproto_test.Capnp.Test { S16s8s64s8Set = S16s8s64s8Set ?? new Capnproto_test.Capnp.Test.TestUnion() { - Union0 = new Capnproto_test.Capnp.Test.TestUnion.@union0() + Union0 = new Capnproto_test.Capnp.Test.TestUnion.union0() { }, - Union1 = new Capnproto_test.Capnp.Test.TestUnion.@union1() + Union1 = new Capnproto_test.Capnp.Test.TestUnion.union1() { }, - Union2 = new Capnproto_test.Capnp.Test.TestUnion.@union2() + Union2 = new Capnproto_test.Capnp.Test.TestUnion.union2() { }, - Union3 = new Capnproto_test.Capnp.Test.TestUnion.@union3() + Union3 = new Capnproto_test.Capnp.Test.TestUnion.union3() { }, Bit0 = false, Bit2 = false, @@ -4933,13 +4933,13 @@ namespace Capnproto_test.Capnp.Test }; S0sps1s32Set = S0sps1s32Set ?? new Capnproto_test.Capnp.Test.TestUnion() { - Union0 = new Capnproto_test.Capnp.Test.TestUnion.@union0() + Union0 = new Capnproto_test.Capnp.Test.TestUnion.union0() { }, - Union1 = new Capnproto_test.Capnp.Test.TestUnion.@union1() + Union1 = new Capnproto_test.Capnp.Test.TestUnion.union1() { }, - Union2 = new Capnproto_test.Capnp.Test.TestUnion.@union2() + Union2 = new Capnproto_test.Capnp.Test.TestUnion.union2() { }, - Union3 = new Capnproto_test.Capnp.Test.TestUnion.@union3() + Union3 = new Capnproto_test.Capnp.Test.TestUnion.union3() { }, Bit0 = false, Bit2 = false, @@ -5298,16 +5298,16 @@ namespace Capnproto_test.Capnp.Test void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); - List0 = reader.List0.ToReadOnlyList(_ => CapnpSerializable.Create(_)); - List1 = reader.List1.ToReadOnlyList(_ => CapnpSerializable.Create(_)); - List8 = reader.List8.ToReadOnlyList(_ => CapnpSerializable.Create(_)); - List16 = reader.List16.ToReadOnlyList(_ => CapnpSerializable.Create(_)); - List32 = reader.List32.ToReadOnlyList(_ => CapnpSerializable.Create(_)); - List64 = reader.List64.ToReadOnlyList(_ => CapnpSerializable.Create(_)); - ListP = reader.ListP.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + List0 = reader.List0?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + List1 = reader.List1?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + List8 = reader.List8?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + List16 = reader.List16?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + List32 = reader.List32?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + List64 = reader.List64?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + ListP = reader.ListP?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); Int32ListList = reader.Int32ListList; TextListList = reader.TextListList; - StructListList = reader.StructListList.ToReadOnlyList(_2 => _2.ToReadOnlyList(_ => CapnpSerializable.Create(_))); + StructListList = reader.StructListList?.ToReadOnlyList(_2 => _2?.ToReadOnlyList(_ => CapnpSerializable.Create(_))); applyDefaults(); } @@ -5872,7 +5872,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string F => ctx.ReadText(0, ""); + public string F => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -5884,8 +5884,8 @@ namespace Capnproto_test.Capnp.Test public string F { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -5932,7 +5932,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -5944,8 +5944,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -6001,7 +6001,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public bool F => ctx.ReadDataBool(0UL, false); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -6019,8 +6019,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -6076,7 +6076,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public byte F => ctx.ReadDataByte(0UL, (byte)0); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -6094,8 +6094,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -6151,7 +6151,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public ushort F => ctx.ReadDataUShort(0UL, (ushort)0); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -6169,8 +6169,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -6226,7 +6226,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public uint F => ctx.ReadDataUInt(0UL, 0U); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -6244,8 +6244,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -6301,7 +6301,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public ulong F => ctx.ReadDataULong(0UL, 0UL); - public string Pad => ctx.ReadText(0, ""); + public string Pad => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -6319,8 +6319,8 @@ namespace Capnproto_test.Capnp.Test public string Pad { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -6375,7 +6375,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string F => ctx.ReadText(0, ""); + public string F => ctx.ReadText(0, null); public ulong Pad => ctx.ReadDataULong(0UL, 0UL); } @@ -6388,8 +6388,8 @@ namespace Capnproto_test.Capnp.Test public string F { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public ulong Pad @@ -6598,8 +6598,8 @@ namespace Capnproto_test.Capnp.Test Foo = reader.Foo; Bar = reader.Bar; Baz = reader.Baz; - TheUnion = CapnpSerializable.Create(reader.TheUnion); - AnotherUnion = CapnpSerializable.Create(reader.AnotherUnion); + TheUnion = CapnpSerializable.Create(reader.TheUnion); + AnotherUnion = CapnpSerializable.Create(reader.AnotherUnion); applyDefaults(); } @@ -6639,13 +6639,13 @@ namespace Capnproto_test.Capnp.Test set; } - public Capnproto_test.Capnp.Test.TestLateUnion.@theUnion TheUnion + public Capnproto_test.Capnp.Test.TestLateUnion.theUnion TheUnion { get; set; } - public Capnproto_test.Capnp.Test.TestLateUnion.@anotherUnion AnotherUnion + public Capnproto_test.Capnp.Test.TestLateUnion.anotherUnion AnotherUnion { get; set; @@ -6663,10 +6663,10 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int Foo => ctx.ReadDataInt(0UL, 0); - public string Bar => ctx.ReadText(0, ""); + public string Bar => ctx.ReadText(0, null); public short Baz => ctx.ReadDataShort(32UL, (short)0); - public @theUnion.READER TheUnion => new @theUnion.READER(ctx); - public @anotherUnion.READER AnotherUnion => new @anotherUnion.READER(ctx); + public theUnion.READER TheUnion => new theUnion.READER(ctx); + public anotherUnion.READER AnotherUnion => new anotherUnion.READER(ctx); } public class WRITER : SerializerState @@ -6684,8 +6684,8 @@ namespace Capnproto_test.Capnp.Test public string Bar { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public short Baz @@ -6694,19 +6694,19 @@ namespace Capnproto_test.Capnp.Test set => this.WriteData(32UL, value, (short)0); } - public @theUnion.WRITER TheUnion + public theUnion.WRITER TheUnion { - get => Rewrap<@theUnion.WRITER>(); + get => Rewrap(); } - public @anotherUnion.WRITER AnotherUnion + public anotherUnion.WRITER AnotherUnion { - get => Rewrap<@anotherUnion.WRITER>(); + get => Rewrap(); } } [TypeId(0x807280a2901aa079UL)] - public class @theUnion : ICapnpSerializable + public class theUnion : ICapnpSerializable { public const UInt64 typeId = 0x807280a2901aa079UL; public enum WHICH : ushort @@ -6829,7 +6829,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public WHICH which => (WHICH)ctx.ReadDataUShort(48U, (ushort)0); - public string Qux => which == WHICH.Qux ? ctx.ReadText(1, "") : default; + public string Qux => which == WHICH.Qux ? ctx.ReadText(1, null) : default; public IReadOnlyList Corge => which == WHICH.Corge ? ctx.ReadList(1).CastInt() : default; public float Grault => which == WHICH.Grault ? ctx.ReadDataFloat(64UL, 0F) : default; } @@ -6848,8 +6848,8 @@ namespace Capnproto_test.Capnp.Test public string Qux { - get => which == WHICH.Qux ? this.ReadText(1, "") : default; - set => this.WriteText(1, value, ""); + get => which == WHICH.Qux ? this.ReadText(1, null) : default; + set => this.WriteText(1, value, null); } public ListOfPrimitivesSerializer Corge @@ -6867,7 +6867,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xc1973984dee98e3aUL)] - public class @anotherUnion : ICapnpSerializable + public class anotherUnion : ICapnpSerializable { public const UInt64 typeId = 0xc1973984dee98e3aUL; public enum WHICH : ushort @@ -6990,7 +6990,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public WHICH which => (WHICH)ctx.ReadDataUShort(96U, (ushort)0); - public string Qux => which == WHICH.Qux ? ctx.ReadText(2, "") : default; + public string Qux => which == WHICH.Qux ? ctx.ReadText(2, null) : default; public IReadOnlyList Corge => which == WHICH.Corge ? ctx.ReadList(2).CastInt() : default; public float Grault => which == WHICH.Grault ? ctx.ReadDataFloat(128UL, 0F) : default; } @@ -7009,8 +7009,8 @@ namespace Capnproto_test.Capnp.Test public string Qux { - get => which == WHICH.Qux ? this.ReadText(2, "") : default; - set => this.WriteText(2, value, ""); + get => which == WHICH.Qux ? this.ReadText(2, null) : default; + set => this.WriteText(2, value, null); } public ListOfPrimitivesSerializer Corge @@ -7087,7 +7087,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public long Old1 => ctx.ReadDataLong(0UL, 0L); - public string Old2 => ctx.ReadText(0, ""); + public string Old2 => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.TestOldVersion.READER Old3 => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestOldVersion.READER.create); } @@ -7106,8 +7106,8 @@ namespace Capnproto_test.Capnp.Test public string Old2 { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.TestOldVersion.WRITER Old3 @@ -7195,7 +7195,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public long Old1 => ctx.ReadDataLong(0UL, 0L); - public string Old2 => ctx.ReadText(0, ""); + public string Old2 => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.TestNewVersion.READER Old3 => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestNewVersion.READER.create); public long New1 => ctx.ReadDataLong(64UL, 987L); public string New2 => ctx.ReadText(2, "baz"); @@ -7216,8 +7216,8 @@ namespace Capnproto_test.Capnp.Test public string Old2 { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.TestNewVersion.WRITER Old3 @@ -7373,7 +7373,7 @@ namespace Capnproto_test.Capnp.Test switch (reader.which) { case WHICH.A: - A = CapnpSerializable.Create(reader.A); + A = CapnpSerializable.Create(reader.A); break; case WHICH.B: B = reader.B; @@ -7428,9 +7428,9 @@ namespace Capnproto_test.Capnp.Test { } - public Capnproto_test.Capnp.Test.TestNewUnionVersion.@a A + public Capnproto_test.Capnp.Test.TestNewUnionVersion.a A { - get => _which == WHICH.A ? (Capnproto_test.Capnp.Test.TestNewUnionVersion.@a)_content : null; + get => _which == WHICH.A ? (Capnproto_test.Capnp.Test.TestNewUnionVersion.a)_content : null; set { _which = WHICH.A; @@ -7460,7 +7460,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public WHICH which => (WHICH)ctx.ReadDataUShort(0U, (ushort)0); - public @a.READER A => which == WHICH.A ? new @a.READER(ctx) : default; + public a.READER A => which == WHICH.A ? new a.READER(ctx) : default; public ulong B => which == WHICH.B ? ctx.ReadDataULong(64UL, 0UL) : default; } @@ -7477,9 +7477,9 @@ namespace Capnproto_test.Capnp.Test set => this.WriteData(0U, (ushort)value, (ushort)0); } - public @a.WRITER A + public a.WRITER A { - get => which == WHICH.A ? Rewrap<@a.WRITER>() : default; + get => which == WHICH.A ? Rewrap() : default; } public ulong B @@ -7490,7 +7490,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x86232c1de4513e84UL)] - public class @a : ICapnpSerializable + public class a : ICapnpSerializable { public const UInt64 typeId = 0x86232c1de4513e84UL; public enum WHICH : ushort @@ -7612,7 +7612,7 @@ namespace Capnproto_test.Capnp.Test void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); - Un = CapnpSerializable.Create(reader.Un); + Un = CapnpSerializable.Create(reader.Un); applyDefaults(); } @@ -7630,7 +7630,7 @@ namespace Capnproto_test.Capnp.Test { } - public Capnproto_test.Capnp.Test.TestStructUnion.@un Un + public Capnproto_test.Capnp.Test.TestStructUnion.un Un { get; set; @@ -7647,7 +7647,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public @un.READER Un => new @un.READER(ctx); + public un.READER Un => new un.READER(ctx); } public class WRITER : SerializerState @@ -7657,14 +7657,14 @@ namespace Capnproto_test.Capnp.Test this.SetStruct(1, 1); } - public @un.WRITER Un + public un.WRITER Un { - get => Rewrap<@un.WRITER>(); + get => Rewrap(); } } [TypeId(0x992edc677bef5a3cUL)] - public class @un : ICapnpSerializable + public class un : ICapnpSerializable { public const UInt64 typeId = 0x992edc677bef5a3cUL; public enum WHICH : ushort @@ -7847,8 +7847,8 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string SomeText => ctx.ReadText(0, ""); - public string MoreText => ctx.ReadText(1, ""); + public string SomeText => ctx.ReadText(0, null); + public string MoreText => ctx.ReadText(1, null); } public class WRITER : SerializerState @@ -7860,14 +7860,14 @@ namespace Capnproto_test.Capnp.Test public string SomeText { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public string MoreText { - get => this.ReadText(1, ""); - set => this.WriteText(1, value, ""); + get => this.ReadText(1, null); + set => this.WriteText(1, value, null); } } } @@ -7881,7 +7881,7 @@ namespace Capnproto_test.Capnp.Test { var reader = READER.create(arg_); SomeText = reader.SomeText; - StructList = reader.StructList.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + StructList = reader.StructList?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); applyDefaults(); } @@ -7923,7 +7923,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string SomeText => ctx.ReadText(0, ""); + public string SomeText => ctx.ReadText(0, null); public IReadOnlyList StructList => ctx.ReadList(1).Cast(Capnproto_test.Capnp.Test.TestPrintInlineStructs.InlineStruct.READER.create); } @@ -7936,8 +7936,8 @@ namespace Capnproto_test.Capnp.Test public string SomeText { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public ListOfStructsSerializer StructList @@ -7998,7 +7998,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int Int32Field => ctx.ReadDataInt(0UL, 0); - public string TextField => ctx.ReadText(0, ""); + public string TextField => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -8016,8 +8016,8 @@ namespace Capnproto_test.Capnp.Test public string TextField { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -8120,13 +8120,13 @@ namespace Capnproto_test.Capnp.Test which = reader.which; break; case WHICH.Ug: - Ug = CapnpSerializable.Create.@ug>(reader.Ug); + Ug = CapnpSerializable.Create.ug>(reader.Ug); break; } Foo = CapnpSerializable.Create(reader.Foo); Rev = CapnpSerializable.Create>(reader.Rev); - List = reader.List.ToReadOnlyList(_ => CapnpSerializable.Create.Inner>(_)); + List = reader.List?.ToReadOnlyList(_ => CapnpSerializable.Create.Inner>(_)); applyDefaults(); } @@ -8189,9 +8189,9 @@ namespace Capnproto_test.Capnp.Test set; } - public Capnproto_test.Capnp.Test.TestGenerics.@ug Ug + public Capnproto_test.Capnp.Test.TestGenerics.ug Ug { - get => _which == WHICH.Ug ? (Capnproto_test.Capnp.Test.TestGenerics.@ug)_content : null; + get => _which == WHICH.Ug ? (Capnproto_test.Capnp.Test.TestGenerics.ug)_content : null; set { _which = WHICH.Ug; @@ -8219,7 +8219,7 @@ namespace Capnproto_test.Capnp.Test public WHICH which => (WHICH)ctx.ReadDataUShort(0U, (ushort)0); public DeserializerState Foo => ctx.StructReadPointer(0); public Capnproto_test.Capnp.Test.TestGenerics.READER Rev => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestGenerics.READER.create); - public @ug.READER Ug => which == WHICH.Ug ? new @ug.READER(ctx) : default; + public ug.READER Ug => which == WHICH.Ug ? new ug.READER(ctx) : default; public IReadOnlyList.Inner.READER> List => ctx.ReadList(2).Cast(Capnproto_test.Capnp.Test.TestGenerics.Inner.READER.create); } @@ -8248,9 +8248,9 @@ namespace Capnproto_test.Capnp.Test set => Link(1, value); } - public @ug.WRITER Ug + public ug.WRITER Ug { - get => which == WHICH.Ug ? Rewrap<@ug.WRITER>() : default; + get => which == WHICH.Ug ? Rewrap() : default; } public ListOfStructsSerializer.Inner.WRITER> List @@ -8261,7 +8261,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xb46a779beaf3384eUL)] - public class @ug : ICapnpSerializable + public class ug : ICapnpSerializable { public const UInt64 typeId = 0xb46a779beaf3384eUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -8612,13 +8612,15 @@ namespace Capnproto_test.Capnp.Test { public async Task Call(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc.Inner2.DeepNest.DeepNestInterface.Params_call.WRITER>(); - var arg_ = new Capnproto_test.Capnp.Test.TestGenerics.Inner2.DeepNest.DeepNestInterface.Params_call() + var in_ = SerializerState.CreateForRpc.Inner2.DeepNest.DeepNestInterface.Params_Call.WRITER>(); + var arg_ = new Capnproto_test.Capnp.Test.TestGenerics.Inner2.DeepNest.DeepNestInterface.Params_Call() { }; - arg_.serialize(in_); - var d_ = await Call(9816138025992274567UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create.Inner2.DeepNest.DeepNestInterface.Result_call>(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(9816138025992274567UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create.Inner2.DeepNest.DeepNestInterface.Result_Call>(d_); + return; + } } } @@ -8632,9 +8634,12 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 9816138025992274567UL; async Task Call(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Call(cancellationToken_); - var s_ = SerializerState.CreateForRpc.Inner2.DeepNest.DeepNestInterface.Result_call.WRITER>(); - return s_; + using (d_) + { + await Impl.Call(cancellationToken_); + var s_ = SerializerState.CreateForRpc.Inner2.DeepNest.DeepNestInterface.Result_Call.WRITER>(); + return s_; + } } } @@ -8642,7 +8647,7 @@ namespace Capnproto_test.Capnp.Test where TQuux : class { [TypeId(0xb84eecc799437049UL)] - public class Params_call : ICapnpSerializable + public class Params_Call : ICapnpSerializable { public const UInt64 typeId = 0xb84eecc799437049UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -8687,7 +8692,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xe080f0fc54614f6fUL)] - public class Result_call : ICapnpSerializable + public class Result_Call : ICapnpSerializable { public const UInt64 typeId = 0xe080f0fc54614f6fUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -8745,11 +8750,14 @@ namespace Capnproto_test.Capnp.Test public Task<(TQux, Capnproto_test.Capnp.Test.TestGenerics)> Call(Capnproto_test.Capnp.Test.TestGenerics.Inner2 arg_, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc.Inner2.WRITER>(); - arg_.serialize(in_); + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(14548678385738242652UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create.Interface.Result_call>(d_); - return (r_.Qux, r_.Gen); + using (d_) + { + var r_ = CapnpSerializable.Create.Interface.Result_Call>(d_); + return (r_.Qux, r_.Gen); + } } ); @@ -8766,15 +8774,18 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 14548678385738242652UL; Task Call(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.Call(CapnpSerializable.Create.Inner2>(d_), cancellationToken_), (qux, gen) => + using (d_) { - var s_ = SerializerState.CreateForRpc.Interface.Result_call.WRITER>(); - var r_ = new Capnproto_test.Capnp.Test.TestGenerics.Interface.Result_call { Qux = qux, Gen = gen }; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.Call(CapnpSerializable.Create.Inner2>(d_), cancellationToken_), (qux, gen) => + { + var s_ = SerializerState.CreateForRpc.Interface.Result_Call.WRITER>(); + var r_ = new Capnproto_test.Capnp.Test.TestGenerics.Interface.Result_Call { Qux = qux, Gen = gen }; + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -8782,7 +8793,7 @@ namespace Capnproto_test.Capnp.Test where TQux : class { [TypeId(0xa5b46224e33581adUL)] - public class Result_call : ICapnpSerializable + public class Result_Call : ICapnpSerializable { public const UInt64 typeId = 0xa5b46224e33581adUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -9116,23 +9127,26 @@ namespace Capnproto_test.Capnp.Test [TypeId(0x8b9717a3f8d85a9aUL), Proxy(typeof(TestImplicitMethodParams_Proxy)), Skeleton(typeof(TestImplicitMethodParams_Skeleton))] public interface ITestImplicitMethodParams : IDisposable { - Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) + Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class; } public class TestImplicitMethodParams_Proxy : Proxy, ITestImplicitMethodParams { - public Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) + public Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class { - var in_ = SerializerState.CreateForRpc.WRITER>(); - var arg_ = new Capnproto_test.Capnp.Test.TestImplicitMethodParams.Params_call() - { Foo = foo, Bar = bar }; - arg_.serialize(in_); + var in_ = SerializerState.CreateForRpc.WRITER>(); + var arg_ = new Capnproto_test.Capnp.Test.TestImplicitMethodParams.Params_Call() + { Foo = Foo, Bar = Bar }; + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(10058534285777328794UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create>(d_); - return r_; + using (d_) + { + var r_ = CapnpSerializable.Create>(d_); + return r_; + } } ); @@ -9150,22 +9164,25 @@ namespace Capnproto_test.Capnp.Test Task Call(DeserializerState d_, CancellationToken cancellationToken_) where TT : class where TU : class { - var in_ = CapnpSerializable.Create>(d_); - return Impatient.MaybeTailCall(Impl.Call(in_.Foo, in_.Bar, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc.WRITER>(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create>(d_); + return Impatient.MaybeTailCall(Impl.Call(in_.Foo, in_.Bar, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc.WRITER>(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } public static class TestImplicitMethodParams { [TypeId(0xf83f8caf54bdc486UL)] - public class Params_call : ICapnpSerializable where TT : class where TU : class + public class Params_Call : ICapnpSerializable where TT : class where TU : class { public const UInt64 typeId = 0xf83f8caf54bdc486UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -9243,23 +9260,26 @@ namespace Capnproto_test.Capnp.Test [TypeId(0xdf9ccdeb81a704c9UL), Proxy(typeof(TestImplicitMethodParamsInGeneric_Proxy<>)), Skeleton(typeof(TestImplicitMethodParamsInGeneric_Skeleton<>))] public interface ITestImplicitMethodParamsInGeneric : IDisposable where TV : class { - Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) + Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class; } public class TestImplicitMethodParamsInGeneric_Proxy : Proxy, ITestImplicitMethodParamsInGeneric where TV : class { - public Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) + public Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class { - var in_ = SerializerState.CreateForRpc.Params_call.WRITER>(); - var arg_ = new Capnproto_test.Capnp.Test.TestImplicitMethodParamsInGeneric.Params_call() - { Foo = foo, Bar = bar }; - arg_.serialize(in_); + var in_ = SerializerState.CreateForRpc.Params_Call.WRITER>(); + var arg_ = new Capnproto_test.Capnp.Test.TestImplicitMethodParamsInGeneric.Params_Call() + { Foo = Foo, Bar = Bar }; + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(16112979978201007305UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create>(d_); - return r_; + using (d_) + { + var r_ = CapnpSerializable.Create>(d_); + return r_; + } } ); @@ -9277,15 +9297,18 @@ namespace Capnproto_test.Capnp.Test Task Call(DeserializerState d_, CancellationToken cancellationToken_) where TT : class where TU : class { - var in_ = CapnpSerializable.Create.Params_call>(d_); - return Impatient.MaybeTailCall(Impl.Call(in_.Foo, in_.Bar, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc.WRITER>(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create.Params_Call>(d_); + return Impatient.MaybeTailCall(Impl.Call(in_.Foo, in_.Bar, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc.WRITER>(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -9293,7 +9316,7 @@ namespace Capnproto_test.Capnp.Test where TV : class { [TypeId(0x9aab8e25c808d71eUL)] - public class Params_call : ICapnpSerializable where TT : class where TU : class + public class Params_Call : ICapnpSerializable where TT : class where TU : class { public const UInt64 typeId = 0x9aab8e25c808d71eUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -10702,7 +10725,7 @@ namespace Capnproto_test.Capnp.Test AnyKindAsStruct = CapnpSerializable.Create(reader.AnyKindAsStruct); AnyStructAsStruct = CapnpSerializable.Create(reader.AnyStructAsStruct); AnyKindAsList = CapnpSerializable.Create(reader.AnyKindAsList); - AnyListAsList = reader.AnyListAsList.ToReadOnlyList(_ => (object)_); + AnyListAsList = reader.AnyListAsList?.ToReadOnlyList(_ => (object)_); applyDefaults(); } @@ -10800,44 +10823,50 @@ namespace Capnproto_test.Capnp.Test [TypeId(0x88eb12a0e0af92b2UL), Proxy(typeof(TestInterface_Proxy)), Skeleton(typeof(TestInterface_Skeleton))] public interface ITestInterface : IDisposable { - Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default); + Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default); Task Bar(CancellationToken cancellationToken_ = default); - Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default); + Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default); } public class TestInterface_Proxy : Proxy, ITestInterface { - public async Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default) + public async Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_foo() - { I = i, J = j }; - arg_.serialize(in_); - var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.X); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() + { I = I, J = J }; + arg_?.serialize(in_); + using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.X); + } } public async Task Bar(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_bar() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Bar() { }; - arg_.serialize(in_); - var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } - public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default) + public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_baz() - { S = s }; - arg_.serialize(in_); - var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() + { S = S }; + arg_?.serialize(in_); + using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -10851,38 +10880,47 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 9865999890858873522UL; Task Foo(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.J, cancellationToken_), x => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestInterface.Result_foo { X = x }; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.J, cancellationToken_), x => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestInterface.Result_Foo { X = x }; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task Bar(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Bar(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Bar(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } async Task Baz(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.Baz(in_.S, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.Baz(in_.S, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } } public static class TestInterface { [TypeId(0xb874edc0d559b391UL)] - public class Params_foo : ICapnpSerializable + public class Params_Foo : ICapnpSerializable { public const UInt64 typeId = 0xb874edc0d559b391UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -10957,7 +10995,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xb04fcaddab714ba4UL)] - public class Result_foo : ICapnpSerializable + public class Result_Foo : ICapnpSerializable { public const UInt64 typeId = 0xb04fcaddab714ba4UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -10998,7 +11036,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string X => ctx.ReadText(0, ""); + public string X => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -11010,14 +11048,14 @@ namespace Capnproto_test.Capnp.Test public string X { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } [TypeId(0xd044893357b42568UL)] - public class Params_bar : ICapnpSerializable + public class Params_Bar : ICapnpSerializable { public const UInt64 typeId = 0xd044893357b42568UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -11062,7 +11100,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x9bf141df4247d52fUL)] - public class Result_bar : ICapnpSerializable + public class Result_Bar : ICapnpSerializable { public const UInt64 typeId = 0x9bf141df4247d52fUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -11107,7 +11145,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xd9ac8abb2a91cfbcUL)] - public class Params_baz : ICapnpSerializable + public class Params_Baz : ICapnpSerializable { public const UInt64 typeId = 0xd9ac8abb2a91cfbcUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -11167,7 +11205,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x9b99d14f2f375b2dUL)] - public class Result_baz : ICapnpSerializable + public class Result_Baz : ICapnpSerializable { public const UInt64 typeId = 0x9b99d14f2f375b2dUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -11224,66 +11262,78 @@ namespace Capnproto_test.Capnp.Test { public async Task Qux(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_qux() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_Qux() { }; - arg_.serialize(in_); - var d_ = await Call(16494920484927878984UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(16494920484927878984UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Corge(Capnproto_test.Capnp.Test.TestAllTypes arg_, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); - arg_.serialize(in_); - var d_ = await Call(16494920484927878984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(16494920484927878984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Grault(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_grault() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_Grault() { }; - arg_.serialize(in_); - var d_ = await Call(16494920484927878984UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + arg_?.serialize(in_); + using (var d_ = await Call(16494920484927878984UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } - public async Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default) + public async Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_foo() - { I = i, J = j }; - arg_.serialize(in_); - var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.X); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() + { I = I, J = J }; + arg_?.serialize(in_); + using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.X); + } } public async Task Bar(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_bar() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Bar() { }; - arg_.serialize(in_); - var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } - public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default) + public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_baz() - { S = s }; - arg_.serialize(in_); - var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() + { S = S }; + arg_?.serialize(in_); + using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -11297,35 +11347,44 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 16494920484927878984UL; async Task Qux(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Qux(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Qux(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } async Task Corge(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Corge(CapnpSerializable.Create(d_), cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Corge(CapnpSerializable.Create(d_), cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } Task Grault(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.Grault(cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.Grault(cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } public static class TestExtends { [TypeId(0x83a4bc5471363f17UL)] - public class Params_qux : ICapnpSerializable + public class Params_Qux : ICapnpSerializable { public const UInt64 typeId = 0x83a4bc5471363f17UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -11370,7 +11429,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x8e4b3d1a3e2753ddUL)] - public class Result_qux : ICapnpSerializable + public class Result_Qux : ICapnpSerializable { public const UInt64 typeId = 0x8e4b3d1a3e2753ddUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -11415,7 +11474,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xacf67532a7e7bad9UL)] - public class Result_corge : ICapnpSerializable + public class Result_Corge : ICapnpSerializable { public const UInt64 typeId = 0xacf67532a7e7bad9UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -11460,7 +11519,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xf3b834e851ea8af6UL)] - public class Params_grault : ICapnpSerializable + public class Params_Grault : ICapnpSerializable { public const UInt64 typeId = 0xf3b834e851ea8af6UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -11514,66 +11573,78 @@ namespace Capnproto_test.Capnp.Test { public async Task Qux(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_qux() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_Qux() { }; - arg_.serialize(in_); - var d_ = await Call(16494920484927878984UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(16494920484927878984UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Corge(Capnproto_test.Capnp.Test.TestAllTypes arg_, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); - arg_.serialize(in_); - var d_ = await Call(16494920484927878984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(16494920484927878984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Grault(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_grault() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_Grault() { }; - arg_.serialize(in_); - var d_ = await Call(16494920484927878984UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + arg_?.serialize(in_); + using (var d_ = await Call(16494920484927878984UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } - public async Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default) + public async Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_foo() - { I = i, J = j }; - arg_.serialize(in_); - var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.X); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() + { I = I, J = J }; + arg_?.serialize(in_); + using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.X); + } } public async Task Bar(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_bar() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Bar() { }; - arg_.serialize(in_); - var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } - public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default) + public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_baz() - { S = s }; - arg_.serialize(in_); - var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() + { S = S }; + arg_?.serialize(in_); + using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -11590,49 +11661,57 @@ namespace Capnproto_test.Capnp.Test [TypeId(0xa5a404caa61d4cd0UL), Proxy(typeof(TestPipeline_Proxy)), Skeleton(typeof(TestPipeline_Skeleton))] public interface ITestPipeline : IDisposable { - Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint n, Capnproto_test.Capnp.Test.ITestInterface inCap, CancellationToken cancellationToken_ = default); - Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_ = default); - Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint n, BareProxy inCap, CancellationToken cancellationToken_ = default); + Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint N, Capnproto_test.Capnp.Test.ITestInterface InCap, CancellationToken cancellationToken_ = default); + Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface Cap, object Obj, IReadOnlyList List, CancellationToken cancellationToken_ = default); + Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint N, BareProxy InCap, CancellationToken cancellationToken_ = default); } public class TestPipeline_Proxy : Proxy, ITestPipeline { - public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint n, Capnproto_test.Capnp.Test.ITestInterface inCap, CancellationToken cancellationToken_ = default) + public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint N, Capnproto_test.Capnp.Test.ITestInterface InCap, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_getCap() - { N = n, InCap = inCap }; - arg_.serialize(in_); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_GetCap() + { N = N, InCap = InCap }; + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(11935670180855499984UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.S, r_.OutBox); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.S, r_.OutBox); + } } ); } - public async Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_ = default) + public async Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface Cap, object Obj, IReadOnlyList List, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_testPointers() - { Cap = cap, Obj = obj, List = list }; - arg_.serialize(in_); - var d_ = await Call(11935670180855499984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_TestPointers() + { Cap = Cap, Obj = Obj, List = List }; + arg_?.serialize(in_); + using (var d_ = await Call(11935670180855499984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } - public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint n, BareProxy inCap, CancellationToken cancellationToken_ = default) + public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint N, BareProxy InCap, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_getAnyCap() - { N = n, InCap = inCap }; - arg_.serialize(in_); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_GetAnyCap() + { N = N, InCap = InCap }; + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(11935670180855499984UL, 2, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.S, r_.OutBox); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.S, r_.OutBox); + } } ); @@ -11649,38 +11728,47 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 11935670180855499984UL; Task GetCap(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.GetCap(in_.N, in_.InCap, cancellationToken_), (s, outBox) => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestPipeline.Result_getCap { S = s, OutBox = outBox }; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.GetCap(in_.N, in_.InCap, cancellationToken_), (s, outBox) => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestPipeline.Result_GetCap { S = s, OutBox = outBox }; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task TestPointers(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.TestPointers(in_.Cap, in_.Obj, in_.List, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.TestPointers(in_.Cap, in_.Obj, in_.List, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } Task GetAnyCap(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.GetAnyCap(in_.N, in_.InCap, cancellationToken_), (s, outBox) => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestPipeline.Result_getAnyCap { S = s, OutBox = outBox }; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.GetAnyCap(in_.N, in_.InCap, cancellationToken_), (s, outBox) => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestPipeline.Result_GetAnyCap { S = s, OutBox = outBox }; + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -11807,7 +11895,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xc7e8df5096257034UL)] - public class Params_getCap : ICapnpSerializable + public class Params_GetCap : ICapnpSerializable { public const UInt64 typeId = 0xc7e8df5096257034UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -11882,7 +11970,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xb2442a9e0ba28fdfUL)] - public class Result_getCap : ICapnpSerializable + public class Result_GetCap : ICapnpSerializable { public const UInt64 typeId = 0xb2442a9e0ba28fdfUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -11931,7 +12019,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string S => ctx.ReadText(0, ""); + public string S => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.TestPipeline.Box.READER OutBox => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestPipeline.Box.READER.create); } @@ -11944,8 +12032,8 @@ namespace Capnproto_test.Capnp.Test public string S { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.TestPipeline.Box.WRITER OutBox @@ -11957,7 +12045,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xa604ee63cf37819fUL)] - public class Params_testPointers : ICapnpSerializable + public class Params_TestPointers : ICapnpSerializable { public const UInt64 typeId = 0xa604ee63cf37819fUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -12047,7 +12135,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x8eda54756c6070d6UL)] - public class Result_testPointers : ICapnpSerializable + public class Result_TestPointers : ICapnpSerializable { public const UInt64 typeId = 0x8eda54756c6070d6UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -12092,7 +12180,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xf8e36b53ab093d4eUL)] - public class Params_getAnyCap : ICapnpSerializable + public class Params_GetAnyCap : ICapnpSerializable { public const UInt64 typeId = 0xf8e36b53ab093d4eUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -12167,7 +12255,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xbf44b4c94c26ef79UL)] - public class Result_getAnyCap : ICapnpSerializable + public class Result_GetAnyCap : ICapnpSerializable { public const UInt64 typeId = 0xbf44b4c94c26ef79UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -12216,7 +12304,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string S => ctx.ReadText(0, ""); + public string S => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.TestPipeline.AnyBox.READER OutBox => ctx.ReadStruct(1, Capnproto_test.Capnp.Test.TestPipeline.AnyBox.READER.create); } @@ -12229,8 +12317,8 @@ namespace Capnproto_test.Capnp.Test public string S { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.TestPipeline.AnyBox.WRITER OutBox @@ -12245,20 +12333,22 @@ namespace Capnproto_test.Capnp.Test [TypeId(0xa0e77035bdff0051UL), Proxy(typeof(TestCallOrder_Proxy)), Skeleton(typeof(TestCallOrder_Skeleton))] public interface ITestCallOrder : IDisposable { - Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default); + Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default); } public class TestCallOrder_Proxy : Proxy, ITestCallOrder { - public async Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) + public async Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestCallOrder.Params_getCallSequence() - { Expected = expected }; - arg_.serialize(in_); - var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.N); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestCallOrder.Params_GetCallSequence() + { Expected = Expected }; + arg_?.serialize(in_); + using (var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.N); + } } } @@ -12272,23 +12362,26 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 11594359141811814481UL; Task GetCallSequence(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.GetCallSequence(in_.Expected, cancellationToken_), n => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestCallOrder.Result_getCallSequence { N = n }; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.GetCallSequence(in_.Expected, cancellationToken_), n => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestCallOrder.Result_GetCallSequence { N = n }; + r_.serialize(s_); + return s_; + } - ); + ); + } } } public static class TestCallOrder { [TypeId(0x8f1e8cd56ceb74dcUL)] - public class Params_getCallSequence : ICapnpSerializable + public class Params_GetCallSequence : ICapnpSerializable { public const UInt64 typeId = 0x8f1e8cd56ceb74dcUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -12348,7 +12441,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xdedbb6bf3810eab7UL)] - public class Result_getCallSequence : ICapnpSerializable + public class Result_GetCallSequence : ICapnpSerializable { public const UInt64 typeId = 0xdedbb6bf3810eab7UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -12411,21 +12504,24 @@ namespace Capnproto_test.Capnp.Test [TypeId(0xddd699207eb8e23bUL), Proxy(typeof(TestTailCallee_Proxy)), Skeleton(typeof(TestTailCallee_Skeleton))] public interface ITestTailCallee : IDisposable { - Task Foo(int i, string t, CancellationToken cancellationToken_ = default); + Task Foo(int I, string T, CancellationToken cancellationToken_ = default); } public class TestTailCallee_Proxy : Proxy, ITestTailCallee { - public Task Foo(int i, string t, CancellationToken cancellationToken_ = default) + public Task Foo(int I, string T, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestTailCallee.Params_foo() - { I = i, T = t }; - arg_.serialize(in_); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestTailCallee.Params_Foo() + { I = I, T = T }; + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15985132292242203195UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return r_; + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } ); @@ -12442,15 +12538,18 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 15985132292242203195UL; Task Foo(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.T, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.T, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -12515,7 +12614,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public uint I => ctx.ReadDataUInt(0UL, 0U); - public string T => ctx.ReadText(0, ""); + public string T => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.ITestCallOrder C => ctx.ReadCap(1); } @@ -12534,8 +12633,8 @@ namespace Capnproto_test.Capnp.Test public string T { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.ITestCallOrder C @@ -12547,7 +12646,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xc5e1efc325614957UL)] - public class Params_foo : ICapnpSerializable + public class Params_Foo : ICapnpSerializable { public const UInt64 typeId = 0xc5e1efc325614957UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -12597,7 +12696,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public int I => ctx.ReadDataInt(0UL, 0); - public string T => ctx.ReadText(0, ""); + public string T => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -12615,8 +12714,8 @@ namespace Capnproto_test.Capnp.Test public string T { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -12625,21 +12724,24 @@ namespace Capnproto_test.Capnp.Test [TypeId(0x870bf40110ce3035UL), Proxy(typeof(TestTailCaller_Proxy)), Skeleton(typeof(TestTailCaller_Skeleton))] public interface ITestTailCaller : IDisposable { - Task Foo(int i, Capnproto_test.Capnp.Test.ITestTailCallee callee, CancellationToken cancellationToken_ = default); + Task Foo(int I, Capnproto_test.Capnp.Test.ITestTailCallee Callee, CancellationToken cancellationToken_ = default); } public class TestTailCaller_Proxy : Proxy, ITestTailCaller { - public Task Foo(int i, Capnproto_test.Capnp.Test.ITestTailCallee callee, CancellationToken cancellationToken_ = default) + public Task Foo(int I, Capnproto_test.Capnp.Test.ITestTailCallee Callee, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestTailCaller.Params_foo() - { I = i, Callee = callee }; - arg_.serialize(in_); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestTailCaller.Params_Foo() + { I = I, Callee = Callee }; + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(9731139705278181429UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return r_; + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } ); @@ -12656,22 +12758,25 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 9731139705278181429UL; Task Foo(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.Callee, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.Callee, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } public static class TestTailCaller { [TypeId(0xb07a279515dc8ac5UL)] - public class Params_foo : ICapnpSerializable + public class Params_Foo : ICapnpSerializable { public const UInt64 typeId = 0xb07a279515dc8ac5UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -12768,144 +12873,168 @@ namespace Capnproto_test.Capnp.Test [TypeId(0xddc70bf9784133cfUL), Proxy(typeof(TestMoreStuff_Proxy)), Skeleton(typeof(TestMoreStuff_Skeleton))] public interface ITestMoreStuff : Capnproto_test.Capnp.Test.ITestCallOrder { - Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); - Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); - Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); - Task Hold(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); + Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); + Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); + Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); + Task Hold(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); Task CallHeld(CancellationToken cancellationToken_ = default); Task GetHeld(CancellationToken cancellationToken_ = default); - Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder cap, CancellationToken cancellationToken_ = default); - Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); - Task<(string, string)> MethodWithDefaults(string a, uint b, string c, CancellationToken cancellationToken_ = default); + Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder Cap, CancellationToken cancellationToken_ = default); + Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); + Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default); Task GetHandle(CancellationToken cancellationToken_ = default); Task GetNull(CancellationToken cancellationToken_ = default); Task GetEnormousString(CancellationToken cancellationToken_ = default); - Task MethodWithNullDefault(string a, Capnproto_test.Capnp.Test.ITestInterface b, CancellationToken cancellationToken_ = default); + Task MethodWithNullDefault(string A, Capnproto_test.Capnp.Test.ITestInterface B, CancellationToken cancellationToken_ = default); } public class TestMoreStuff_Proxy : Proxy, ITestMoreStuff { - public async Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) + public async Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_callFoo() - { Cap = cap }; - arg_.serialize(in_); - var d_ = await Call(15980754968839795663UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.S); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_CallFoo() + { Cap = Cap }; + arg_?.serialize(in_); + using (var d_ = await Call(15980754968839795663UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.S); + } } - public async Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) + public async Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_callFooWhenResolved() - { Cap = cap }; - arg_.serialize(in_); - var d_ = await Call(15980754968839795663UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.S); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_CallFooWhenResolved() + { Cap = Cap }; + arg_?.serialize(in_); + using (var d_ = await Call(15980754968839795663UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.S); + } } - public Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) + public Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_neverReturn() - { Cap = cap }; - arg_.serialize(in_); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_NeverReturn() + { Cap = Cap }; + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 2, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.CapCopy); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.CapCopy); + } } ); } - public async Task Hold(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) + public async Task Hold(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_hold() - { Cap = cap }; - arg_.serialize(in_); - var d_ = await Call(15980754968839795663UL, 3, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_Hold() + { Cap = Cap }; + arg_?.serialize(in_); + using (var d_ = await Call(15980754968839795663UL, 3, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task CallHeld(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_callHeld() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_CallHeld() { }; - arg_.serialize(in_); - var d_ = await Call(15980754968839795663UL, 4, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.S); + arg_?.serialize(in_); + using (var d_ = await Call(15980754968839795663UL, 4, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.S); + } } public Task GetHeld(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_getHeld() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_GetHeld() { }; - arg_.serialize(in_); + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 5, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.Cap); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Cap); + } } ); } - public Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder cap, CancellationToken cancellationToken_ = default) + public Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder Cap, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_echo() - { Cap = cap }; - arg_.serialize(in_); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_Echo() + { Cap = Cap }; + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 6, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.Cap); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Cap); + } } ); } - public async Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) + public async Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_expectCancel() - { Cap = cap }; - arg_.serialize(in_); - var d_ = await Call(15980754968839795663UL, 7, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_ExpectCancel() + { Cap = Cap }; + arg_?.serialize(in_); + using (var d_ = await Call(15980754968839795663UL, 7, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } - public async Task<(string, string)> MethodWithDefaults(string a, uint b, string c, CancellationToken cancellationToken_ = default) + public async Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_methodWithDefaults() - { A = a, B = b, C = c }; - arg_.serialize(in_); - var d_ = await Call(15980754968839795663UL, 8, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.D, r_.E); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_MethodWithDefaults() + { A = A, B = B, C = C }; + arg_?.serialize(in_); + using (var d_ = await Call(15980754968839795663UL, 8, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.D, r_.E); + } } public Task GetHandle(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_getHandle() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_GetHandle() { }; - arg_.serialize(in_); + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 9, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.Handle); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Handle); + } } ); @@ -12913,14 +13042,17 @@ namespace Capnproto_test.Capnp.Test public Task GetNull(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_getNull() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_GetNull() { }; - arg_.serialize(in_); + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 10, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.NullCap); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.NullCap); + } } ); @@ -12928,35 +13060,41 @@ namespace Capnproto_test.Capnp.Test public async Task GetEnormousString(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_getEnormousString() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_GetEnormousString() { }; - arg_.serialize(in_); - var d_ = await Call(15980754968839795663UL, 11, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.Str); + arg_?.serialize(in_); + using (var d_ = await Call(15980754968839795663UL, 11, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Str); + } } - public async Task MethodWithNullDefault(string a, Capnproto_test.Capnp.Test.ITestInterface b, CancellationToken cancellationToken_ = default) + public async Task MethodWithNullDefault(string A, Capnproto_test.Capnp.Test.ITestInterface B, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_methodWithNullDefault() - { A = a, B = b }; - arg_.serialize(in_); - var d_ = await Call(15980754968839795663UL, 12, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_MethodWithNullDefault() + { A = A, B = B }; + arg_?.serialize(in_); + using (var d_ = await Call(15980754968839795663UL, 12, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } - public async Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) + public async Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestCallOrder.Params_getCallSequence() - { Expected = expected }; - arg_.serialize(in_); - var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.N); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestCallOrder.Params_GetCallSequence() + { Expected = Expected }; + arg_?.serialize(in_); + using (var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.N); + } } } @@ -12970,168 +13108,207 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 15980754968839795663UL; Task CallFoo(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.CallFoo(in_.Cap, cancellationToken_), s => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_callFoo { S = s }; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.CallFoo(in_.Cap, cancellationToken_), s => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_CallFoo { S = s }; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task CallFooWhenResolved(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.CallFooWhenResolved(in_.Cap, cancellationToken_), s => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_callFooWhenResolved { S = s }; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.CallFooWhenResolved(in_.Cap, cancellationToken_), s => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_CallFooWhenResolved { S = s }; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task NeverReturn(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.NeverReturn(in_.Cap, cancellationToken_), capCopy => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_neverReturn { CapCopy = capCopy }; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.NeverReturn(in_.Cap, cancellationToken_), capCopy => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_NeverReturn { CapCopy = capCopy }; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task Hold(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.Hold(in_.Cap, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.Hold(in_.Cap, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } Task CallHeld(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.CallHeld(cancellationToken_), s => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_callHeld { S = s }; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.CallHeld(cancellationToken_), s => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_CallHeld { S = s }; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task GetHeld(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.GetHeld(cancellationToken_), cap => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_getHeld { Cap = cap }; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.GetHeld(cancellationToken_), cap => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetHeld { Cap = cap }; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task Echo(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.Echo(in_.Cap, cancellationToken_), cap => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_echo { Cap = cap }; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.Echo(in_.Cap, cancellationToken_), cap => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_Echo { Cap = cap }; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task ExpectCancel(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.ExpectCancel(in_.Cap, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.ExpectCancel(in_.Cap, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } Task MethodWithDefaults(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.MethodWithDefaults(in_.A, in_.B, in_.C, cancellationToken_), (d, e) => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_methodWithDefaults { D = d, E = e }; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.MethodWithDefaults(in_.A, in_.B, in_.C, cancellationToken_), (d, e) => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_MethodWithDefaults { D = d, E = e }; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task GetHandle(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.GetHandle(cancellationToken_), handle => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_getHandle { Handle = handle }; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.GetHandle(cancellationToken_), handle => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetHandle { Handle = handle }; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task GetNull(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.GetNull(cancellationToken_), nullCap => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_getNull { NullCap = nullCap }; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.GetNull(cancellationToken_), nullCap => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetNull { NullCap = nullCap }; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task GetEnormousString(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.GetEnormousString(cancellationToken_), str => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_getEnormousString { Str = str }; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.GetEnormousString(cancellationToken_), str => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetEnormousString { Str = str }; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task MethodWithNullDefault(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.MethodWithNullDefault(in_.A, in_.B, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.MethodWithNullDefault(in_.A, in_.B, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } } public static class TestMoreStuff { [TypeId(0x931ba418da60f6e4UL)] - public class Params_callFoo : ICapnpSerializable + public class Params_CallFoo : ICapnpSerializable { public const UInt64 typeId = 0x931ba418da60f6e4UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13191,7 +13368,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x9a28970beccecdd0UL)] - public class Result_callFoo : ICapnpSerializable + public class Result_CallFoo : ICapnpSerializable { public const UInt64 typeId = 0x9a28970beccecdd0UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13232,7 +13409,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string S => ctx.ReadText(0, ""); + public string S => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -13244,14 +13421,14 @@ namespace Capnproto_test.Capnp.Test public string S { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } [TypeId(0xfabc700c2ebe6378UL)] - public class Params_callFooWhenResolved : ICapnpSerializable + public class Params_CallFooWhenResolved : ICapnpSerializable { public const UInt64 typeId = 0xfabc700c2ebe6378UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13311,7 +13488,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xa54ce1e9aa822f90UL)] - public class Result_callFooWhenResolved : ICapnpSerializable + public class Result_CallFooWhenResolved : ICapnpSerializable { public const UInt64 typeId = 0xa54ce1e9aa822f90UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13352,7 +13529,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string S => ctx.ReadText(0, ""); + public string S => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -13364,14 +13541,14 @@ namespace Capnproto_test.Capnp.Test public string S { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } [TypeId(0x94fe60465c95182bUL)] - public class Params_neverReturn : ICapnpSerializable + public class Params_NeverReturn : ICapnpSerializable { public const UInt64 typeId = 0x94fe60465c95182bUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13431,7 +13608,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xdef4e5fa6999c5dcUL)] - public class Result_neverReturn : ICapnpSerializable + public class Result_NeverReturn : ICapnpSerializable { public const UInt64 typeId = 0xdef4e5fa6999c5dcUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13491,7 +13668,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xfe7c8fbb769d8e58UL)] - public class Params_hold : ICapnpSerializable + public class Params_Hold : ICapnpSerializable { public const UInt64 typeId = 0xfe7c8fbb769d8e58UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13551,7 +13728,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xf839fb1374d003c9UL)] - public class Result_hold : ICapnpSerializable + public class Result_Hold : ICapnpSerializable { public const UInt64 typeId = 0xf839fb1374d003c9UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13596,7 +13773,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xf8c5e5ef1edf83beUL)] - public class Params_callHeld : ICapnpSerializable + public class Params_CallHeld : ICapnpSerializable { public const UInt64 typeId = 0xf8c5e5ef1edf83beUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13641,7 +13818,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xe59935f160ac7578UL)] - public class Result_callHeld : ICapnpSerializable + public class Result_CallHeld : ICapnpSerializable { public const UInt64 typeId = 0xe59935f160ac7578UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13682,7 +13859,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string S => ctx.ReadText(0, ""); + public string S => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -13694,14 +13871,14 @@ namespace Capnproto_test.Capnp.Test public string S { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } [TypeId(0xfeffc025fce317e3UL)] - public class Params_getHeld : ICapnpSerializable + public class Params_GetHeld : ICapnpSerializable { public const UInt64 typeId = 0xfeffc025fce317e3UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13746,7 +13923,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xef4e146185af67ceUL)] - public class Result_getHeld : ICapnpSerializable + public class Result_GetHeld : ICapnpSerializable { public const UInt64 typeId = 0xef4e146185af67ceUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13806,7 +13983,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xc07526f7e2e533b9UL)] - public class Params_echo : ICapnpSerializable + public class Params_Echo : ICapnpSerializable { public const UInt64 typeId = 0xc07526f7e2e533b9UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13866,7 +14043,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xa6224536593d5b92UL)] - public class Result_echo : ICapnpSerializable + public class Result_Echo : ICapnpSerializable { public const UInt64 typeId = 0xa6224536593d5b92UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13926,7 +14103,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xa1cc32d87f3edeb1UL)] - public class Params_expectCancel : ICapnpSerializable + public class Params_ExpectCancel : ICapnpSerializable { public const UInt64 typeId = 0xa1cc32d87f3edeb1UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -13986,7 +14163,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x8a3eba1758c0916eUL)] - public class Result_expectCancel : ICapnpSerializable + public class Result_ExpectCancel : ICapnpSerializable { public const UInt64 typeId = 0x8a3eba1758c0916eUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14031,7 +14208,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x99160a25fa50fbf1UL)] - public class Params_methodWithDefaults : ICapnpSerializable + public class Params_MethodWithDefaults : ICapnpSerializable { public const UInt64 typeId = 0x99160a25fa50fbf1UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14090,7 +14267,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string A => ctx.ReadText(0, ""); + public string A => ctx.ReadText(0, null); public uint B => ctx.ReadDataUInt(0UL, 123U); public string C => ctx.ReadText(1, "foo"); } @@ -14104,8 +14281,8 @@ namespace Capnproto_test.Capnp.Test public string A { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public uint B @@ -14123,7 +14300,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x9c7e066f845a6c56UL)] - public class Result_methodWithDefaults : ICapnpSerializable + public class Result_MethodWithDefaults : ICapnpSerializable { public const UInt64 typeId = 0x9c7e066f845a6c56UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14173,7 +14350,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string D => ctx.ReadText(0, ""); + public string D => ctx.ReadText(0, null); public string E => ctx.ReadText(1, "bar"); } @@ -14186,8 +14363,8 @@ namespace Capnproto_test.Capnp.Test public string D { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public string E @@ -14199,7 +14376,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xead024a301a092a1UL)] - public class Params_getHandle : ICapnpSerializable + public class Params_GetHandle : ICapnpSerializable { public const UInt64 typeId = 0xead024a301a092a1UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14244,7 +14421,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xc3490d75420a1fe8UL)] - public class Result_getHandle : ICapnpSerializable + public class Result_GetHandle : ICapnpSerializable { public const UInt64 typeId = 0xc3490d75420a1fe8UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14304,7 +14481,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xd8493f0e175d61f2UL)] - public class Params_getNull : ICapnpSerializable + public class Params_GetNull : ICapnpSerializable { public const UInt64 typeId = 0xd8493f0e175d61f2UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14349,7 +14526,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xe6955d8ef1023671UL)] - public class Result_getNull : ICapnpSerializable + public class Result_GetNull : ICapnpSerializable { public const UInt64 typeId = 0xe6955d8ef1023671UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14409,7 +14586,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x805df436f55dd07aUL)] - public class Params_getEnormousString : ICapnpSerializable + public class Params_GetEnormousString : ICapnpSerializable { public const UInt64 typeId = 0x805df436f55dd07aUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14454,7 +14631,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x860e7512dc3925b0UL)] - public class Result_getEnormousString : ICapnpSerializable + public class Result_GetEnormousString : ICapnpSerializable { public const UInt64 typeId = 0x860e7512dc3925b0UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14495,7 +14672,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Str => ctx.ReadText(0, ""); + public string Str => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -14507,14 +14684,14 @@ namespace Capnproto_test.Capnp.Test public string Str { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } [TypeId(0xfb92899aeb0ee74fUL)] - public class Params_methodWithNullDefault : ICapnpSerializable + public class Params_MethodWithNullDefault : ICapnpSerializable { public const UInt64 typeId = 0xfb92899aeb0ee74fUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14563,7 +14740,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string A => ctx.ReadText(0, ""); + public string A => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.ITestInterface B => ctx.ReadCap(1); } @@ -14576,8 +14753,8 @@ namespace Capnproto_test.Capnp.Test public string A { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.ITestInterface B @@ -14589,7 +14766,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x8467348247305cf7UL)] - public class Result_methodWithNullDefault : ICapnpSerializable + public class Result_MethodWithNullDefault : ICapnpSerializable { public const UInt64 typeId = 0x8467348247305cf7UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14638,9 +14815,9 @@ namespace Capnproto_test.Capnp.Test public interface ITestMembrane : IDisposable { Task MakeThing(CancellationToken cancellationToken_ = default); - Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default); - Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default); - Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, CancellationToken cancellationToken_ = default); + Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default); + Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default); + Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, CancellationToken cancellationToken_ = default); Task WaitForever(CancellationToken cancellationToken_ = default); } @@ -14648,51 +14825,61 @@ namespace Capnproto_test.Capnp.Test { public Task MakeThing(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_makeThing() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_MakeThing() { }; - arg_.serialize(in_); + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(13870398341137210380UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.Thing); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Thing); + } } ); } - public async Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default) + public async Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_callPassThrough() - { Thing = thing, TailCall = tailCall }; - arg_.serialize(in_); - var d_ = await Call(13870398341137210380UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_CallPassThrough() + { Thing = Thing, TailCall = TailCall }; + arg_?.serialize(in_); + using (var d_ = await Call(13870398341137210380UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } - public async Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default) + public async Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_callIntercept() - { Thing = thing, TailCall = tailCall }; - arg_.serialize(in_); - var d_ = await Call(13870398341137210380UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_CallIntercept() + { Thing = Thing, TailCall = TailCall }; + arg_?.serialize(in_); + using (var d_ = await Call(13870398341137210380UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } - public Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, CancellationToken cancellationToken_ = default) + public Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_loopback() - { Thing = thing }; - arg_.serialize(in_); + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_Loopback() + { Thing = Thing }; + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(13870398341137210380UL, 3, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.Thing); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Thing); + } } ); @@ -14700,13 +14887,15 @@ namespace Capnproto_test.Capnp.Test public async Task WaitForever(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_waitForever() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_WaitForever() { }; - arg_.serialize(in_); - var d_ = await Call(13870398341137210380UL, 4, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(13870398341137210380UL, 4, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -14720,62 +14909,77 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 13870398341137210380UL; Task MakeThing(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.MakeThing(cancellationToken_), thing => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMembrane.Result_makeThing { Thing = thing }; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.MakeThing(cancellationToken_), thing => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMembrane.Result_MakeThing { Thing = thing }; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task CallPassThrough(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.CallPassThrough(in_.Thing, in_.TailCall, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.CallPassThrough(in_.Thing, in_.TailCall, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } Task CallIntercept(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.CallIntercept(in_.Thing, in_.TailCall, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.CallIntercept(in_.Thing, in_.TailCall, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } Task Loopback(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.Loopback(in_.Thing, cancellationToken_), thing => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMembrane.Result_loopback { Thing = thing }; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.Loopback(in_.Thing, cancellationToken_), thing => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMembrane.Result_Loopback { Thing = thing }; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task WaitForever(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.WaitForever(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.WaitForever(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } } @@ -14792,24 +14996,28 @@ namespace Capnproto_test.Capnp.Test { public async Task PassThrough(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Thing.Params_passThrough() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Thing.Params_PassThrough() { }; - arg_.serialize(in_); - var d_ = await Call(10615798940090972439UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + arg_?.serialize(in_); + using (var d_ = await Call(10615798940090972439UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } public async Task Intercept(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Thing.Params_intercept() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Thing.Params_Intercept() { }; - arg_.serialize(in_); - var d_ = await Call(10615798940090972439UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + arg_?.serialize(in_); + using (var d_ = await Call(10615798940090972439UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } } @@ -14823,33 +15031,39 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 10615798940090972439UL; Task PassThrough(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.PassThrough(cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.PassThrough(cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } Task Intercept(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.Intercept(cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.Intercept(cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } public static class Thing { [TypeId(0xff9bdcd05085d786UL)] - public class Params_passThrough : ICapnpSerializable + public class Params_PassThrough : ICapnpSerializable { public const UInt64 typeId = 0xff9bdcd05085d786UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14894,7 +15108,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xee94bed3615ee745UL)] - public class Params_intercept : ICapnpSerializable + public class Params_Intercept : ICapnpSerializable { public const UInt64 typeId = 0xee94bed3615ee745UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -14981,7 +15195,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Text => ctx.ReadText(0, ""); + public string Text => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -14993,14 +15207,14 @@ namespace Capnproto_test.Capnp.Test public string Text { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } [TypeId(0xd8ac2acc3ece6556UL)] - public class Params_makeThing : ICapnpSerializable + public class Params_MakeThing : ICapnpSerializable { public const UInt64 typeId = 0xd8ac2acc3ece6556UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15045,7 +15259,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xe5d4904814ccbf29UL)] - public class Result_makeThing : ICapnpSerializable + public class Result_MakeThing : ICapnpSerializable { public const UInt64 typeId = 0xe5d4904814ccbf29UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15105,7 +15319,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x945d9f634a6a29daUL)] - public class Params_callPassThrough : ICapnpSerializable + public class Params_CallPassThrough : ICapnpSerializable { public const UInt64 typeId = 0x945d9f634a6a29daUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15180,7 +15394,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x8749aac3375c5c71UL)] - public class Params_callIntercept : ICapnpSerializable + public class Params_CallIntercept : ICapnpSerializable { public const UInt64 typeId = 0x8749aac3375c5c71UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15255,7 +15469,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x869a1b7ab34b42c9UL)] - public class Params_loopback : ICapnpSerializable + public class Params_Loopback : ICapnpSerializable { public const UInt64 typeId = 0x869a1b7ab34b42c9UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15315,7 +15529,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xecd19398fd88ab5cUL)] - public class Result_loopback : ICapnpSerializable + public class Result_Loopback : ICapnpSerializable { public const UInt64 typeId = 0xecd19398fd88ab5cUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15375,7 +15589,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x8f6bb30cc62917ffUL)] - public class Params_waitForever : ICapnpSerializable + public class Params_WaitForever : ICapnpSerializable { public const UInt64 typeId = 0x8f6bb30cc62917ffUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15420,7 +15634,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xc343a4907280be01UL)] - public class Result_waitForever : ICapnpSerializable + public class Result_WaitForever : ICapnpSerializable { public const UInt64 typeId = 0xc343a4907280be01UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15547,7 +15761,7 @@ namespace Capnproto_test.Capnp.Test void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); - List = reader.List.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + List = reader.List?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); applyDefaults(); } @@ -15649,7 +15863,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Text => ctx.ReadText(0, ""); + public string Text => ctx.ReadText(0, null); public Capnproto_test.Capnp.Test.ITestInterface Cap => ctx.ReadCap(1); } @@ -15662,8 +15876,8 @@ namespace Capnproto_test.Capnp.Test public string Text { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public Capnproto_test.Capnp.Test.ITestInterface Cap @@ -15688,46 +15902,54 @@ namespace Capnproto_test.Capnp.Test { public async Task Delete(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_delete() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_Delete() { }; - arg_.serialize(in_); - var d_ = await Call(11160837778045172988UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(11160837778045172988UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Class(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_class() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_Class() { }; - arg_.serialize(in_); - var d_ = await Call(11160837778045172988UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(11160837778045172988UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Void(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_void() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_Void() { }; - arg_.serialize(in_); - var d_ = await Call(11160837778045172988UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(11160837778045172988UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Return(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_return() + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_Return() { }; - arg_.serialize(in_); - var d_ = await Call(11160837778045172988UL, 3, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + arg_?.serialize(in_); + using (var d_ = await Call(11160837778045172988UL, 3, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -15741,37 +15963,49 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 11160837778045172988UL; async Task Delete(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Delete(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Delete(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } async Task Class(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Class(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Class(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } async Task Void(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Void(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Void(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } async Task Return(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Return(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Return(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } } public static class TestKeywordMethods { [TypeId(0xca3a89cdeb6bd6b7UL)] - public class Params_delete : ICapnpSerializable + public class Params_Delete : ICapnpSerializable { public const UInt64 typeId = 0xca3a89cdeb6bd6b7UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15816,7 +16050,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xeeb5843598307592UL)] - public class Result_delete : ICapnpSerializable + public class Result_Delete : ICapnpSerializable { public const UInt64 typeId = 0xeeb5843598307592UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15861,7 +16095,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x9cf5a8313c5db036UL)] - public class Params_class : ICapnpSerializable + public class Params_Class : ICapnpSerializable { public const UInt64 typeId = 0x9cf5a8313c5db036UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15906,7 +16140,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xc0253868ac12e7d8UL)] - public class Result_class : ICapnpSerializable + public class Result_Class : ICapnpSerializable { public const UInt64 typeId = 0xc0253868ac12e7d8UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15951,7 +16185,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xa4a08763833c7757UL)] - public class Params_void : ICapnpSerializable + public class Params_Void : ICapnpSerializable { public const UInt64 typeId = 0xa4a08763833c7757UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -15996,7 +16230,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xde82773089c0aeabUL)] - public class Result_void : ICapnpSerializable + public class Result_Void : ICapnpSerializable { public const UInt64 typeId = 0xde82773089c0aeabUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -16041,7 +16275,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0x99817360625e8ca3UL)] - public class Params_return : ICapnpSerializable + public class Params_Return : ICapnpSerializable { public const UInt64 typeId = 0x99817360625e8ca3UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -16086,7 +16320,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xb70872e07eaa992fUL)] - public class Result_return : ICapnpSerializable + public class Result_Return : ICapnpSerializable { public const UInt64 typeId = 0xb70872e07eaa992fUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -16141,14 +16375,17 @@ namespace Capnproto_test.Capnp.Test { public Task GetCallerId(CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc.Params_getCallerId.WRITER>(); - var arg_ = new Capnproto_test.Capnp.Test.TestAuthenticatedBootstrap.Params_getCallerId() + var in_ = SerializerState.CreateForRpc.Params_GetCallerId.WRITER>(); + var arg_ = new Capnproto_test.Capnp.Test.TestAuthenticatedBootstrap.Params_GetCallerId() { }; - arg_.serialize(in_); + arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(16893789964317726925UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create.Result_getCallerId>(d_); - return (r_.Caller); + using (d_) + { + var r_ = CapnpSerializable.Create.Result_GetCallerId>(d_); + return (r_.Caller); + } } ); @@ -16165,15 +16402,18 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 16893789964317726925UL; Task GetCallerId(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.GetCallerId(cancellationToken_), caller => + using (d_) { - var s_ = SerializerState.CreateForRpc.Result_getCallerId.WRITER>(); - var r_ = new Capnproto_test.Capnp.Test.TestAuthenticatedBootstrap.Result_getCallerId { Caller = caller }; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.GetCallerId(cancellationToken_), caller => + { + var s_ = SerializerState.CreateForRpc.Result_GetCallerId.WRITER>(); + var r_ = new Capnproto_test.Capnp.Test.TestAuthenticatedBootstrap.Result_GetCallerId { Caller = caller }; + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -16181,7 +16421,7 @@ namespace Capnproto_test.Capnp.Test where TVatId : class { [TypeId(0x8ec30e2451f1cffeUL)] - public class Params_getCallerId : ICapnpSerializable + public class Params_GetCallerId : ICapnpSerializable { public const UInt64 typeId = 0x8ec30e2451f1cffeUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -16226,7 +16466,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xc71cf776034a3e67UL)] - public class Result_getCallerId : ICapnpSerializable + public class Result_GetCallerId : ICapnpSerializable { public const UInt64 typeId = 0xc71cf776034a3e67UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -16403,7 +16643,7 @@ namespace Capnproto_test.Capnp.Test public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Host => ctx.ReadText(0, ""); + public string Host => ctx.ReadText(0, null); } public class WRITER : SerializerState @@ -16415,8 +16655,8 @@ namespace Capnproto_test.Capnp.Test public string Host { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } } } @@ -16697,7 +16937,7 @@ namespace Capnproto_test.Capnp.Test } AnotherBadFieldName = reader.AnotherBadFieldName; - BadlyNamedUnion = CapnpSerializable.Create(reader.BadlyNamedUnion); + BadlyNamedUnion = CapnpSerializable.Create(reader.BadlyNamedUnion); applyDefaults(); } @@ -16775,7 +17015,7 @@ namespace Capnproto_test.Capnp.Test set; } - public Capnproto_test.Capnp.Test.TestNameAnnotation.@badlyNamedUnion BadlyNamedUnion + public Capnproto_test.Capnp.Test.TestNameAnnotation.badlyNamedUnion BadlyNamedUnion { get; set; @@ -16796,7 +17036,7 @@ namespace Capnproto_test.Capnp.Test public bool BadFieldName => which == WHICH.BadFieldName ? ctx.ReadDataBool(0UL, false) : default; public sbyte Bar => which == WHICH.Bar ? ctx.ReadDataSByte(0UL, (sbyte)0) : default; public Capnproto_test.Capnp.Test.TestNameAnnotation.BadlyNamedEnum AnotherBadFieldName => (Capnproto_test.Capnp.Test.TestNameAnnotation.BadlyNamedEnum)ctx.ReadDataUShort(32UL, (ushort)0); - public @badlyNamedUnion.READER BadlyNamedUnion => new @badlyNamedUnion.READER(ctx); + public badlyNamedUnion.READER BadlyNamedUnion => new badlyNamedUnion.READER(ctx); } public class WRITER : SerializerState @@ -16830,14 +17070,14 @@ namespace Capnproto_test.Capnp.Test set => this.WriteData(32UL, (ushort)value, (ushort)0); } - public @badlyNamedUnion.WRITER BadlyNamedUnion + public badlyNamedUnion.WRITER BadlyNamedUnion { - get => Rewrap<@badlyNamedUnion.WRITER>(); + get => Rewrap(); } } [TypeId(0x89d9d1626b34017cUL)] - public class @badlyNamedUnion : ICapnpSerializable + public class badlyNamedUnion : ICapnpSerializable { public const UInt64 typeId = 0x89d9d1626b34017cUL; public enum WHICH : ushort @@ -16853,7 +17093,7 @@ namespace Capnproto_test.Capnp.Test switch (reader.which) { case WHICH.BadlyNamedGroup: - BadlyNamedGroup = CapnpSerializable.Create(reader.BadlyNamedGroup); + BadlyNamedGroup = CapnpSerializable.Create(reader.BadlyNamedGroup); break; case WHICH.Baz: Baz = CapnpSerializable.Create(reader.Baz); @@ -16908,9 +17148,9 @@ namespace Capnproto_test.Capnp.Test { } - public Capnproto_test.Capnp.Test.TestNameAnnotation.@badlyNamedUnion.@badlyNamedGroup BadlyNamedGroup + public Capnproto_test.Capnp.Test.TestNameAnnotation.badlyNamedUnion.badlyNamedGroup BadlyNamedGroup { - get => _which == WHICH.BadlyNamedGroup ? (Capnproto_test.Capnp.Test.TestNameAnnotation.@badlyNamedUnion.@badlyNamedGroup)_content : null; + get => _which == WHICH.BadlyNamedGroup ? (Capnproto_test.Capnp.Test.TestNameAnnotation.badlyNamedUnion.badlyNamedGroup)_content : null; set { _which = WHICH.BadlyNamedGroup; @@ -16940,7 +17180,7 @@ namespace Capnproto_test.Capnp.Test public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public WHICH which => (WHICH)ctx.ReadDataUShort(48U, (ushort)0); - public @badlyNamedGroup.READER BadlyNamedGroup => which == WHICH.BadlyNamedGroup ? new @badlyNamedGroup.READER(ctx) : default; + public badlyNamedGroup.READER BadlyNamedGroup => which == WHICH.BadlyNamedGroup ? new badlyNamedGroup.READER(ctx) : default; public Capnproto_test.Capnp.Test.TestNameAnnotation.NestedStruct.READER Baz => which == WHICH.Baz ? ctx.ReadStruct(0, Capnproto_test.Capnp.Test.TestNameAnnotation.NestedStruct.READER.create) : default; } @@ -16956,9 +17196,9 @@ namespace Capnproto_test.Capnp.Test set => this.WriteData(48U, (ushort)value, (ushort)0); } - public @badlyNamedGroup.WRITER BadlyNamedGroup + public badlyNamedGroup.WRITER BadlyNamedGroup { - get => which == WHICH.BadlyNamedGroup ? Rewrap<@badlyNamedGroup.WRITER>() : default; + get => which == WHICH.BadlyNamedGroup ? Rewrap() : default; } public Capnproto_test.Capnp.Test.TestNameAnnotation.NestedStruct.WRITER Baz @@ -16969,7 +17209,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xc3594bce5b24b722UL)] - public class @badlyNamedGroup : ICapnpSerializable + public class badlyNamedGroup : ICapnpSerializable { public const UInt64 typeId = 0xc3594bce5b24b722UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -17108,20 +17348,22 @@ namespace Capnproto_test.Capnp.Test [TypeId(0xd112a69d31ed918bUL), Proxy(typeof(TestNameAnnotationInterface_Proxy)), Skeleton(typeof(TestNameAnnotationInterface_Skeleton))] public interface ITestNameAnnotationInterface : IDisposable { - Task BadlyNamedMethod(byte badlyNamedParam, CancellationToken cancellationToken_ = default); + Task BadlyNamedMethod(byte BadlyNamedParam, CancellationToken cancellationToken_ = default); } public class TestNameAnnotationInterface_Proxy : Proxy, ITestNameAnnotationInterface { - public async Task BadlyNamedMethod(byte badlyNamedParam, CancellationToken cancellationToken_ = default) + public async Task BadlyNamedMethod(byte BadlyNamedParam, CancellationToken cancellationToken_ = default) { - var in_ = SerializerState.CreateForRpc(); - var arg_ = new Capnproto_test.Capnp.Test.TestNameAnnotationInterface.Params_badlyNamedMethod() - { BadlyNamedParam = badlyNamedParam }; - arg_.serialize(in_); - var d_ = await Call(15065286897585459595UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + var in_ = SerializerState.CreateForRpc(); + var arg_ = new Capnproto_test.Capnp.Test.TestNameAnnotationInterface.Params_BadlyNamedMethod() + { BadlyNamedParam = BadlyNamedParam }; + arg_?.serialize(in_); + using (var d_ = await Call(15065286897585459595UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -17135,17 +17377,20 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 15065286897585459595UL; async Task BadlyNamedMethod(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.BadlyNamedMethod(in_.BadlyNamedParam, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.BadlyNamedMethod(in_.BadlyNamedParam, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } } public static class TestNameAnnotationInterface { [TypeId(0xc12efc3b075adfe9UL)] - public class Params_badlyNamedMethod : ICapnpSerializable + public class Params_BadlyNamedMethod : ICapnpSerializable { public const UInt64 typeId = 0xc12efc3b075adfe9UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -17205,7 +17450,7 @@ namespace Capnproto_test.Capnp.Test } [TypeId(0xdcc3cdb4b28f6c86UL)] - public class Result_badlyNamedMethod : ICapnpSerializable + public class Result_BadlyNamedMethod : ICapnpSerializable { public const UInt64 typeId = 0xdcc3cdb4b28f6c86UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) @@ -17255,23 +17500,22 @@ namespace Capnproto_test.Capnp.Test static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap = new MemberAccessPath(1U, 0U); public static Capnproto_test.Capnp.Test.ITestInterface OutBox_Cap(this Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> task) { - async Task AwaitProxy() => (await task).Item2.Cap; - - return (Capnproto_test.Capnp.Test.ITestInterface)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access( - Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap, - AwaitProxy())); + async Task AwaitProxy() => (await task).Item2?.Cap; + return (Capnproto_test.Capnp.Test.ITestInterface)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap, AwaitProxy())); } static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap = new MemberAccessPath(1U, 0U); public static BareProxy OutBox_Cap(this Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> task) { - return (BareProxy)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap)); + async Task AwaitProxy() => (await task).Item2?.Cap; + return (BareProxy)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap, AwaitProxy())); } static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestTailCallee_foo_C = new MemberAccessPath(1U); public static Capnproto_test.Capnp.Test.ITestCallOrder C(this Task task) { - return (Capnproto_test.Capnp.Test.ITestCallOrder)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestTailCallee_foo_C)); + async Task AwaitProxy() => (await task).C; + return (Capnproto_test.Capnp.Test.ITestCallOrder)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestTailCallee_foo_C, AwaitProxy())); } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs b/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs index 300320d..be58c28 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs @@ -127,7 +127,7 @@ namespace Capnp.Net.Runtime.Tests _.Call.Target.ImportedCap = bootCapId; _.Call.InterfaceId = ((TypeIdAttribute)typeof(ITestInterface).GetCustomAttributes(typeof(TypeIdAttribute), false)[0]).Id; _.Call.MethodId = 0; - _.Call.Params.Content.Rewrap(); + _.Call.Params.Content.Rewrap(); }); tester.ExpectAbort(); } @@ -154,7 +154,7 @@ namespace Capnp.Net.Runtime.Tests _.Call.Target.ImportedCap = bootCapId; _.Call.InterfaceId = ((TypeIdAttribute)typeof(ITestInterface).GetCustomAttributes(typeof(TypeIdAttribute), false)[0]).Id; _.Call.MethodId = 0; - var wr = _.Call.Params.Content.Rewrap(); + var wr = _.Call.Params.Content.Rewrap(); wr.I = 123u; wr.J = true; }); @@ -168,7 +168,7 @@ namespace Capnp.Net.Runtime.Tests _.Call.Target.ImportedCap = bootCapId; _.Call.InterfaceId = ((TypeIdAttribute)typeof(ITestInterface).GetCustomAttributes(typeof(TypeIdAttribute), false)[0]).Id; _.Call.MethodId = 0; - _.Call.Params.Content.Rewrap(); + _.Call.Params.Content.Rewrap(); }); tester.ExpectAbort(); } @@ -565,7 +565,7 @@ namespace Capnp.Net.Runtime.Tests _.Call.Target.ImportedCap = bootCapId; _.Call.InterfaceId = new TestPipeline_Skeleton().InterfaceId; _.Call.MethodId = 0; - var wr = _.Call.Params.Content.Rewrap(); + var wr = _.Call.Params.Content.Rewrap(); wr.InCap = null; _.Call.Params.CapTable.Init(1); _.Call.Params.CapTable[0].which = CapDescriptor.WHICH.ReceiverHosted; diff --git a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs index 6376c49..2f16eff 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs @@ -642,7 +642,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void RetainAndReleaseClient() { using (var server = SetupServer()) diff --git a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs index 5bf3b17..293e595 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs @@ -12,6 +12,7 @@ using Microsoft.Extensions.Logging; namespace Capnp.Net.Runtime.Tests { + [TestClass] [TestCategory("Coverage")] public class TcpRpcPorted: TestBase @@ -19,99 +20,19 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void Basic() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var counters = new Counters(); - server.Main = new TestInterfaceImpl(counters); - using (var main = client.GetMain()) - { - var request1 = main.Foo(123, true, default); - var request3 = Assert.ThrowsExceptionAsync(() => main.Bar(default)); - var s = new TestAllTypes(); - Common.InitTestMessage(s); - var request2 = main.Baz(s, default); - - Assert.IsTrue(request1.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(request2.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(request3.Wait(MediumNonDbgTimeout)); - - Assert.AreEqual("foo", request1.Result); - Assert.AreEqual(2, counters.CallCount); - } - } + NewLocalhostTcpTestbed().RunTest(Testsuite.Basic); } [TestMethod] public void Pipeline() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var counters = new Counters(); - server.Main = new TestPipelineImpl(counters); - using (var main = client.GetMain()) - { - var chainedCallCount = new Counters(); - var request = main.GetCap(234, new TestInterfaceImpl(chainedCallCount), default); - using (var outBox = request.OutBox_Cap()) - { - var pipelineRequest = outBox.Foo(321, false, default); - var pipelineRequest2 = ((Proxy)outBox).Cast(false).Grault(default); - - Assert.IsTrue(pipelineRequest.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(pipelineRequest2.Wait(MediumNonDbgTimeout)); - - Assert.AreEqual("bar", pipelineRequest.Result); - Common.CheckTestMessage(pipelineRequest2.Result); - - Assert.AreEqual(3, counters.CallCount); - Assert.AreEqual(1, chainedCallCount.CallCount); - } - } - - } + NewLocalhostTcpTestbed().RunTest(Testsuite.Pipeline); } [TestMethod] public void Release() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var counters = new Counters(); - server.Main = new TestMoreStuffImpl(counters); - using (var main = client.GetMain()) - { - var task1 = main.GetHandle(default); - var task2 = main.GetHandle(default); - Assert.IsTrue(task1.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(task2.Wait(MediumNonDbgTimeout)); - - Assert.AreEqual(2, counters.HandleCount); - - task1.Result.Dispose(); - - Assert.IsTrue(SpinWait.SpinUntil(() => counters.HandleCount == 1, MediumNonDbgTimeout)); - - task2.Result.Dispose(); - - Assert.IsTrue(SpinWait.SpinUntil(() => counters.HandleCount == 0, MediumNonDbgTimeout)); - } - - } + NewLocalhostTcpTestbed().RunTest(Testsuite.Release); } [TestMethod] @@ -160,482 +81,63 @@ namespace Capnp.Net.Runtime.Tests } [TestMethod] - public void TestTailCall() + public void TailCall() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var counters = new Counters(); - server.Main = new TestTailCallerImpl(counters); - using (var main = client.GetMain()) - { - var calleeCallCount = new Counters(); - var callee = new TestTailCalleeImpl(calleeCallCount); - - var promise = main.Foo(456, callee, default); - var dependentCall0 = promise.C().GetCallSequence(0, default); - - Assert.IsTrue(promise.Wait(MediumNonDbgTimeout)); - Assert.AreEqual(456u, promise.Result.I); - Assert.AreEqual("from TestTailCaller", promise.Result.T); - - var dependentCall1 = promise.C().GetCallSequence(0, default); - var dependentCall2 = promise.C().GetCallSequence(0, default); - - Assert.IsTrue(dependentCall0.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(dependentCall1.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(dependentCall2.Wait(MediumNonDbgTimeout)); - - Assert.AreEqual(1, counters.CallCount); - Assert.AreEqual(1, calleeCallCount.CallCount); - } - } + NewLocalhostTcpTestbed().RunTest(Testsuite.TailCall); } [TestMethod] public void Cancelation() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var counters = new Counters(); - server.Main = new TestMoreStuffImpl(counters); - using (var main = client.GetMain()) - { - var destroyed = new TaskCompletionSource(); - var impl = new TestInterfaceImpl(counters, destroyed); - var cts = new CancellationTokenSource(); - var cancelTask = main.ExpectCancel(impl, cts.Token); - - Assert.IsFalse(SpinWait.SpinUntil(() => destroyed.Task.IsCompleted || cancelTask.IsCompleted, ShortTimeout)); - - cts.Cancel(); - - Assert.IsTrue(destroyed.Task.Wait(MediumNonDbgTimeout)); - Assert.IsFalse(cancelTask.IsCompleted && !cancelTask.IsCanceled); - } - - } + NewLocalhostTcpTestbed().RunTest(Testsuite.Cancelation); } [TestMethod] public void PromiseResolve() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var counters = new Counters(); - var impl = new TestMoreStuffImpl(counters); - server.Main = impl; - using (var main = client.GetMain()) - { - var tcs = new TaskCompletionSource(); - var eager = tcs.Task.Eager(true); - - var request = main.CallFoo(eager, default); - var request2 = main.CallFooWhenResolved(eager, default); - - var gcs = main.GetCallSequence(0, default); - Assert.IsTrue(gcs.Wait(MediumNonDbgTimeout)); - Assert.AreEqual(2u, gcs.Result); - Assert.AreEqual(3, counters.CallCount); - - var chainedCallCount = new Counters(); - var tiimpl = new TestInterfaceImpl(chainedCallCount); - tcs.SetResult(tiimpl); - - Assert.IsTrue(request.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(request2.Wait(MediumNonDbgTimeout)); - - Assert.AreEqual("bar", request.Result); - Assert.AreEqual("bar", request2.Result); - Assert.AreEqual(3, counters.CallCount); - Assert.AreEqual(2, chainedCallCount.CallCount); - } - - } + NewLocalhostTcpTestbed().RunTest(Testsuite.PromiseResolve); } [TestMethod] public void RetainAndRelease() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var destructionPromise = new TaskCompletionSource(); - var destructionTask = destructionPromise.Task; - - var counters = new Counters(); - var impl = new TestMoreStuffImpl(counters); - server.Main = impl; - using (var main = client.GetMain()) - { - var holdTask = main.Hold(new TestInterfaceImpl(new Counters(), destructionPromise), default); - Assert.IsTrue(holdTask.Wait(MediumNonDbgTimeout)); - - var cstask = main.GetCallSequence(0, default); - Assert.IsTrue(cstask.Wait(MediumNonDbgTimeout)); - Assert.AreEqual(1u, cstask.Result); - - Assert.IsFalse(destructionTask.IsCompleted); - - var htask = main.CallHeld(default); - Assert.IsTrue(htask.Wait(MediumNonDbgTimeout)); - Assert.AreEqual("bar", htask.Result); - - var gtask = main.GetHeld(default); - Assert.IsTrue(gtask.Wait(MediumNonDbgTimeout)); - // We can get the cap back from it. - using (var cap = gtask.Result) - { - // Wait for balanced state - WaitClientServerIdle(server, client); - - // And call it, without any network communications. - long oldSendCount = client.SendCount; - var ftask = cap.Foo(123, true, default); - Assert.IsTrue(ftask.Wait(MediumNonDbgTimeout)); - Assert.AreEqual("foo", ftask.Result); - Assert.AreEqual(oldSendCount, client.SendCount); - - // We can send another copy of the same cap to another method, and it works. - var ctask = main.CallFoo(cap, default); - Assert.IsTrue(ctask.Wait(MediumNonDbgTimeout)); - Assert.AreEqual("bar", ctask.Result); - - // Give some time to settle. - cstask = main.GetCallSequence(0, default); - Assert.IsTrue(cstask.Wait(MediumNonDbgTimeout)); - Assert.AreEqual(5u, cstask.Result); - cstask = main.GetCallSequence(0, default); - Assert.IsTrue(cstask.Wait(MediumNonDbgTimeout)); - Assert.AreEqual(6u, cstask.Result); - cstask = main.GetCallSequence(0, default); - Assert.IsTrue(cstask.Wait(MediumNonDbgTimeout)); - Assert.AreEqual(7u, cstask.Result); - - // Can't be destroyed, we haven't released it. - Assert.IsFalse(destructionTask.IsCompleted); - } - - // In deviation from original test, we have null the held capability on the main interface. - // This is because the main interface is the bootstrap capability and, as such, won't be disposed - // after disconnect. - var holdNullTask = main.Hold(null, default); - Assert.IsTrue(holdNullTask.Wait(MediumNonDbgTimeout)); - } - - Assert.IsTrue(destructionTask.Wait(MediumNonDbgTimeout)); - } + NewLocalhostTcpTestbed().RunTest(Testsuite.RetainAndRelease); } [TestMethod] public void Cancel() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var destructionPromise = new TaskCompletionSource(); - var destructionTask = destructionPromise.Task; - - var counters = new Counters(); - var impl = new TestMoreStuffImpl(counters); - server.Main = impl; - using (var main = client.GetMain()) - using (var cts = new CancellationTokenSource()) - { - var ntask = main.NeverReturn(new TestInterfaceImpl(counters, destructionPromise), cts.Token); - - // Allow some time to settle. - var cstask = main.GetCallSequence(0, default); - Assert.IsTrue(cstask.Wait(MediumNonDbgTimeout)); - Assert.AreEqual(1u, cstask.Result); - cstask = main.GetCallSequence(0, default); - Assert.IsTrue(cstask.Wait(MediumNonDbgTimeout)); - Assert.AreEqual(2u, cstask.Result); - - // The cap shouldn't have been destroyed yet because the call never returned. - Assert.IsFalse(destructionTask.IsCompleted); - - // There will be no automatic cancellation just because "ntask" goes of of scope or - // because the Proxy is disposed. Even ntask.Dispose() would not cancel the request. - // In .NET this needs to be done explicitly. - cts.Cancel(); - } - - // Now the cap should be released. - Assert.IsTrue(destructionTask.Wait(MediumNonDbgTimeout)); - } + NewLocalhostTcpTestbed().RunTest(Testsuite.Cancel); } [TestMethod] public void SendTwice() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var destructionPromise = new TaskCompletionSource(); - var destructionTask = destructionPromise.Task; - - var counters = new Counters(); - var impl = new TestMoreStuffImpl(counters); - server.Main = impl; - using (var main = client.GetMain()) - { - var cap = new TestInterfaceImpl(new Counters(), destructionPromise); - - Task ftask1, ftask2; - - using (Skeleton.Claim(cap)) - { - var ftask = main.CallFoo(cap, default); - Assert.IsTrue(ftask.Wait(MediumNonDbgTimeout)); - Assert.AreEqual("bar", ftask.Result); - - var ctask = main.GetCallSequence(0, default); - Assert.IsTrue(ctask.Wait(MediumNonDbgTimeout)); - Assert.AreEqual(1u, ctask.Result); - - ftask1 = main.CallFoo(cap, default); - ftask2 = main.CallFoo(cap, default); - } - - Assert.IsTrue(ftask1.Wait(MediumNonDbgTimeout)); - Assert.AreEqual("bar", ftask1.Result); - Assert.IsTrue(ftask2.Wait(MediumNonDbgTimeout)); - Assert.AreEqual("bar", ftask2.Result); - - // Now the cap should be released. - Assert.IsTrue(destructionTask.Wait(MediumNonDbgTimeout)); - } - } + NewLocalhostTcpTestbed().RunTest(Testsuite.SendTwice); } [TestMethod] public void Embargo() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var counters = new Counters(); - var impl = new TestMoreStuffImpl(counters); - server.Main = impl; - using (var main = client.GetMain()) - { - var resolving = main as IResolvingCapability; - Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout)); - - var cap = new TestCallOrderImpl(); - cap.CountToDispose = 6; - - var earlyCall = main.GetCallSequence(0, default); - - var echo = main.Echo(cap, default); - - using (var pipeline = echo.Eager()) - { - var call0 = pipeline.GetCallSequence(0, default); - var call1 = pipeline.GetCallSequence(1, default); - - Assert.IsTrue(earlyCall.Wait(MediumNonDbgTimeout)); - - impl.EnableEcho(); - - var call2 = pipeline.GetCallSequence(2, default); - - Assert.IsTrue(echo.Wait(MediumNonDbgTimeout)); - using (var resolved = echo.Result) - { - var call3 = pipeline.GetCallSequence(3, default); - var call4 = pipeline.GetCallSequence(4, default); - var call5 = pipeline.GetCallSequence(5, default); - - try - { - bool flag = call0.Wait(MediumNonDbgTimeout); - Assert.IsTrue(flag); - } - catch (AggregateException exception) when (exception.InnerException is RpcException rpcException && rpcException.Message == "Cannot access a disposed object.") - { - Console.WriteLine($"Oops, object disposed. Counter = {cap.Count}, tx count = {client.SendCount}, rx count = {client.RecvCount}"); - throw; - } - - Assert.IsTrue(call1.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(call2.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(call3.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(call4.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(call5.Wait(MediumNonDbgTimeout)); - - Assert.AreEqual(0u, call0.Result); - Assert.AreEqual(1u, call1.Result); - Assert.AreEqual(2u, call2.Result); - Assert.AreEqual(3u, call3.Result); - Assert.AreEqual(4u, call4.Result); - Assert.AreEqual(5u, call5.Result); - } - } - } - } + NewLocalhostTcpTestbed().RunTest(Testsuite.Embargo); } [TestMethod] public void EmbargoError() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var counters = new Counters(); - var impl = new TestMoreStuffImpl(counters); - server.Main = impl; - using (var main = client.GetMain()) - { - var resolving = main as IResolvingCapability; - Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout)); - - var cap = new TaskCompletionSource(); - - var earlyCall = main.GetCallSequence(0, default); - - var echo = main.Echo(cap.Task.Eager(true), default); - - var pipeline = echo.Eager(); - - var call0 = pipeline.GetCallSequence(0, default); - var call1 = pipeline.GetCallSequence(1, default); - - Assert.IsTrue(earlyCall.Wait(MediumNonDbgTimeout)); - - impl.EnableEcho(); - - var call2 = pipeline.GetCallSequence(2, default); - - Assert.IsTrue(echo.Wait(MediumNonDbgTimeout)); - var resolved = echo.Result; - - var call3 = pipeline.GetCallSequence(3, default); - var call4 = pipeline.GetCallSequence(4, default); - var call5 = pipeline.GetCallSequence(5, default); - - cap.SetException(new InvalidOperationException("I'm annoying")); - - ExpectPromiseThrows(call0); - ExpectPromiseThrows(call1); - ExpectPromiseThrows(call2); - ExpectPromiseThrows(call3); - ExpectPromiseThrows(call4); - ExpectPromiseThrows(call5); - - // Verify that we're still connected (there were no protocol errors). - Assert.IsTrue(main.GetCallSequence(1, default).Wait(MediumNonDbgTimeout)); - } - } + NewLocalhostTcpTestbed().RunTest(Testsuite.EmbargoError); } [TestMethod] public void EmbargoNull() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var counters = new Counters(); - var impl = new TestMoreStuffImpl(counters); - server.Main = impl; - using (var main = client.GetMain()) - { - var resolving = main as IResolvingCapability; - Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout)); - - var promise = main.GetNull(default); - - var cap = promise.Eager(); - - var call0 = cap.GetCallSequence(0, default); - - Assert.IsTrue(promise.Wait(MediumNonDbgTimeout)); - - var call1 = cap.GetCallSequence(1, default); - - ExpectPromiseThrows(call0); - ExpectPromiseThrows(call1); - - // Verify that we're still connected (there were no protocol errors). - Assert.IsTrue(main.GetCallSequence(1, default).Wait(MediumNonDbgTimeout)); - } - } + NewLocalhostTcpTestbed().RunTest(Testsuite.EmbargoNull); } [TestMethod] public void CallBrokenPromise() { - (var server, var client) = SetupClientServerPair(); - - using (server) - using (client) - { - client.WhenConnected.Wait(); - - var counters = new Counters(); - var impl = new TestMoreStuffImpl(counters); - server.Main = impl; - using (var main = client.GetMain()) - { - var resolving = main as IResolvingCapability; - Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout)); - - var tcs = new TaskCompletionSource(); - - var req = main.Hold(tcs.Task.Eager(true), default); - Assert.IsTrue(req.Wait(MediumNonDbgTimeout)); - - var req2 = main.CallHeld(default); - - Assert.IsFalse(req2.Wait(ShortTimeout)); - - tcs.SetException(new InvalidOperationException("I'm a promise-breaker!")); - - ExpectPromiseThrows(req2); - - // Verify that we're still connected (there were no protocol errors). - Assert.IsTrue(main.GetCallSequence(1, default).Wait(MediumNonDbgTimeout)); - } - } + NewLocalhostTcpTestbed().RunTest(Testsuite.CallBrokenPromise); } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs index fd41551..8f6eec1 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs @@ -6,6 +6,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.Net; +using System.Net.Sockets; using System.Text; using System.Threading; @@ -60,7 +61,11 @@ namespace Capnp.Net.Runtime.Tests { var t = new TcpRpcPorted(); Repeat(100, t.Embargo); + } + [TestMethod] + public void EmbargoServer() + { var t2 = new TcpRpcInterop(); Repeat(100, t2.EmbargoServer); } @@ -94,35 +99,45 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void ScatteredTransfer() { - - using (var server = new TcpRpcServer(IPAddress.Any, TcpPort)) - using (var client = new TcpRpcClient()) + for (int retry = 0; retry < 10; retry++) { - server.InjectMidlayer(s => new ScatteringStream(s, 7)); - client.InjectMidlayer(s => new ScatteringStream(s, 10)); - client.Connect("localhost", TcpPort); - client.WhenConnected.Wait(); - - var counters = new Counters(); - server.Main = new TestInterfaceImpl(counters); - using (var main = client.GetMain()) + try { - for (int i = 0; i < 100; i++) + using (var server = new TcpRpcServer(IPAddress.Any, TcpPort)) + using (var client = new TcpRpcClient()) { - var request1 = main.Foo(123, true, default); - var request3 = Assert.ThrowsExceptionAsync(() => main.Bar(default)); - var s = new TestAllTypes(); - Common.InitTestMessage(s); - var request2 = main.Baz(s, default); + server.InjectMidlayer(s => new ScatteringStream(s, 7)); + client.InjectMidlayer(s => new ScatteringStream(s, 10)); + client.Connect("localhost", TcpPort); + client.WhenConnected.Wait(); - Assert.IsTrue(request1.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(request2.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(request3.Wait(MediumNonDbgTimeout)); + var counters = new Counters(); + server.Main = new TestInterfaceImpl(counters); + using (var main = client.GetMain()) + { + for (int i = 0; i < 100; i++) + { + var request1 = main.Foo(123, true, default); + var request3 = Assert.ThrowsExceptionAsync(() => main.Bar(default)); + var s = new TestAllTypes(); + Common.InitTestMessage(s); + var request2 = main.Baz(s, default); - Assert.AreEqual("foo", request1.Result); - Assert.AreEqual(2, counters.CallCount); - counters.CallCount = 0; + Assert.IsTrue(request1.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(request2.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(request3.Wait(MediumNonDbgTimeout)); + + Assert.AreEqual("foo", request1.Result); + Assert.AreEqual(2, counters.CallCount); + counters.CallCount = 0; + } + } } + return; + } + catch (SocketException) + { + IncrementTcpPort(); } } } diff --git a/Capnp.Net.Runtime.Tests/TestBase.cs b/Capnp.Net.Runtime.Tests/TestBase.cs deleted file mode 100644 index 3eb33fd..0000000 --- a/Capnp.Net.Runtime.Tests/TestBase.cs +++ /dev/null @@ -1,130 +0,0 @@ -using Capnp.Rpc; -using Microsoft.Extensions.Logging; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace Capnp.Net.Runtime.Tests -{ - public class TestBase - { - public static int TcpPort = 49152; - public static int MediumNonDbgTimeout => Debugger.IsAttached ? Timeout.Infinite : 5000; - public static int LargeNonDbgTimeout => Debugger.IsAttached ? Timeout.Infinite : 20000; - public static int ShortTimeout => 500; - - protected ILogger Logger { get; set; } - - protected TcpRpcClient SetupClient() - { - var client = new TcpRpcClient(); - client.AddBuffering(); - client.Connect("localhost", TcpPort); - return client; - } - - protected TcpRpcServer SetupServer() - { - int attempt = 0; - - while (true) - { - try - { - var server = new TcpRpcServer(IPAddress.Any, TcpPort); - server.AddBuffering(); - return server; - } - catch (SocketException) - { - // If the TCP listening port is occupied by some other process, - // retry with a different one - - if (attempt == 5) - throw; - } - - IncrementTcpPort(); - ++attempt; - } - } - - protected (TcpRpcServer, TcpRpcClient) SetupClientServerPair() - { - var server = SetupServer(); - var client = SetupClient(); - return (server, client); - } - - public static void IncrementTcpPort() - { - if (++TcpPort > 49200) - { - TcpPort = 49152; - } - } - - [TestInitialize] - public void InitConsoleLogging() - { - Logging.LoggerFactory?.Dispose(); - Logging.LoggerFactory = new LoggerFactory().AddConsole((msg, level) => true); - Logger = Logging.CreateLogger(); - if (Thread.CurrentThread.Name == null) - Thread.CurrentThread.Name = $"Test Thread {Thread.CurrentThread.ManagedThreadId}"; - } - - /// - /// Somewhat ugly helper method which ensures that both Tcp client and server - /// are waiting for data reception from each other. This is a "balanced" state, meaning - /// that nothing will ever happen in the RcpEngines without some other thread requesting - /// anything. - /// - protected void WaitClientServerIdle(TcpRpcServer server, TcpRpcClient client) - { - var conn = server.Connections[0]; - SpinWait.SpinUntil(() => conn.IsWaitingForData && client.IsWaitingForData && - conn.RecvCount == client.SendCount && - conn.SendCount == client.RecvCount, - MediumNonDbgTimeout); - } - - protected void ExpectPromiseThrows(Task task) - { - async Task ExpectPromiseThrowsAsync(Task t) - { - try - { - await t; - Assert.Fail("Did not throw"); - } - catch (InvalidOperationException) - { - // Happens if the call went to the resolution - // (thus, locally). In this case, the original - // exception is routed here. - } - catch (RpcException) - { - // Happens if the call went to the promise - // (thus, remotely). In this case, the original - // exception had to be serialized, so we receive - // the wrapped version. - } - catch (System.Exception exception) - { - Assert.Fail($"Got wrong kind of exception: {exception}"); - } - } - - Assert.IsTrue(ExpectPromiseThrowsAsync(task).Wait(MediumNonDbgTimeout)); - } - - } -} diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs new file mode 100644 index 0000000..0d9821a --- /dev/null +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -0,0 +1,523 @@ +using System; +using System.Linq; +using Capnp.Rpc; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Capnp.Net.Runtime.Tests.GenImpls; +using Capnproto_test.Capnp.Test; +using System.Threading.Tasks; +using System.Threading; +using System.Runtime.CompilerServices; + +namespace Capnp.Net.Runtime.Tests +{ + static class Testsuite + { + static void ExpectPromiseThrows(this ITestbed testbed, params Task[] tasks) + { + async Task ExpectPromiseThrowsAsync(Task t) + { + try + { + await t; + Assert.Fail("Did not throw"); + } + catch (InvalidOperationException) + { + // Happens if the call went to the resolution + // (thus, locally). In this case, the original + // exception is routed here. + } + catch (InvalidTimeZoneException) + { + // Happens if the call went to the resolution + // (thus, locally). In this case, the original + // exception is routed here. + } + catch (RpcException) + { + // Happens if the call went to the promise + // (thus, remotely). In this case, the original + // exception had to be serialized, so we receive + // the wrapped version. + } + catch (System.Exception exception) + { + Assert.Fail($"Got wrong kind of exception: {exception}"); + } + } + + var ftasks = tasks.Select(ExpectPromiseThrowsAsync).ToArray(); + testbed.MustComplete(ftasks); + + foreach (var ftask in ftasks) + ftask.GetAwaiter().GetResult(); // re-throw exception + } + + public static void Embargo(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + + using (var main = testbed.ConnectMain(impl)) + { + var resolving = main as IResolvingCapability; + testbed.MustComplete(resolving.WhenResolved); + + var cap = new TestCallOrderImpl(); + cap.CountToDispose = 6; + + var earlyCall = main.GetCallSequence(0, default); + + var echo = main.Echo(cap, default); + testbed.MustComplete(Task.CompletedTask); + using (var pipeline = echo.Eager()) + { + var call0 = pipeline.GetCallSequence(0, default); + var call1 = pipeline.GetCallSequence(1, default); + + testbed.MustComplete(earlyCall); + + impl.EnableEcho(); + + var call2 = pipeline.GetCallSequence(2, default); + + testbed.MustComplete(echo); + using (var resolved = echo.Result) + { + var call3 = pipeline.GetCallSequence(3, default); + var call4 = pipeline.GetCallSequence(4, default); + var call5 = pipeline.GetCallSequence(5, default); + + try + { + testbed.MustComplete(call0); + testbed.MustComplete(call1); + testbed.MustComplete(call2); + testbed.MustComplete(call3); + testbed.MustComplete(call4); + testbed.MustComplete(call5); + } + catch (System.Exception) + { + cap.CountToDispose = null; + throw; + } + + Assert.AreEqual(0u, call0.Result); + Assert.AreEqual(1u, call1.Result); + Assert.AreEqual(2u, call2.Result); + Assert.AreEqual(3u, call3.Result); + Assert.AreEqual(4u, call4.Result); + Assert.AreEqual(5u, call5.Result); + } + } + } + } + + public static void EmbargoError(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var resolving = main as IResolvingCapability; + testbed.MustComplete(resolving.WhenResolved); + + var cap = new TaskCompletionSource(); + + var earlyCall = main.GetCallSequence(0, default); + var echo = main.Echo(cap.Task.Eager(true), default); + + using (var pipeline = echo.Eager()) + { + var call0 = pipeline.GetCallSequence(0, default); + var call1 = pipeline.GetCallSequence(1, default); + + testbed.MustComplete(earlyCall); + + impl.EnableEcho(); + + var call2 = pipeline.GetCallSequence(2, default); + + testbed.MustComplete(echo); + var resolved = echo.Result; + var call3 = pipeline.GetCallSequence(3, default); + var call4 = pipeline.GetCallSequence(4, default); + var call5 = pipeline.GetCallSequence(5, default); + + cap.SetException(new InvalidTimeZoneException("I'm annoying")); + + testbed.ExpectPromiseThrows(call0, call1, call2, call3, call4, call5); + + // Verify that we're still connected (there were no protocol errors). + testbed.MustComplete(main.GetCallSequence(1, default)); + } + } + } + + public static void EmbargoNull(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var resolving = main as IResolvingCapability; + testbed.MustComplete(resolving.WhenResolved); + + var promise = main.GetNull(default); + + var cap = promise.Eager(); + + var call0 = cap.GetCallSequence(0, default); + + testbed.MustComplete(promise); + + var call1 = cap.GetCallSequence(1, default); + + testbed.ExpectPromiseThrows(call0, call1); + + // Verify that we're still connected (there were no protocol errors). + testbed.MustComplete(main.GetCallSequence(1, default)); + } + } + + public static void CallBrokenPromise(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var resolving = main as IResolvingCapability; + testbed.MustComplete(resolving.WhenResolved); + + var tcs = new TaskCompletionSource(); + + var req = main.Hold(tcs.Task.Eager(true), default); + testbed.MustComplete(req); + + var req2 = main.CallHeld(default); + + testbed.MustNotComplete(req2); + + tcs.SetException(new InvalidOperationException("I'm a promise-breaker!")); + + testbed.ExpectPromiseThrows(req2); + + // Verify that we're still connected (there were no protocol errors). + testbed.MustComplete(main.GetCallSequence(1, default)); + } + } + + public static void TailCall(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestTailCallerImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var calleeCallCount = new Counters(); + var callee = new TestTailCalleeImpl(calleeCallCount); + + var promise = main.Foo(456, callee, default); + using (var c = promise.C()) + { + var dependentCall0 = c.GetCallSequence(0, default); + + testbed.MustComplete(promise); + Assert.AreEqual(456u, promise.Result.I); + Assert.AreEqual("from TestTailCaller", promise.Result.T); + + var dependentCall1 = c.GetCallSequence(0, default); + var dependentCall2 = c.GetCallSequence(0, default); + + testbed.MustComplete(dependentCall0, dependentCall1, dependentCall2); + + Assert.AreEqual(1, counters.CallCount); + Assert.AreEqual(1, calleeCallCount.CallCount); + } + } + } + + public static void SendTwice(ITestbed testbed) + { + var destructionPromise = new TaskCompletionSource(); + var destructionTask = destructionPromise.Task; + + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var cap = new TestInterfaceImpl(new Counters(), destructionPromise); + + Task ftask1, ftask2; + + using (var claimer = Skeleton.Claim(cap)) + { + var ftask = main.CallFoo(cap, default); + testbed.MustComplete(ftask); + Assert.AreEqual("bar", ftask.Result); + + var ctask = main.GetCallSequence(0, default); + testbed.MustComplete(ctask); + Assert.AreEqual(1u, ctask.Result); + + ftask1 = main.CallFoo(cap, default); + ftask2 = main.CallFoo(cap, default); + } + + testbed.MustComplete(ftask1); + Assert.AreEqual("bar", ftask1.Result); + testbed.MustComplete(ftask2); + Assert.AreEqual("bar", ftask2.Result); + + // Now the cap should be released. + testbed.MustComplete(destructionTask); + } + } + + public static void Cancel(ITestbed testbed) + { + var destructionPromise = new TaskCompletionSource(); + var destructionTask = destructionPromise.Task; + + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + using (var cts = new CancellationTokenSource()) + { + var ntask = main.NeverReturn(new TestInterfaceImpl(counters, destructionPromise), cts.Token); + + // Allow some time to settle. + var cstask = main.GetCallSequence(0, default); + testbed.MustComplete(cstask); + Assert.AreEqual(1u, cstask.Result); + cstask = main.GetCallSequence(0, default); + testbed.MustComplete(cstask); + Assert.AreEqual(2u, cstask.Result); + + // The cap shouldn't have been destroyed yet because the call never returned. + Assert.IsFalse(destructionTask.IsCompleted); + + // There will be no automatic cancellation just because "ntask" goes of of scope or + // because the Proxy is disposed. Even ntask.Dispose() would not cancel the request. + // In .NET this needs to be done explicitly. + cts.Cancel(); + } + + // Now the cap should be released. + testbed.MustComplete(destructionTask); + } + + public static void RetainAndRelease(ITestbed testbed) + { + var destructionPromise = new TaskCompletionSource(); + var destructionTask = destructionPromise.Task; + + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var holdTask = main.Hold(new TestInterfaceImpl(new Counters(), destructionPromise), default); + testbed.MustComplete(holdTask); + + var cstask = main.GetCallSequence(0, default); + testbed.MustComplete(cstask); + Assert.AreEqual(1u, cstask.Result); + + Assert.IsFalse(destructionTask.IsCompleted); + + var htask = main.CallHeld(default); + testbed.MustComplete(htask); + Assert.AreEqual("bar", htask.Result); + + var gtask = main.GetHeld(default); + testbed.MustComplete(gtask); + // We can get the cap back from it. + using (var cap = gtask.Result) + { + // Wait for balanced state + testbed.FlushCommunication(); + + // And call it, without any network communications. + long oldSendCount = testbed.ClientSendCount; + var ftask = cap.Foo(123, true, default); + testbed.MustComplete(ftask); + Assert.AreEqual("foo", ftask.Result); + Assert.AreEqual(oldSendCount, testbed.ClientSendCount); + + // We can send another copy of the same cap to another method, and it works. + // Note that this was a bug in previous versions: + // Since passing a cap has move semantics, we need to create an explicit copy. + var copy = Proxy.Share(cap); + var ctask = main.CallFoo(copy, default); + testbed.MustComplete(ctask); + Assert.AreEqual("bar", ctask.Result); + + // Give some time to settle. + cstask = main.GetCallSequence(0, default); + testbed.MustComplete(cstask); + Assert.AreEqual(5u, cstask.Result); + cstask = main.GetCallSequence(0, default); + testbed.MustComplete(cstask); + Assert.AreEqual(6u, cstask.Result); + cstask = main.GetCallSequence(0, default); + testbed.MustComplete(cstask); + Assert.AreEqual(7u, cstask.Result); + + // Can't be destroyed, we haven't released it. + Assert.IsFalse(destructionTask.IsCompleted); + } + + // In deviation from original test, we have null the held capability on the main interface. + // This is because the main interface is the bootstrap capability and, as such, won't be disposed + // after disconnect. + var holdNullTask = main.Hold(null, default); + testbed.MustComplete(holdNullTask); + } + + testbed.MustComplete(destructionTask); + } + + public static void PromiseResolve(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var tcs = new TaskCompletionSource(); + var eager = tcs.Task.Eager(true); + + var request = main.CallFoo(eager, default); + var request2 = main.CallFooWhenResolved(eager, default); + + var gcs = main.GetCallSequence(0, default); + testbed.MustComplete(gcs); + Assert.AreEqual(2u, gcs.Result); + Assert.AreEqual(3, counters.CallCount); + + var chainedCallCount = new Counters(); + var tiimpl = new TestInterfaceImpl(chainedCallCount); + tcs.SetResult(tiimpl); + + testbed.MustComplete(request, request2); + + Assert.AreEqual("bar", request.Result); + Assert.AreEqual("bar", request2.Result); + Assert.AreEqual(3, counters.CallCount); + Assert.AreEqual(2, chainedCallCount.CallCount); + } + } + + public static void Cancelation(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var destroyed = new TaskCompletionSource(); + var impl2 = new TestInterfaceImpl(counters, destroyed); + var cts = new CancellationTokenSource(); + var cancelTask = main.ExpectCancel(impl2, cts.Token); + + testbed.MustNotComplete(destroyed.Task, cancelTask); + + cts.Cancel(); + + testbed.MustComplete(destroyed.Task); + Assert.IsFalse(cancelTask.IsCompleted && !cancelTask.IsCanceled); + } + } + + public static void ReleaseOnCancel(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + using (var cts = new CancellationTokenSource()) + { + var task = main.GetHandle(cts.Token); + testbed.MustComplete(Task.CompletedTask); // turn event loop + cts.Cancel(); + testbed.MustComplete(task); + try + { + task.Result.Dispose(); + } + catch (AggregateException ex) when (ex.InnerException is TaskCanceledException) + { + } + } + + testbed.FlushCommunication(); + Assert.AreEqual(0, counters.HandleCount); + } + } + + public static void Release(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var task1 = main.GetHandle(default); + var task2 = main.GetHandle(default); + testbed.MustComplete(task1, task2); + + Assert.AreEqual(2, counters.HandleCount); + + task1.Result.Dispose(); + + testbed.FlushCommunication(); + Assert.AreEqual(1, counters.HandleCount); + + task2.Result.Dispose(); + + testbed.FlushCommunication(); + Assert.AreEqual(0, counters.HandleCount); + } + } + + public static void Pipeline(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestPipelineImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var chainedCallCount = new Counters(); + var request = main.GetCap(234, new TestInterfaceImpl(chainedCallCount), default); + using (var outBox = request.OutBox_Cap()) + { + var pipelineRequest = outBox.Foo(321, false, default); + var pipelineRequest2 = ((Proxy)outBox).Cast(false).Grault(default); + + testbed.MustComplete(pipelineRequest, pipelineRequest2); + + Assert.AreEqual("bar", pipelineRequest.Result); + Common.CheckTestMessage(pipelineRequest2.Result); + + Assert.AreEqual(3, counters.CallCount); + Assert.AreEqual(1, chainedCallCount.CallCount); + } + } + } + + public static void Basic(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestInterfaceImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var request1 = main.Foo(123, true, default); + var request3 = Assert.ThrowsExceptionAsync(() => main.Bar(default)); + var s = new TestAllTypes(); + Common.InitTestMessage(s); + var request2 = main.Baz(s, default); + + testbed.MustComplete(request1, request2, request3); + + Assert.AreEqual("foo", request1.Result); + Assert.AreEqual(2, counters.CallCount); + } + } + } +} diff --git a/Capnp.Net.Runtime.Tests/Util/DecisionTree.cs b/Capnp.Net.Runtime.Tests/Util/DecisionTree.cs new file mode 100644 index 0000000..038e95f --- /dev/null +++ b/Capnp.Net.Runtime.Tests/Util/DecisionTree.cs @@ -0,0 +1,98 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; + +namespace Capnp.Net.Runtime.Tests +{ + public class DecisionTree + { + readonly ILogger Logger = Logging.CreateLogger(); + + readonly List _decisions = new List(); + readonly Stack _freezeStack = new Stack(); + int _pos, _freezeCounter; + + public DecisionTree() + { + _freezeStack.Push(0); + } + + public DecisionTree(params bool[] initialDecisions): this() + { + _decisions.AddRange(initialDecisions); + } + + public bool MakeDecision() + { + if (_pos >= _decisions.Count) + { + _decisions.Add(false); + } + + try + { + return _decisions[_pos++]; + } + catch (ArgumentOutOfRangeException) + { + Logger.LogError($"WTF?! {_pos - 1}, {_decisions.Count}"); + throw; + } + } + + public void Freeze() + { + _freezeStack.Push(_pos); + } + + public bool NextRound() + { + _pos = 0; + + for (int i = 0; i < _freezeCounter; i++) + _freezeStack.Pop(); + + while (_freezeStack.Count > 1) + { + int end = _freezeStack.Pop(); + int begin = _freezeStack.Peek(); + + for (int i = end - 1; i >= begin; i--) + { + if (_decisions[i] == false) + { + _decisions[i] = true; + _freezeStack.Clear(); + _freezeStack.Push(0); + return true; + } + //else + //{ + // _decisions.RemoveAt(i); + //} + } + + ++_freezeCounter; + } + + return false; + } + + public override string ToString() + { + return "[" + string.Join("|", _decisions) + "]"; + } + + public void Iterate(Action testMethod) + { + Logger.LogInformation("Starting decision-tree based combinatorial test"); + int iter = 0; + do + { + Logger.LogInformation($"Iteration {iter}: pattern {ToString()}"); + testMethod(); + ++iter; + } while (NextRound()); + } + } +} diff --git a/Capnp.Net.Runtime.Tests/JobUtil.cs b/Capnp.Net.Runtime.Tests/Util/JobUtil.cs similarity index 100% rename from Capnp.Net.Runtime.Tests/JobUtil.cs rename to Capnp.Net.Runtime.Tests/Util/JobUtil.cs diff --git a/Capnp.Net.Runtime.Tests/ScatteringStream.cs b/Capnp.Net.Runtime.Tests/Util/ScatteringStream.cs similarity index 100% rename from Capnp.Net.Runtime.Tests/ScatteringStream.cs rename to Capnp.Net.Runtime.Tests/Util/ScatteringStream.cs diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs new file mode 100644 index 0000000..b64377f --- /dev/null +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -0,0 +1,350 @@ +using Capnp.Rpc; +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Capnp.Net.Runtime.Tests +{ + public interface ITestbed + { + T ConnectMain(T main) where T : class; + void MustComplete(params Task[] tasks); + void MustNotComplete(params Task[] tasks); + void FlushCommunication(); + + long ClientSendCount { get; } + } + + public interface ITestController + { + void RunTest(Action action); + } + + public class TestBase + { + + protected class EnginePair + { + class EngineChannel : IEndpoint + { + readonly Queue _frameBuffer = new Queue(); + readonly Func _decide; + bool _recursion; + bool _dismissed; + + public EngineChannel(Func decide) + { + _decide = decide; + } + + public RpcEngine.RpcEndpoint OtherEndpoint { get; set; } + public bool HasBufferedFrames => _frameBuffer.Count > 0; + public int FrameCounter { get; private set; } + + + public void Dismiss() + { + OtherEndpoint.Dismiss(); + _dismissed = true; + } + + public void Forward(WireFrame frame) + { + if (_dismissed) + return; + + ++FrameCounter; + + if (_recursion || _frameBuffer.Count > 0 || _decide()) + { + _frameBuffer.Enqueue(frame); + } + else + { + _recursion = true; + OtherEndpoint.Forward(frame); + _recursion = false; + } + } + + public bool Flush() + { + if (_frameBuffer.Count > 0) + { + var frame = _frameBuffer.Dequeue(); + _recursion = true; + OtherEndpoint.Forward(frame); + _recursion = false; + + return true; + } + else + { + return false; + } + } + } + + readonly DecisionTree _decisionTree; + readonly EngineChannel _channel1, _channel2; + + public RpcEngine Engine1 { get; } + public RpcEngine Engine2 { get; } + public RpcEngine.RpcEndpoint Endpoint1 { get; } + public RpcEngine.RpcEndpoint Endpoint2 { get; } + + public EnginePair(DecisionTree decisionTree) + { + _decisionTree = decisionTree; + Engine1 = new RpcEngine(); + Engine2 = new RpcEngine(); + _channel1 = new EngineChannel(decisionTree.MakeDecision); + Endpoint1 = Engine1.AddEndpoint(_channel1); + _channel2 = new EngineChannel(() => false); + Endpoint2 = Engine2.AddEndpoint(_channel2); + _channel1.OtherEndpoint = Endpoint2; + _channel2.OtherEndpoint = Endpoint1; + } + + public void FlushChannels(Func pred) + { + while (!pred()) + { + if (!_channel1.Flush() && + !_channel2.Flush()) + return; + } + + while ((_channel1.HasBufferedFrames || _channel2.HasBufferedFrames) && _decisionTree.MakeDecision()) + { + if (_channel1.HasBufferedFrames) + { + int mark = _channel2.FrameCounter; + + while (_channel1.Flush() && _channel2.FrameCounter == mark) + ; + } + else if (_channel2.HasBufferedFrames) + { + int mark = _channel1.FrameCounter; + + while (_channel2.Flush() && _channel1.FrameCounter == mark) + ; + } + + } + } + + public int Channel1SendCount => _channel1.FrameCounter; + public int Channel2SendCount => _channel2.FrameCounter; + } + + protected class DtbdctTestbed : ITestbed, ITestController + { + readonly DecisionTree _decisionTree = new DecisionTree(); + EnginePair _enginePair; + + public void RunTest(Action action) + { + _decisionTree.Iterate(() => action(this)); + } + + T ITestbed.ConnectMain(T main) + { + return SetupEnginePair(main, _decisionTree, out _enginePair); + } + + void ITestbed.MustComplete(params Task[] tasks) + { + bool AllDone() => tasks.All(t => t.IsCompleted); + _enginePair.FlushChannels(AllDone); + _decisionTree.Freeze(); + Assert.IsTrue(AllDone()); + } + + void ITestbed.MustNotComplete(params Task[] tasks) + { + Assert.IsFalse(tasks.Any(t => t.IsCompleted)); + } + + void ITestbed.FlushCommunication() + { + _enginePair.FlushChannels(() => false); + } + + long ITestbed.ClientSendCount => _enginePair.Channel2SendCount; + } + + protected class LocalhostTcpTestbed : ITestbed, ITestController + { + TcpRpcServer _server; + TcpRpcClient _client; + + public void RunTest(Action action) + { + (_server, _client) = SetupClientServerPair(); + _client.WhenConnected.Wait(MediumNonDbgTimeout); + + using (_server) + using (_client) + { + action(this); + } + } + + T ITestbed.ConnectMain(T main) + { + _server.Main = main; + return _client.GetMain(); + } + + void ITestbed.MustComplete(params Task[] tasks) + { + Assert.IsTrue(Task.WaitAll(tasks, MediumNonDbgTimeout)); + } + + void ITestbed.MustNotComplete(params Task[] tasks) + { + Assert.AreEqual(-1, Task.WaitAny(tasks, ShortTimeout)); + } + + void ITestbed.FlushCommunication() + { + WaitClientServerIdle(_server, _client); + } + + long ITestbed.ClientSendCount => _client.SendCount; + } + + public static int TcpPort = 49152; + public static int MediumNonDbgTimeout => Debugger.IsAttached ? Timeout.Infinite : 5000; + public static int LargeNonDbgTimeout => Debugger.IsAttached ? Timeout.Infinite : 20000; + public static int ShortTimeout => 500; + + protected ILogger Logger { get; set; } + + protected static TcpRpcClient SetupClient() + { + var client = new TcpRpcClient(); + client.AddBuffering(); + client.Connect("localhost", TcpPort); + return client; + } + + protected static TcpRpcServer SetupServer() + { + int attempt = 0; + + while (true) + { + try + { + var server = new TcpRpcServer(IPAddress.Any, TcpPort); + server.AddBuffering(); + return server; + } + catch (SocketException) + { + // If the TCP listening port is occupied by some other process, retry with a different one + // TIME_WAIT is 4min: http://blog.davidvassallo.me/2010/07/13/time_wait-and-port-reuse/ + if (attempt == 2400) + throw; + } + + IncrementTcpPort(); + ++attempt; + Thread.Sleep(100); + } + } + + protected static (TcpRpcServer, TcpRpcClient) SetupClientServerPair() + { + var server = SetupServer(); + var client = SetupClient(); + return (server, client); + } + + protected static T SetupEnginePair(T main, DecisionTree decisionTree, out EnginePair pair) where T: class + { + pair = new EnginePair(decisionTree); + pair.Engine1.Main = main; + return (CapabilityReflection.CreateProxy(pair.Endpoint2.QueryMain()) as T); + } + + public static void IncrementTcpPort() + { + if (++TcpPort > 49200) + { + TcpPort = 49152; + } + } + + protected static DtbdctTestbed NewDtbdctTestbed() => new DtbdctTestbed(); + protected static LocalhostTcpTestbed NewLocalhostTcpTestbed() => new LocalhostTcpTestbed(); + + [TestInitialize] + public void InitConsoleLogging() + { + Logging.LoggerFactory?.Dispose(); + Logging.LoggerFactory = new LoggerFactory().AddConsole((msg, level) => true); + Logger = Logging.CreateLogger(); + if (Thread.CurrentThread.Name == null) + Thread.CurrentThread.Name = $"Test Thread {Thread.CurrentThread.ManagedThreadId}"; + } + + /// + /// Somewhat ugly helper method which ensures that both Tcp client and server + /// are waiting for data reception from each other. This is a "balanced" state, meaning + /// that nothing will ever happen in the RcpEngines without some other thread requesting + /// anything. + /// + static protected void WaitClientServerIdle(TcpRpcServer server, TcpRpcClient client) + { + var conn = server.Connections[0]; + SpinWait.SpinUntil(() => conn.IsWaitingForData && client.IsWaitingForData && + conn.RecvCount == client.SendCount && + conn.SendCount == client.RecvCount, + MediumNonDbgTimeout); + } + + protected void ExpectPromiseThrows(Task task) + { + async Task ExpectPromiseThrowsAsync(Task t) + { + try + { + await t; + Assert.Fail("Did not throw"); + } + catch (InvalidOperationException) + { + // Happens if the call went to the resolution + // (thus, locally). In this case, the original + // exception is routed here. + } + catch (RpcException) + { + // Happens if the call went to the promise + // (thus, remotely). In this case, the original + // exception had to be serialized, so we receive + // the wrapped version. + } + catch (System.Exception exception) + { + Assert.Fail($"Got wrong kind of exception: {exception}"); + } + } + + Assert.IsTrue(ExpectPromiseThrowsAsync(task).Wait(MediumNonDbgTimeout)); + } + + } +} diff --git a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj index af2c400..6f81750 100644 --- a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj +++ b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj @@ -29,7 +29,7 @@ - DebugCapabilityLifecycle + DebugFinalizers diff --git a/Capnp.Net.Runtime/CapnpSerializable.cs b/Capnp.Net.Runtime/CapnpSerializable.cs index 9f33940..ec7cb48 100644 --- a/Capnp.Net.Runtime/CapnpSerializable.cs +++ b/Capnp.Net.Runtime/CapnpSerializable.cs @@ -160,6 +160,7 @@ namespace Capnp /// The domain object instance. Nullability note: The returned reference may be null if /// represents the nil object. /// Cannot construct object of type + /// Note that capability ownership is moved to the domain object public static T? Create(DeserializerState state) where T: class { diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs index b420725..ea02416 100644 --- a/Capnp.Net.Runtime/DeserializerState.cs +++ b/Capnp.Net.Runtime/DeserializerState.cs @@ -9,7 +9,7 @@ namespace Capnp /// Although it is public, you should not use it directly. Instead, use the reader, writer, and domain class adapters which are produced /// by the code generator. /// - public struct DeserializerState: IStructDeserializer + public struct DeserializerState: IStructDeserializer, IDisposable { /// /// A wire message is essentially a collection of memory blocks. @@ -50,7 +50,7 @@ namespace Capnp /// public IList? Caps { get; set; } /// - /// Current segment (essentially Segments[CurrentSegmentIndex] + /// Current segment (essentially Segments[CurrentSegmentIndex]) /// public ReadOnlySpan CurrentSegment => Segments != null ? Segments[(int)CurrentSegmentIndex].Span : default; @@ -106,11 +106,6 @@ namespace Capnp case ObjectKind.ListOfStructs: case ObjectKind.Nil: case ObjectKind.Struct: - if (state.Caps != null) - { - foreach (var cap in state.Caps) - cap?.Release(true); - } return new DeserializerState(state.Allocator!.Segments) { CurrentSegmentIndex = state.SegmentIndex, @@ -646,13 +641,10 @@ namespace Capnp /// negative index /// state does not represent a struct, invalid pointer, /// non-capability pointer, traversal limit exceeded - public T? ReadCap(int index, - [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", - [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", - [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) where T: class + public T? ReadCap(int index) where T: class { var cap = StructReadRawCap(index); - return Rpc.CapabilityReflection.CreateProxy(cap, memberName, sourceFilePath, sourceLineNumber) as T; + return Rpc.CapabilityReflection.CreateProxy(cap) as T; } /// @@ -690,5 +682,16 @@ namespace Capnp return (Rpc.CapabilityReflection.CreateProxy(Caps[(int)CapabilityIndex]) as T)!; } + + public void Dispose() + { + if (Caps != null) + { + foreach (var cap in Caps) + { + cap?.Release(false); + } + } + } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/DynamicSerializerState.cs b/Capnp.Net.Runtime/DynamicSerializerState.cs index edf3d15..fe750d9 100644 --- a/Capnp.Net.Runtime/DynamicSerializerState.cs +++ b/Capnp.Net.Runtime/DynamicSerializerState.cs @@ -44,8 +44,6 @@ namespace Capnp if (state.Caps != null) { mb.InitCapTable(); - foreach (var cap in state.Caps) - cap?.AddRef(); } var sstate = mb.CreateObject(); Reserializing.DeepCopy(state, sstate); diff --git a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs index 42ae7ca..6e10a58 100644 --- a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs +++ b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs @@ -262,25 +262,11 @@ namespace Capnp.Rpc /// Problem with instatiating the Proxy (constructor threw exception). /// Caller does not have permission to invoke the Proxy constructor. /// Problem with building the Proxy type, or problem with loading some dependent class. - public static Proxy CreateProxy(ConsumedCapability? cap, - [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", - [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", - [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) + public static Proxy CreateProxy(ConsumedCapability? cap) { var factory = GetProxyFactory(typeof(TInterface)); var proxy = factory.NewProxy(); proxy.Bind(cap); -#if DebugFinalizers - proxy.CreatorMemberName = memberName; - proxy.CreatorFilePath = sourceFilePath; - proxy.CreatorLineNumber = sourceLineNumber; - if (cap != null) - { - cap.CreatorFilePath = proxy.CreatorFilePath; - cap.CreatorLineNumber = proxy.CreatorLineNumber; - cap.CreatorMemberName = proxy.CreatorMemberName; - } -#endif return proxy; } } diff --git a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs index 1204fa0..4342b84 100644 --- a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs @@ -1,4 +1,6 @@ -namespace Capnp.Rpc +using System; + +namespace Capnp.Rpc { /// /// Base class for a low-level capability at consumer side. It is created by the . An application does not directly interact with it @@ -13,7 +15,7 @@ /// which usually also means to remove it from the remote peer's export table. /// protected abstract void ReleaseRemotely(); - internal abstract void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer); + internal abstract Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer); internal abstract void Freeze(out IRpcEndpoint? boundEndpoint); internal abstract void Unfreeze(); @@ -23,11 +25,5 @@ [System.Runtime.CompilerServices.CallerMemberName] string methodName = "", [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0); - -#if DebugFinalizers - public string CreatorMemberName { get; set; } - public string CreatorFilePath { get; set; } - public int CreatorLineNumber { get; set; } -#endif } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs index 7b774f8..6fc1788 100644 --- a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs @@ -24,6 +24,6 @@ namespace Capnp.Rpc /// Pipelined low-level capability ConsumedCapability? Access(MemberAccessPath access); - ConsumedCapability? Access(MemberAccessPath access, Task proxyTask); + ConsumedCapability? Access(MemberAccessPath access, Task proxyTask); } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/IRpcEndpoint.cs b/Capnp.Net.Runtime/Rpc/IRpcEndpoint.cs index 339ec26..fccfc6c 100644 --- a/Capnp.Net.Runtime/Rpc/IRpcEndpoint.cs +++ b/Capnp.Net.Runtime/Rpc/IRpcEndpoint.cs @@ -8,7 +8,6 @@ namespace Capnp.Rpc PendingQuestion BeginQuestion(ConsumedCapability target, SerializerState inParams); void SendQuestion(SerializerState inParams, Payload.WRITER payload); uint AllocateExport(Skeleton providedCapability, out bool first); - void RequestPostAction(Action postAction); void Finish(uint questionId); void ReleaseImport(uint importId); void Resolve(uint preliminaryId, Skeleton preliminaryCap, Func resolvedCapGetter); diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index 1a0a81e..b07e5ba 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -94,7 +94,20 @@ namespace Capnp.Rpc static async Task AwaitProxy(Task task) where T: class { - var item = await task; + T item; + + try + { + item = await task; + } + catch (TaskCanceledException exception) + { + return new Proxy(LazyCapability.CreateCanceledCap(exception.CancellationToken)); + } + catch (System.Exception exception) + { + return new Proxy(LazyCapability.CreateBrokenCap(exception.Message)); + } switch (item) { @@ -124,14 +137,11 @@ namespace Capnp.Rpc /// did not /// quality as capability interface. [Obsolete("Call Eager(task, true) instead")] - public static TInterface PseudoEager(this Task task, - [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", - [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", - [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) + public static TInterface PseudoEager(this Task task) where TInterface : class { var lazyCap = new LazyCapability(AwaitProxy(task)); - return (CapabilityReflection.CreateProxy(lazyCap, memberName, sourceFilePath, sourceLineNumber) as TInterface)!; + return (CapabilityReflection.CreateProxy(lazyCap) as TInterface)!; } static readonly MemberAccessPath Path_OneAndOnly = new MemberAccessPath(0U); @@ -157,7 +167,7 @@ namespace Capnp.Rpc /// Caller does not have permission to invoke the Proxy constructor. /// Problem with building the Proxy type, or problem with loading some dependent class. public static TInterface Eager(this Task task, bool allowNoPipeliningFallback = false) - where TInterface : class + where TInterface : class, IDisposable { var answer = TryGetAnswer(task); if (answer == null) @@ -172,7 +182,12 @@ namespace Capnp.Rpc } else { - return (CapabilityReflection.CreateProxy(answer.Access(Path_OneAndOnly)) as TInterface)!; + async Task AsDisposableTask() + { + return await task; + } + + return (CapabilityReflection.CreateProxy(answer.Access(Path_OneAndOnly, AsDisposableTask())) as TInterface)!; } } diff --git a/Capnp.Net.Runtime/Rpc/ImportedCapability.cs b/Capnp.Net.Runtime/Rpc/ImportedCapability.cs index 9645022..5564351 100644 --- a/Capnp.Net.Runtime/Rpc/ImportedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/ImportedCapability.cs @@ -1,4 +1,6 @@ -namespace Capnp.Rpc +using System; + +namespace Capnp.Rpc { /// /// Low-level capability which as imported from a remote peer. @@ -35,7 +37,7 @@ { } - internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER capDesc) + internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER capDesc) { if (endpoint == _ep) { @@ -47,6 +49,7 @@ capDesc.which = CapDescriptor.WHICH.SenderHosted; capDesc.SenderHosted = endpoint.AllocateExport(Vine.Create(this), out var _); } + return null; } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs index 36b95d6..018d865 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs @@ -50,7 +50,7 @@ namespace Capnp.Rpc.Interception } } - public ConsumedCapability? Access(MemberAccessPath _, Task task) + public ConsumedCapability? Access(MemberAccessPath _, Task task) { var proxyTask = task.AsProxyTask(); diff --git a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs index bd66f9b..3323c16 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs @@ -1,4 +1,6 @@ -namespace Capnp.Rpc.Interception +using System; + +namespace Capnp.Rpc.Interception { class CensorCapability : RefCountingCapability { @@ -26,10 +28,11 @@ return cc.Answer; } - internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) + internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { writer.which = CapDescriptor.WHICH.SenderHosted; writer.SenderHosted = endpoint.AllocateExport(MyVine, out bool _); + return null; } internal override void Freeze(out IRpcEndpoint? boundEndpoint) diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index d56297c..2c06584 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -8,19 +8,15 @@ namespace Capnp.Rpc { public static LazyCapability CreateBrokenCap(string message) { - var cap = new LazyCapability(Task.FromException(new RpcException(message))); - cap.AddRef(); // Instance shall be persistent - return cap; + return new LazyCapability(Task.FromException(new RpcException(message))); } public static LazyCapability CreateCanceledCap(CancellationToken token) { - var cap = new LazyCapability(Task.FromCanceled(token)); - cap.AddRef(); // Instance shall be persistent - return cap; + return new LazyCapability(Task.FromCanceled(token)); } - public static LazyCapability Null { get; } = CreateBrokenCap("Null capability"); + public static LazyCapability Null => CreateBrokenCap("Null capability"); readonly Task? _proxyTask; @@ -63,16 +59,17 @@ namespace Capnp.Rpc { } - internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) + internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { if (WhenResolved.ReplacementTaskIsCompletedSuccessfully()) { using var proxy = new Proxy(WhenResolved.Result); proxy.Export(endpoint, writer); + return null; } else { - this.ExportAsSenderPromise(endpoint, writer); + return this.ExportAsSenderPromise(endpoint, writer); } } diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswer.cs b/Capnp.Net.Runtime/Rpc/LocalAnswer.cs index a90166f..f88e27b 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswer.cs @@ -30,7 +30,7 @@ namespace Capnp.Rpc return new LocalAnswerCapabilityDeprecated(WhenReturned, access); } - public ConsumedCapability Access(MemberAccessPath _, Task task) + public ConsumedCapability Access(MemberAccessPath _, Task task) { return new LocalAnswerCapability(task.AsProxyTask()); } diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs index fdd8ad4..9d6093e 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs @@ -29,7 +29,7 @@ namespace Capnp.Rpc public Task WhenResolved { get; private set; } - internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) + internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { if (_whenResolvedProxy.IsCompleted) { @@ -39,12 +39,14 @@ namespace Capnp.Rpc } catch (AggregateException exception) { - throw exception.InnerException; + throw exception.InnerException!; } + + return null; } else { - this.ExportAsSenderPromise(endpoint, writer); + return this.ExportAsSenderPromise(endpoint, writer); } } diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs index f78788d..3688638 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs @@ -30,7 +30,7 @@ namespace Capnp.Rpc public Task WhenResolved { get; private set; } - internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) + internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { if (_answer.IsCompleted) { @@ -46,10 +46,11 @@ namespace Capnp.Rpc using var proxy = new Proxy(_access.Eval(result)); proxy.Export(endpoint, writer); + return null; } else { - this.ExportAsSenderPromise(endpoint, writer); + return this.ExportAsSenderPromise(endpoint, writer); } } diff --git a/Capnp.Net.Runtime/Rpc/LocalCapability.cs b/Capnp.Net.Runtime/Rpc/LocalCapability.cs index d0dc90f..5ae7c91 100644 --- a/Capnp.Net.Runtime/Rpc/LocalCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalCapability.cs @@ -54,10 +54,11 @@ namespace Capnp.Rpc return new LocalAnswer(cts, AwaitAnswer(call)); } - internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER capDesc) + internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER capDesc) { capDesc.which = CapDescriptor.WHICH.SenderHosted; capDesc.SenderHosted = endpoint.AllocateExport(ProvidedCap, out bool _); + return null; } internal override void Freeze(out IRpcEndpoint? boundEndpoint) diff --git a/Capnp.Net.Runtime/Rpc/MemberAccessPath.cs b/Capnp.Net.Runtime/Rpc/MemberAccessPath.cs index 4843c08..3b4cf20 100644 --- a/Capnp.Net.Runtime/Rpc/MemberAccessPath.cs +++ b/Capnp.Net.Runtime/Rpc/MemberAccessPath.cs @@ -132,7 +132,7 @@ namespace Capnp.Rpc { if (state.Kind == ObjectKind.Nil) { - return default(DeserializerState); + return default; } if (state.Kind != ObjectKind.Struct) diff --git a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs index ed51a34..3b4bc38 100644 --- a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs @@ -24,11 +24,35 @@ namespace Capnp.Rpc _cts = cts; _cancelCompleter = new TaskCompletionSource(); _answerTask = CancelableAwaitWhenReady(); + + Chain(async t => + { + var aorcq = default(AnswerOrCounterquestion); + + try + { + aorcq = await t; + } + catch + { + } + + if (aorcq.Answer != null) + { + if (aorcq.Answer.Caps != null) + { + foreach (var cap in aorcq.Answer.Caps) + { + cap?.AddRef(); + } + } + } + }); } public CancellationToken CancellationToken => _cts?.Token ?? CancellationToken.None; - public IReadOnlyList CapTable { get; set; } + public IReadOnlyList? CapTable { get; set; } public void Cancel() { @@ -99,7 +123,7 @@ namespace Capnp.Rpc else { var path = MemberAccessPath.Deserialize(rd); - var cap = new RemoteAnswerCapabilityDeprecated(aorcq.Counterquestion!, path); + var cap = new RemoteAnswerCapability(aorcq.Counterquestion!, path); return new Proxy(cap); } } @@ -111,6 +135,31 @@ namespace Capnp.Rpc public void Dispose() { _cts?.Dispose(); + + Chain(async t => + { + AnswerOrCounterquestion aorcq; + + try + { + aorcq = await t; + } + catch + { + return; + } + + if (aorcq.Answer != null) + { + if (aorcq.Answer.Caps != null) + { + foreach (var cap in aorcq.Answer.Caps) + { + cap?.Release(false); + } + } + } + }); } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index cf7a900..dcdd7be 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -126,17 +126,17 @@ namespace Capnp.Rpc lock (ReentrancyBlocker) { SetReturned(); - } - if (StateFlags.HasFlag(State.TailCall)) - { - _tcs.TrySetException(new RpcException(ReturnDespiteTailCallMessage)); - } - else - { - if (!_tcs.TrySetResult(results)) + if (StateFlags.HasFlag(State.TailCall)) { - ReleaseOutCaps(results); + _tcs.TrySetException(new RpcException(ReturnDespiteTailCallMessage)); + } + else + { + if (!_tcs.TrySetResult(results)) + { + ReleaseOutCaps(results); + } } } } @@ -146,15 +146,15 @@ namespace Capnp.Rpc lock (ReentrancyBlocker) { SetReturned(); - } - if (!StateFlags.HasFlag(State.TailCall)) - { - _tcs.TrySetException(new RpcException("Peer sent the results of this questions somewhere else. This was not expected and is a protocol error.")); - } - else - { - _tcs.TrySetResult(default); + if (!StateFlags.HasFlag(State.TailCall)) + { + _tcs.TrySetException(new RpcException("Peer sent the results of this questions somewhere else. This was not expected and is a protocol error.")); + } + else + { + _tcs.TrySetResult(default); + } } } @@ -163,9 +163,9 @@ namespace Capnp.Rpc lock (ReentrancyBlocker) { SetReturned(); - } - _tcs.TrySetException(new RpcException(exception.Reason)); + _tcs.TrySetException(new RpcException(exception.Reason)); + } } internal void OnException(System.Exception exception) @@ -173,9 +173,9 @@ namespace Capnp.Rpc lock (ReentrancyBlocker) { SetReturned(); - } - _tcs.TrySetException(exception); + _tcs.TrySetException(exception); + } } internal void OnCanceled() @@ -183,9 +183,9 @@ namespace Capnp.Rpc lock (ReentrancyBlocker) { SetReturned(); - } - _tcs.TrySetCanceled(); + _tcs.TrySetCanceled(); + } } void DeleteMyQuestion() @@ -234,6 +234,7 @@ namespace Capnp.Rpc /// Access path /// Low-level capability /// The referenced member does not exist or does not resolve to a capability pointer. + [Obsolete("Please re-generate. Replaced by Access(MemberAccessPath access, Task task)")] public ConsumedCapability? Access(MemberAccessPath access) { lock (ReentrancyBlocker) @@ -252,7 +253,7 @@ namespace Capnp.Rpc } else { - return new RemoteAnswerCapabilityDeprecated(this, access); + return new RemoteAnswerCapability(this, access); } } } @@ -261,32 +262,14 @@ namespace Capnp.Rpc /// Refer to a (possibly nested) member of this question's (possibly future) result and return /// it as a capability. /// + /// Access path /// promises the cap whose ownership is transferred to this object /// Low-level capability /// The referenced member does not exist or does not resolve to a capability pointer. - public ConsumedCapability? Access(MemberAccessPath access, Task task) + public ConsumedCapability? Access(MemberAccessPath access, Task task) { var proxyTask = task.AsProxyTask(); - - lock (ReentrancyBlocker) - { - if (proxyTask.IsCompleted && !StateFlags.HasFlag(State.TailCall)) - { - try - { - using var proxy = proxyTask.Result; - return proxy.ConsumedCap; - } - catch (AggregateException exception) - { - throw exception.InnerException!; - } - } - else - { - return new RemoteAnswerCapabilityDeprecated(this, access); - } - } + return new RemoteAnswerCapability(this, access, proxyTask); } static void ReleaseCaps(ConsumedCapability? target, SerializerState? inParams) diff --git a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs index 27a23f4..ec9a97b 100644 --- a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs @@ -78,7 +78,7 @@ namespace Capnp.Rpc } } - internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) + internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { lock (_reentrancyBlocker) { @@ -98,7 +98,7 @@ namespace Capnp.Rpc Debug.Assert(!_released); ++_pendingCallsOnPromise; - _ep.RequestPostAction(() => + return () => { bool release = false; @@ -115,7 +115,7 @@ namespace Capnp.Rpc { _ep.ReleaseImport(_remoteId); } - }); + }; } else { @@ -123,6 +123,8 @@ namespace Capnp.Rpc } } } + + return null; } async void TrackCall(Task call) diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index 18ab5f4..1d6c9e0 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Extensions.Logging; +using System; using System.Threading; using System.Threading.Tasks; @@ -99,9 +100,12 @@ namespace Capnp.Rpc /// public Proxy() { +#if DebugFinalizers + CreatorStackTrace = Environment.StackTrace; +#endif } - internal Proxy(ConsumedCapability? cap) + internal Proxy(ConsumedCapability? cap): this() { Bind(cap); } @@ -118,7 +122,7 @@ namespace Capnp.Rpc cap.AddRef(); } - internal IProvidedCapability? GetProvider() + internal Skeleton? GetProvider() { switch (ConsumedCap) { @@ -163,7 +167,7 @@ namespace Capnp.Rpc ~Proxy() { #if DebugFinalizers - Logger.LogWarning($"Caught orphaned Proxy, created from {CreatorMemberName} in {CreatorFilePath}, line {CreatorLineNumber}."); + Logger.LogWarning($"Caught orphaned Proxy, created from here: {CreatorStackTrace}."); #endif Dispose(false); @@ -230,9 +234,7 @@ namespace Capnp.Rpc } #if DebugFinalizers - public string CreatorMemberName { get; set; } - public string CreatorFilePath { get; set; } - public int CreatorLineNumber { get; set; } + string CreatorStackTrace { get; set; } #endif } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs index 240fc9e..b6beae8 100644 --- a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs @@ -26,16 +26,33 @@ namespace Capnp.Rpc // Value 0 has the special meaning of being in state C. long _refCount = 1; -#if DebugCapabilityLifecycle +#if DebugCapabilityLifecycle || DebugFinalizers ILogger Logger { get; } = Logging.CreateLogger(); +#endif +#if DebugCapabilityLifecycle string? _releasingMethodName; string? _releasingFilePath; int _releasingLineNumber; #endif +#if DebugFinalizers + string CreatorStackTrace { get; set; } +#endif + + public RefCountingCapability() + { +#if DebugFinalizers + CreatorStackTrace = Environment.StackTrace; +#endif + } + ~RefCountingCapability() { +#if DebugFinalizers + Logger.LogWarning($"Caught orphaned capability, created from here: {CreatorStackTrace}."); +#endif + Dispose(false); } diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index 328e8e3..8423581 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -37,6 +37,19 @@ namespace Capnp.Rpc WhenResolved = AwaitWhenResolved(); } + static async Task TransferOwnershipToDummyProxy(PendingQuestion question, MemberAccessPath access) + { + var result = await question.WhenReturned; + var cap = access.Eval(result); + var proxy = new Proxy(cap); + cap?.Release(false); + return proxy; + } + + public RemoteAnswerCapability(PendingQuestion question, MemberAccessPath access) : this(question, access, TransferOwnershipToDummyProxy(question, access)) + { + } + async void ReAllowFinishWhenDone(Task task) { try @@ -64,7 +77,7 @@ namespace Capnp.Rpc { lock (_question.ReentrancyBlocker) { - if (!_question.IsTailCall && WhenResolved.IsCompleted) + if (!_question.IsTailCall && _question.StateFlags.HasFlag(PendingQuestion.State.Returned)) { try { @@ -96,8 +109,8 @@ namespace Capnp.Rpc { lock (_question.ReentrancyBlocker) { - if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned) && - !_question.StateFlags.HasFlag(PendingQuestion.State.TailCall)) + if (!_question.StateFlags.HasFlag(PendingQuestion.State.TailCall) && + _question.StateFlags.HasFlag(PendingQuestion.State.Returned)) { if (ResolvedCap == null) { @@ -165,8 +178,9 @@ namespace Capnp.Rpc { lock (_question.ReentrancyBlocker) { - if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned) && - _pendingCallsOnPromise == 0) + if ( _question.StateFlags.HasFlag(PendingQuestion.State.Returned) && + !_question.StateFlags.HasFlag(PendingQuestion.State.TailCall) && + _pendingCallsOnPromise == 0) { if (ResolvedCap == null) { @@ -200,7 +214,7 @@ namespace Capnp.Rpc } } - internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) + internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { lock (_question.ReentrancyBlocker) { @@ -236,10 +250,12 @@ namespace Capnp.Rpc } else { - this.ExportAsSenderPromise(endpoint, writer); + return this.ExportAsSenderPromise(endpoint, writer); } } } + + return null; } protected async override void ReleaseRemotely() diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs index 51e8ee5..f950659 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; namespace Capnp.Rpc { +#if false class RemoteAnswerCapabilityDeprecated : RemoteResolvingCapability { @@ -17,7 +18,6 @@ namespace Capnp.Rpc readonly PendingQuestion _question; readonly MemberAccessPath _access; - readonly Task _whenResolvedProxy; ConsumedCapability? _resolvedCap; public RemoteAnswerCapabilityDeprecated(PendingQuestion question, MemberAccessPath access): base(question.RpcEndpoint) @@ -36,9 +36,6 @@ namespace Capnp.Rpc } WhenResolved = AwaitWhenResolved(); - - async Task AwaitProxy() => new Proxy(await WhenResolved); - _whenResolvedProxy = AwaitProxy(); } async void ReAllowFinishWhenDone(Task task) @@ -62,16 +59,6 @@ namespace Capnp.Rpc } } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - lock (_question.ReentrancyBlocker) - { - using var _ = new Proxy(_resolvedCap); - } - } - protected override ConsumedCapability? ResolvedCap { get @@ -258,8 +245,9 @@ namespace Capnp.Rpc protected async override void ReleaseRemotely() { - try { using var _ = await _whenResolvedProxy; } + try { (await WhenResolved)?.Release(false); } catch { } } } +#endif } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs index 36d0ae2..ade7ee8 100644 --- a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs @@ -5,7 +5,7 @@ namespace Capnp.Rpc { static class ResolvingCapabilityExtensions { - public static void ExportAsSenderPromise(this T cap, IRpcEndpoint endpoint, CapDescriptor.WRITER writer) + public static Action? ExportAsSenderPromise(this T cap, IRpcEndpoint endpoint, CapDescriptor.WRITER writer) where T: ConsumedCapability, IResolvingCapability { var vine = Vine.Create(cap); @@ -16,7 +16,7 @@ namespace Capnp.Rpc if (first) { - endpoint.RequestPostAction(async () => { + return async () => { try { @@ -28,14 +28,21 @@ namespace Capnp.Rpc endpoint.Resolve(preliminaryId, vine, () => throw exception); } - }); + }; } + + return null; } - public static async Task AsProxyTask(this Task task) + public static async Task AsProxyTask(this Task task) { var obj = await task; - return obj is Proxy proxy ? proxy : BareProxy.FromImpl(obj); + switch (obj) + { + case Proxy proxy: return proxy; + case null: return new Proxy(LazyCapability.Null); + default: return BareProxy.FromImpl(obj); + } } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 0b1ad55..74ffc4b 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -68,7 +68,6 @@ namespace Capnp.Rpc Dismissed } - static readonly ThreadLocal _exportCapTablePostActions = new ThreadLocal(); static readonly ThreadLocal _tailCall = new ThreadLocal(); static readonly ThreadLocal _canDeferCalls = new ThreadLocal(); @@ -386,7 +385,7 @@ namespace Capnp.Rpc } } - IProvidedCapability? cap; + Skeleton? callTargetCap; PendingAnswer pendingAnswer; bool releaseParamCaps = false; @@ -507,7 +506,7 @@ namespace Capnp.Rpc var inParams = req.Params.Content; inParams.Caps = ImportCapTable(req.Params); - if (cap == null) + if (callTargetCap == null) { releaseParamCaps = true; pendingAnswer = new PendingAnswer( @@ -519,7 +518,7 @@ namespace Capnp.Rpc try { var cts = new CancellationTokenSource(); - var callTask = cap.Invoke(req.InterfaceId, req.MethodId, inParams, cts.Token); + var callTask = callTargetCap.Invoke(req.InterfaceId, req.MethodId, inParams, cts.Token); pendingAnswer = new PendingAnswer(callTask, cts); } catch (System.Exception exception) @@ -528,6 +527,10 @@ namespace Capnp.Rpc pendingAnswer = new PendingAnswer( Task.FromException(exception), null); } + finally + { + callTargetCap.Relinquish(); + } } AwaitAnswerAndReply(); @@ -561,7 +564,8 @@ namespace Capnp.Rpc { if (_exportTable.TryGetValue(req.Target.ImportedCap, out var rc)) { - cap = rc.Cap; + callTargetCap = rc.Cap; + callTargetCap.Claim(); } else { @@ -594,7 +598,8 @@ namespace Capnp.Rpc try { using var proxy = await t; - cap = proxy?.GetProvider(); + callTargetCap = proxy?.GetProvider(); + callTargetCap?.Claim(); CreateAnswerAwaitItAndReply(); } catch (TaskCanceledException) @@ -631,8 +636,9 @@ namespace Capnp.Rpc { _canDeferCalls.Value = false; Impatient.AskingEndpoint = null; - _tailCall.Value?.Send(); + var call = _tailCall.Value; _tailCall.Value = null; + call?.Send(); } } @@ -948,14 +954,6 @@ namespace Capnp.Rpc } } } - - //if (results != null && results.Caps != null) - //{ - // foreach (var cap in results.Caps) - // { - // cap?.Release(); - // } - //} } catch { @@ -1105,7 +1103,7 @@ namespace Capnp.Rpc Tx(mb.Frame); - var main = new RemoteAnswerCapabilityDeprecated( + var main = new RemoteAnswerCapability( pendingBootstrap, MemberAccessPath.BootstrapAccess); @@ -1340,7 +1338,9 @@ namespace Capnp.Rpc { foreach (var capDesc in payload.CapTable) { - list.Add(ImportCap(capDesc)); + var cap = ImportCap(capDesc); + cap.AddRef(); + list.Add(cap); } } } @@ -1348,20 +1348,13 @@ namespace Capnp.Rpc return list; } - void IRpcEndpoint.RequestPostAction(Action postAction) - { - _exportCapTablePostActions.Value += postAction; - } - void ExportCapTableAndSend( SerializerState state, Payload.WRITER payload) { - Debug.Assert(_exportCapTablePostActions.Value == null); - _exportCapTablePostActions.Value = null; - payload.CapTable.Init(state.MsgBuilder!.Caps!.Count); + Action? postAction = null; int i = 0; foreach (var cap in state.MsgBuilder.Caps) { @@ -1373,7 +1366,7 @@ namespace Capnp.Rpc } else { - cap.Export(this, capDesc); + postAction += cap.Export(this, capDesc); cap.Release(false); } } @@ -1386,9 +1379,7 @@ namespace Capnp.Rpc // To avoid that situation, calls to "ReExportCapWhenResolved" are queued (and // therefore deferred) to the postAction. - var pa = _exportCapTablePostActions.Value; - _exportCapTablePostActions.Value = null; - pa?.Invoke(); + postAction?.Invoke(); } PendingQuestion IRpcEndpoint.BeginQuestion(ConsumedCapability target, SerializerState inParams) diff --git a/Capnp.Net.Runtime/Rpc/Vine.cs b/Capnp.Net.Runtime/Rpc/Vine.cs index db63d0c..1542681 100644 --- a/Capnp.Net.Runtime/Rpc/Vine.cs +++ b/Capnp.Net.Runtime/Rpc/Vine.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Extensions.Logging; +using System; using System.Threading; using System.Threading.Tasks; @@ -17,8 +18,24 @@ namespace Capnp.Rpc Vine(ConsumedCapability consumedCap) { Proxy = new Proxy(consumedCap ?? throw new ArgumentNullException(nameof(consumedCap))); + +#if DebugFinalizers + CreatorStackTrace = Environment.StackTrace; +#endif } +#if DebugFinalizers + ~Vine() + { + Logger.LogWarning($"Caught orphaned Vine, created from here: {CreatorStackTrace}."); + + Dispose(false); + } + + ILogger Logger { get; } = Logging.CreateLogger(); + string CreatorStackTrace { get; } +#endif + internal override void Bind(object impl) { throw new NotImplementedException(); diff --git a/Capnp.Net.sln b/Capnp.Net.sln index ff53c1c..8540d21 100644 --- a/Capnp.Net.sln +++ b/Capnp.Net.sln @@ -9,8 +9,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "capnpc-csharp", "capnpc-csh EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnp.Net.Runtime.Tests.Std20", "Capnp.Net.Runtime.Tests\Capnp.Net.Runtime.Tests.Std20.csproj", "{9ED38750-F83F-4B10-B3A3-4FD6183F9E86}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnp.Net.Runtime.Tests.Core21", "Capnp.Net.Runtime.Tests.Core21\Capnp.Net.Runtime.Tests.Core21.csproj", "{58E8FFC8-D207-4B0F-842A-58ED9D3D9EEF}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CapnpC.CSharp.Generator.Tests", "CapnpC.CSharp.Generator.Tests\CapnpC.CSharp.Generator.Tests.csproj", "{B77AC567-E232-4072-85C3-8689566BF3D4}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CapnpC.CSharp.MsBuild.Generation", "CapnpC.CSharp.MsBuild.Generation\CapnpC.CSharp.MsBuild.Generation.csproj", "{1EFC1F20-C7BB-4F44-8BF9-DBB123AACCF4}" @@ -37,10 +35,6 @@ Global {9ED38750-F83F-4B10-B3A3-4FD6183F9E86}.Debug|Any CPU.Build.0 = Debug|Any CPU {9ED38750-F83F-4B10-B3A3-4FD6183F9E86}.Release|Any CPU.ActiveCfg = Release|Any CPU {9ED38750-F83F-4B10-B3A3-4FD6183F9E86}.Release|Any CPU.Build.0 = Release|Any CPU - {58E8FFC8-D207-4B0F-842A-58ED9D3D9EEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {58E8FFC8-D207-4B0F-842A-58ED9D3D9EEF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {58E8FFC8-D207-4B0F-842A-58ED9D3D9EEF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {58E8FFC8-D207-4B0F-842A-58ED9D3D9EEF}.Release|Any CPU.Build.0 = Release|Any CPU {B77AC567-E232-4072-85C3-8689566BF3D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B77AC567-E232-4072-85C3-8689566BF3D4}.Debug|Any CPU.Build.0 = Debug|Any CPU {B77AC567-E232-4072-85C3-8689566BF3D4}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs index e96c18b..6053239 100644 --- a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs +++ b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs @@ -8480,9 +8480,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestGenerics.Inner2.DeepNest.DeepNestInterface.Params_Call() {}; arg_?.serialize(in_); - var d_ = await Call(9816138025992274567UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create.Inner2.DeepNest.DeepNestInterface.Result_Call>(d_); - return; + using (var d_ = await Call(9816138025992274567UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create.Inner2.DeepNest.DeepNestInterface.Result_Call>(d_); + return; + } } } @@ -8496,9 +8498,12 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 9816138025992274567UL; async Task Call(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Call(cancellationToken_); - var s_ = SerializerState.CreateForRpc.Inner2.DeepNest.DeepNestInterface.Result_Call.WRITER>(); - return s_; + using (d_) + { + await Impl.Call(cancellationToken_); + var s_ = SerializerState.CreateForRpc.Inner2.DeepNest.DeepNestInterface.Result_Call.WRITER>(); + return s_; + } } } @@ -8612,8 +8617,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(14548678385738242652UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create.Interface.Result_Call>(d_); - return (r_.Qux, r_.Gen); + using (d_) + { + var r_ = CapnpSerializable.Create.Interface.Result_Call>(d_); + return (r_.Qux, r_.Gen); + } } ); @@ -8630,15 +8638,18 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 14548678385738242652UL; Task Call(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.Call(CapnpSerializable.Create.Inner2>(d_), cancellationToken_), (qux, gen) => + using (d_) { - var s_ = SerializerState.CreateForRpc.Interface.Result_Call.WRITER>(); - var r_ = new Capnproto_test.Capnp.Test.TestGenerics.Interface.Result_Call{Qux = qux, Gen = gen}; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.Call(CapnpSerializable.Create.Inner2>(d_), cancellationToken_), (qux, gen) => + { + var s_ = SerializerState.CreateForRpc.Interface.Result_Call.WRITER>(); + var r_ = new Capnproto_test.Capnp.Test.TestGenerics.Interface.Result_Call{Qux = qux, Gen = gen}; + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -8995,8 +9006,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(10058534285777328794UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create>(d_); - return r_; + using (d_) + { + var r_ = CapnpSerializable.Create>(d_); + return r_; + } } ); @@ -9014,15 +9028,18 @@ namespace Capnproto_test.Capnp.Test Task Call(DeserializerState d_, CancellationToken cancellationToken_) where TT : class where TU : class { - var in_ = CapnpSerializable.Create>(d_); - return Impatient.MaybeTailCall(Impl.Call(in_.Foo, in_.Bar, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc.WRITER>(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create>(d_); + return Impatient.MaybeTailCall(Impl.Call(in_.Foo, in_.Bar, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc.WRITER>(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -9122,8 +9139,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(16112979978201007305UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create>(d_); - return r_; + using (d_) + { + var r_ = CapnpSerializable.Create>(d_); + return r_; + } } ); @@ -9141,15 +9161,18 @@ namespace Capnproto_test.Capnp.Test Task Call(DeserializerState d_, CancellationToken cancellationToken_) where TT : class where TU : class { - var in_ = CapnpSerializable.Create.Params_Call>(d_); - return Impatient.MaybeTailCall(Impl.Call(in_.Foo, in_.Bar, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc.WRITER>(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create.Params_Call>(d_); + return Impatient.MaybeTailCall(Impl.Call(in_.Foo, in_.Bar, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc.WRITER>(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -10029,9 +10052,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() {I = I, J = J}; arg_?.serialize(in_); - var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.X); + using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.X); + } } public async Task Bar(CancellationToken cancellationToken_ = default) @@ -10040,9 +10065,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Bar() {}; arg_?.serialize(in_); - var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) @@ -10051,9 +10078,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() {S = S}; arg_?.serialize(in_); - var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -10067,31 +10096,40 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 9865999890858873522UL; Task Foo(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.J, cancellationToken_), x => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestInterface.Result_Foo{X = x}; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.J, cancellationToken_), x => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestInterface.Result_Foo{X = x}; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task Bar(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Bar(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Bar(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } async Task Baz(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.Baz(in_.S, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.Baz(in_.S, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } } @@ -10444,18 +10482,22 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_Qux() {}; arg_?.serialize(in_); - var d_ = await Call(16494920484927878984UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(16494920484927878984UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Corge(Capnproto_test.Capnp.Test.TestAllTypes arg_, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); arg_?.serialize(in_); - var d_ = await Call(16494920484927878984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(16494920484927878984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Grault(CancellationToken cancellationToken_ = default) @@ -10464,9 +10506,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_Grault() {}; arg_?.serialize(in_); - var d_ = await Call(16494920484927878984UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + using (var d_ = await Call(16494920484927878984UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } public async Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default) @@ -10475,9 +10519,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() {I = I, J = J}; arg_?.serialize(in_); - var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.X); + using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.X); + } } public async Task Bar(CancellationToken cancellationToken_ = default) @@ -10486,9 +10532,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Bar() {}; arg_?.serialize(in_); - var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) @@ -10497,9 +10545,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() {S = S}; arg_?.serialize(in_); - var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -10513,28 +10563,37 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 16494920484927878984UL; async Task Qux(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Qux(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Qux(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } async Task Corge(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Corge(CapnpSerializable.Create(d_), cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Corge(CapnpSerializable.Create(d_), cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } Task Grault(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.Grault(cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.Grault(cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -10734,18 +10793,22 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_Qux() {}; arg_?.serialize(in_); - var d_ = await Call(16494920484927878984UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(16494920484927878984UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Corge(Capnproto_test.Capnp.Test.TestAllTypes arg_, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); arg_?.serialize(in_); - var d_ = await Call(16494920484927878984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(16494920484927878984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Grault(CancellationToken cancellationToken_ = default) @@ -10754,9 +10817,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestExtends.Params_Grault() {}; arg_?.serialize(in_); - var d_ = await Call(16494920484927878984UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + using (var d_ = await Call(16494920484927878984UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } public async Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default) @@ -10765,9 +10830,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() {I = I, J = J}; arg_?.serialize(in_); - var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.X); + using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.X); + } } public async Task Bar(CancellationToken cancellationToken_ = default) @@ -10776,9 +10843,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Bar() {}; arg_?.serialize(in_); - var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(9865999890858873522UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) @@ -10787,9 +10856,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() {S = S}; arg_?.serialize(in_); - var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -10821,8 +10892,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(11935670180855499984UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.S, r_.OutBox); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.S, r_.OutBox); + } } ); @@ -10834,9 +10908,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_TestPointers() {Cap = Cap, Obj = Obj, List = List}; arg_?.serialize(in_); - var d_ = await Call(11935670180855499984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(11935670180855499984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint N, BareProxy InCap, CancellationToken cancellationToken_ = default) @@ -10847,8 +10923,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(11935670180855499984UL, 2, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.S, r_.OutBox); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.S, r_.OutBox); + } } ); @@ -10865,38 +10944,47 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 11935670180855499984UL; Task GetCap(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.GetCap(in_.N, in_.InCap, cancellationToken_), (s, outBox) => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestPipeline.Result_GetCap{S = s, OutBox = outBox}; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.GetCap(in_.N, in_.InCap, cancellationToken_), (s, outBox) => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestPipeline.Result_GetCap{S = s, OutBox = outBox}; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task TestPointers(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.TestPointers(in_.Cap, in_.Obj, in_.List, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.TestPointers(in_.Cap, in_.Obj, in_.List, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } Task GetAnyCap(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.GetAnyCap(in_.N, in_.InCap, cancellationToken_), (s, outBox) => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestPipeline.Result_GetAnyCap{S = s, OutBox = outBox}; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.GetAnyCap(in_.N, in_.InCap, cancellationToken_), (s, outBox) => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestPipeline.Result_GetAnyCap{S = s, OutBox = outBox}; + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -11472,9 +11560,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestCallOrder.Params_GetCallSequence() {Expected = Expected}; arg_?.serialize(in_); - var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.N); + using (var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.N); + } } } @@ -11488,16 +11578,19 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 11594359141811814481UL; Task GetCallSequence(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.GetCallSequence(in_.Expected, cancellationToken_), n => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestCallOrder.Result_GetCallSequence{N = n}; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.GetCallSequence(in_.Expected, cancellationToken_), n => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestCallOrder.Result_GetCallSequence{N = n}; + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -11640,8 +11733,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15985132292242203195UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return r_; + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } ); @@ -11658,15 +11754,18 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 15985132292242203195UL; Task Foo(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.T, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.T, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -11854,8 +11953,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(9731139705278181429UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return r_; + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } ); @@ -11872,15 +11974,18 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 9731139705278181429UL; Task Foo(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.Callee, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.Foo(in_.I, in_.Callee, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -12007,9 +12112,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_CallFoo() {Cap = Cap}; arg_?.serialize(in_); - var d_ = await Call(15980754968839795663UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.S); + using (var d_ = await Call(15980754968839795663UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.S); + } } public async Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) @@ -12018,9 +12125,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_CallFooWhenResolved() {Cap = Cap}; arg_?.serialize(in_); - var d_ = await Call(15980754968839795663UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.S); + using (var d_ = await Call(15980754968839795663UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.S); + } } public Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) @@ -12031,8 +12140,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 2, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.CapCopy); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.CapCopy); + } } ); @@ -12044,9 +12156,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_Hold() {Cap = Cap}; arg_?.serialize(in_); - var d_ = await Call(15980754968839795663UL, 3, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(15980754968839795663UL, 3, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task CallHeld(CancellationToken cancellationToken_ = default) @@ -12055,9 +12169,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_CallHeld() {}; arg_?.serialize(in_); - var d_ = await Call(15980754968839795663UL, 4, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.S); + using (var d_ = await Call(15980754968839795663UL, 4, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.S); + } } public Task GetHeld(CancellationToken cancellationToken_ = default) @@ -12068,8 +12184,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 5, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.Cap); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Cap); + } } ); @@ -12083,8 +12202,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 6, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.Cap); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Cap); + } } ); @@ -12096,9 +12218,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_ExpectCancel() {Cap = Cap}; arg_?.serialize(in_); - var d_ = await Call(15980754968839795663UL, 7, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(15980754968839795663UL, 7, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default) @@ -12107,9 +12231,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_MethodWithDefaults() {A = A, B = B, C = C}; arg_?.serialize(in_); - var d_ = await Call(15980754968839795663UL, 8, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.D, r_.E); + using (var d_ = await Call(15980754968839795663UL, 8, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.D, r_.E); + } } public Task GetHandle(CancellationToken cancellationToken_ = default) @@ -12120,8 +12246,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 9, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.Handle); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Handle); + } } ); @@ -12135,8 +12264,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 10, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.NullCap); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.NullCap); + } } ); @@ -12148,9 +12280,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_GetEnormousString() {}; arg_?.serialize(in_); - var d_ = await Call(15980754968839795663UL, 11, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.Str); + using (var d_ = await Call(15980754968839795663UL, 11, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Str); + } } public async Task MethodWithNullDefault(string A, Capnproto_test.Capnp.Test.ITestInterface B, CancellationToken cancellationToken_ = default) @@ -12159,9 +12293,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_MethodWithNullDefault() {A = A, B = B}; arg_?.serialize(in_); - var d_ = await Call(15980754968839795663UL, 12, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(15980754968839795663UL, 12, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default) @@ -12170,9 +12306,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestCallOrder.Params_GetCallSequence() {Expected = Expected}; arg_?.serialize(in_); - var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return (r_.N); + using (var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.N); + } } } @@ -12186,161 +12324,200 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 15980754968839795663UL; Task CallFoo(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.CallFoo(in_.Cap, cancellationToken_), s => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_CallFoo{S = s}; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.CallFoo(in_.Cap, cancellationToken_), s => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_CallFoo{S = s}; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task CallFooWhenResolved(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.CallFooWhenResolved(in_.Cap, cancellationToken_), s => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_CallFooWhenResolved{S = s}; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.CallFooWhenResolved(in_.Cap, cancellationToken_), s => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_CallFooWhenResolved{S = s}; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task NeverReturn(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.NeverReturn(in_.Cap, cancellationToken_), capCopy => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_NeverReturn{CapCopy = capCopy}; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.NeverReturn(in_.Cap, cancellationToken_), capCopy => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_NeverReturn{CapCopy = capCopy}; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task Hold(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.Hold(in_.Cap, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.Hold(in_.Cap, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } Task CallHeld(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.CallHeld(cancellationToken_), s => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_CallHeld{S = s}; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.CallHeld(cancellationToken_), s => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_CallHeld{S = s}; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task GetHeld(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.GetHeld(cancellationToken_), cap => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetHeld{Cap = cap}; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.GetHeld(cancellationToken_), cap => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetHeld{Cap = cap}; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task Echo(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.Echo(in_.Cap, cancellationToken_), cap => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_Echo{Cap = cap}; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.Echo(in_.Cap, cancellationToken_), cap => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_Echo{Cap = cap}; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task ExpectCancel(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.ExpectCancel(in_.Cap, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.ExpectCancel(in_.Cap, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } Task MethodWithDefaults(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.MethodWithDefaults(in_.A, in_.B, in_.C, cancellationToken_), (d, e) => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_MethodWithDefaults{D = d, E = e}; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.MethodWithDefaults(in_.A, in_.B, in_.C, cancellationToken_), (d, e) => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_MethodWithDefaults{D = d, E = e}; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task GetHandle(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.GetHandle(cancellationToken_), handle => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetHandle{Handle = handle}; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.GetHandle(cancellationToken_), handle => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetHandle{Handle = handle}; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task GetNull(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.GetNull(cancellationToken_), nullCap => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetNull{NullCap = nullCap}; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.GetNull(cancellationToken_), nullCap => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetNull{NullCap = nullCap}; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task GetEnormousString(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.GetEnormousString(cancellationToken_), str => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetEnormousString{Str = str}; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.GetEnormousString(cancellationToken_), str => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Result_GetEnormousString{Str = str}; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task MethodWithNullDefault(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.MethodWithNullDefault(in_.A, in_.B, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.MethodWithNullDefault(in_.A, in_.B, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } } @@ -13870,8 +14047,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(13870398341137210380UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.Thing); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Thing); + } } ); @@ -13883,9 +14063,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_CallPassThrough() {Thing = Thing, TailCall = TailCall}; arg_?.serialize(in_); - var d_ = await Call(13870398341137210380UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + using (var d_ = await Call(13870398341137210380UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } public async Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default) @@ -13894,9 +14076,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_CallIntercept() {Thing = Thing, TailCall = TailCall}; arg_?.serialize(in_); - var d_ = await Call(13870398341137210380UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + using (var d_ = await Call(13870398341137210380UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } public Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, CancellationToken cancellationToken_ = default) @@ -13907,8 +14091,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(13870398341137210380UL, 3, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create(d_); - return (r_.Thing); + using (d_) + { + var r_ = CapnpSerializable.Create(d_); + return (r_.Thing); + } } ); @@ -13920,9 +14107,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_WaitForever() {}; arg_?.serialize(in_); - var d_ = await Call(13870398341137210380UL, 4, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(13870398341137210380UL, 4, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -13936,62 +14125,77 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 13870398341137210380UL; Task MakeThing(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.MakeThing(cancellationToken_), thing => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMembrane.Result_MakeThing{Thing = thing}; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.MakeThing(cancellationToken_), thing => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMembrane.Result_MakeThing{Thing = thing}; + r_.serialize(s_); + return s_; + } - ); + ); + } } Task CallPassThrough(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.CallPassThrough(in_.Thing, in_.TailCall, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.CallPassThrough(in_.Thing, in_.TailCall, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } Task CallIntercept(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.CallIntercept(in_.Thing, in_.TailCall, cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.CallIntercept(in_.Thing, in_.TailCall, cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } Task Loopback(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - return Impatient.MaybeTailCall(Impl.Loopback(in_.Thing, cancellationToken_), thing => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - var r_ = new Capnproto_test.Capnp.Test.TestMembrane.Result_Loopback{Thing = thing}; - r_.serialize(s_); - return s_; - } + var in_ = CapnpSerializable.Create(d_); + return Impatient.MaybeTailCall(Impl.Loopback(in_.Thing, cancellationToken_), thing => + { + var s_ = SerializerState.CreateForRpc(); + var r_ = new Capnproto_test.Capnp.Test.TestMembrane.Result_Loopback{Thing = thing}; + r_.serialize(s_); + return s_; + } - ); + ); + } } async Task WaitForever(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.WaitForever(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.WaitForever(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } } @@ -14012,9 +14216,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Thing.Params_PassThrough() {}; arg_?.serialize(in_); - var d_ = await Call(10615798940090972439UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + using (var d_ = await Call(10615798940090972439UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } public async Task Intercept(CancellationToken cancellationToken_ = default) @@ -14023,9 +14229,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Thing.Params_Intercept() {}; arg_?.serialize(in_); - var d_ = await Call(10615798940090972439UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return r_; + using (var d_ = await Call(10615798940090972439UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return r_; + } } } @@ -14039,26 +14247,32 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 10615798940090972439UL; Task PassThrough(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.PassThrough(cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.PassThrough(cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } Task Intercept(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.Intercept(cancellationToken_), r_ => + using (d_) { - var s_ = SerializerState.CreateForRpc(); - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.Intercept(cancellationToken_), r_ => + { + var s_ = SerializerState.CreateForRpc(); + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -14908,9 +15122,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_Delete() {}; arg_?.serialize(in_); - var d_ = await Call(11160837778045172988UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(11160837778045172988UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Class(CancellationToken cancellationToken_ = default) @@ -14919,9 +15135,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_Class() {}; arg_?.serialize(in_); - var d_ = await Call(11160837778045172988UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(11160837778045172988UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Void(CancellationToken cancellationToken_ = default) @@ -14930,9 +15148,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_Void() {}; arg_?.serialize(in_); - var d_ = await Call(11160837778045172988UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(11160837778045172988UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } public async Task Return(CancellationToken cancellationToken_ = default) @@ -14941,9 +15161,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestKeywordMethods.Params_Return() {}; arg_?.serialize(in_); - var d_ = await Call(11160837778045172988UL, 3, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(11160837778045172988UL, 3, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -14957,30 +15179,42 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 11160837778045172988UL; async Task Delete(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Delete(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Delete(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } async Task Class(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Class(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Class(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } async Task Void(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Void(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Void(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } async Task Return(DeserializerState d_, CancellationToken cancellationToken_) { - await Impl.Return(cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + await Impl.Return(cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } } @@ -15363,8 +15597,11 @@ namespace Capnproto_test.Capnp.Test arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(16893789964317726925UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { - var r_ = CapnpSerializable.Create.Result_GetCallerId>(d_); - return (r_.Caller); + using (d_) + { + var r_ = CapnpSerializable.Create.Result_GetCallerId>(d_); + return (r_.Caller); + } } ); @@ -15381,15 +15618,18 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 16893789964317726925UL; Task GetCallerId(DeserializerState d_, CancellationToken cancellationToken_) { - return Impatient.MaybeTailCall(Impl.GetCallerId(cancellationToken_), caller => + using (d_) { - var s_ = SerializerState.CreateForRpc.Result_GetCallerId.WRITER>(); - var r_ = new Capnproto_test.Capnp.Test.TestAuthenticatedBootstrap.Result_GetCallerId{Caller = caller}; - r_.serialize(s_); - return s_; - } + return Impatient.MaybeTailCall(Impl.GetCallerId(cancellationToken_), caller => + { + var s_ = SerializerState.CreateForRpc.Result_GetCallerId.WRITER>(); + var r_ = new Capnproto_test.Capnp.Test.TestAuthenticatedBootstrap.Result_GetCallerId{Caller = caller}; + r_.serialize(s_); + return s_; + } - ); + ); + } } } @@ -16335,9 +16575,11 @@ namespace Capnproto_test.Capnp.Test var arg_ = new Capnproto_test.Capnp.Test.TestNameAnnotationInterface.Params_BadlyNamedMethod() {BadlyNamedParam = BadlyNamedParam}; arg_?.serialize(in_); - var d_ = await Call(15065286897585459595UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned; - var r_ = CapnpSerializable.Create(d_); - return; + using (var d_ = await Call(15065286897585459595UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) + { + var r_ = CapnpSerializable.Create(d_); + return; + } } } @@ -16351,10 +16593,13 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 15065286897585459595UL; async Task BadlyNamedMethod(DeserializerState d_, CancellationToken cancellationToken_) { - var in_ = CapnpSerializable.Create(d_); - await Impl.BadlyNamedMethod(in_.BadlyNamedParam, cancellationToken_); - var s_ = SerializerState.CreateForRpc(); - return s_; + using (d_) + { + var in_ = CapnpSerializable.Create(d_); + await Impl.BadlyNamedMethod(in_.BadlyNamedParam, cancellationToken_); + var s_ = SerializerState.CreateForRpc(); + return s_; + } } } @@ -16471,19 +16716,22 @@ namespace Capnproto_test.Capnp.Test static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap = new MemberAccessPath(1U, 0U); public static Capnproto_test.Capnp.Test.ITestInterface OutBox_Cap(this Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> task) { - return (Capnproto_test.Capnp.Test.ITestInterface)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap)); + async Task AwaitProxy() => (await task).Item2?.Cap; + return (Capnproto_test.Capnp.Test.ITestInterface)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap, AwaitProxy())); } static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap = new MemberAccessPath(1U, 0U); public static BareProxy OutBox_Cap(this Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> task) { - return (BareProxy)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap)); + async Task AwaitProxy() => (await task).Item2?.Cap; + return (BareProxy)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap, AwaitProxy())); } static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestTailCallee_foo_C = new MemberAccessPath(1U); public static Capnproto_test.Capnp.Test.ITestCallOrder C(this Task task) { - return (Capnproto_test.Capnp.Test.ITestCallOrder)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestTailCallee_foo_C)); + async Task AwaitProxy() => (await task).C; + return (Capnproto_test.Capnp.Test.ITestCallOrder)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestTailCallee_foo_C, AwaitProxy())); } } } \ No newline at end of file diff --git a/CapnpC.CSharp.Generator/CodeGen/GenNames.cs b/CapnpC.CSharp.Generator/CodeGen/GenNames.cs index afcdf19..95f1889 100644 --- a/CapnpC.CSharp.Generator/CodeGen/GenNames.cs +++ b/CapnpC.CSharp.Generator/CodeGen/GenNames.cs @@ -72,6 +72,7 @@ namespace CapnpC.CSharp.Generator.CodeGen public string PipeliningExtensionsClassFormat { get; } public string ProxyClassFormat { get; } public string SkeletonClassFormat { get; } + public Name AwaitProxy { get; } public bool NullableEnable { get; set; } public GenNames(GeneratorOptions options) { @@ -110,6 +111,7 @@ namespace CapnpC.CSharp.Generator.CodeGen PipeliningExtensionsClassFormat = options.PipeliningExtensionsClassFormat; ProxyClassFormat = options.ProxyClassFormat; SkeletonClassFormat = options.SkeletonClassFormat; + AwaitProxy = new Name(options.AwaitProxyName); } public Name MakeTypeName(TypeDefinition def, NameUsage usage = NameUsage.Default) diff --git a/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs b/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs index 3a3eccf..178d41b 100644 --- a/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs +++ b/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs @@ -37,6 +37,7 @@ public string TaskParameterName { get; set; } = "task"; public string EagerMethodName { get; set; } = "Eager"; public string TypeIdFieldName { get; set; } = "typeId"; + public string AwaitProxyName { get; set; } = "AwaitProxy"; public bool NullableEnableDefault { get; set; } = false; } } diff --git a/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs b/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs index c683f3b..f1940aa 100644 --- a/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs +++ b/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs @@ -404,8 +404,11 @@ namespace CapnpC.CSharp.Generator.CodeGen Argument(SimpleLambdaExpression( Parameter(_names.DeserializerLocal.Identifier), Block( - MakeProxyCreateResult(method), - MakeProxyReturnResult(method))))); + UsingStatement( + Block( + MakeProxyCreateResult(method), + MakeProxyReturnResult(method))) + .WithExpression(_names.DeserializerLocal.IdentifierName))))); bodyStmts.Add(ReturnStatement(pipelineAwareCall)); } @@ -422,19 +425,18 @@ namespace CapnpC.CSharp.Generator.CodeGen call, IdentifierName(nameof(Capnp.Rpc.IPromisedAnswer.WhenReturned))); - var assignAwaited = LocalDeclarationStatement( - VariableDeclaration( + bodyStmts.Add(UsingStatement( + Block( + MakeProxyCreateResult(method), + MakeProxyReturnResult(method))) + .WithDeclaration(VariableDeclaration( IdentifierName("var")) - .AddVariables( - VariableDeclarator( - _names.DeserializerLocal.Identifier) - .WithInitializer( - EqualsValueClause( - AwaitExpression(whenReturned))))); - - bodyStmts.Add(assignAwaited); - bodyStmts.Add(MakeProxyCreateResult(method)); - bodyStmts.Add(MakeProxyReturnResult(method)); + .AddVariables( + VariableDeclarator( + _names.DeserializerLocal.Identifier) + .WithInitializer( + EqualsValueClause( + AwaitExpression(whenReturned)))))); } if (method.GenericParameters.Count > 0) @@ -703,7 +705,10 @@ namespace CapnpC.CSharp.Generator.CodeGen Parameter(_names.CancellationTokenParameter.Identifier) .WithType(_names.Type(Nullability.NonNullable))) .AddBodyStatements( - MakeSkeletonMethodBody(method).ToArray()); + UsingStatement( + Block( + MakeSkeletonMethodBody(method).ToArray())) + .WithExpression(_names.DeserializerLocal.IdentifierName)); if (method.Results.Count == 0) { @@ -808,6 +813,59 @@ namespace CapnpC.CSharp.Generator.CodeGen readonly HashSet<(string, string)> _existingExtensionMethods = new HashSet<(string, string)>(); + LocalFunctionStatementSyntax MakeLocalAwaitProxyFunction(Method method, IReadOnlyList path) + { + var members = new List(); + IEnumerable fields = path; + + if (method.Results.Count >= 2) + { + int index = Array.IndexOf(method.ResultStruct.Fields.ToArray(), path[0]) + 1; + members.Add(new Name($"Item{index}")); + fields = path.Skip(1); + } + + foreach (var field in fields) + { + members.Add(_names.GetCodeIdentifier(field)); + } + + ExpressionSyntax memberAccess = + ParenthesizedExpression( + AwaitExpression( + _names.TaskParameter.IdentifierName)); + + memberAccess = MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + memberAccess, + members.First().IdentifierName); + + foreach (var member in members.Skip(1)) + { + memberAccess = ConditionalAccessExpression( + memberAccess, + MemberBindingExpression(member.IdentifierName)); + } + + var idisposable = _names.MakeNullableRefType(IdentifierName(nameof(IDisposable))); + + return LocalFunctionStatement( + GenericName( + Identifier(nameof(Task))) + .WithTypeArgumentList( + TypeArgumentList( + SingletonSeparatedList( + idisposable))), + _names.AwaitProxy.Identifier) + .WithModifiers( + TokenList( + Token(SyntaxKind.AsyncKeyword))) + .WithExpressionBody( + ArrowExpressionClause(memberAccess)) + .WithSemicolonToken( + Token(SyntaxKind.SemicolonToken)); + } + public IEnumerable MakePipeliningSupport(TypeDefinition type) { foreach (var method in type.Methods) @@ -856,6 +914,7 @@ namespace CapnpC.CSharp.Generator.CodeGen .AddModifiers(This) .WithType(TransformReturnType(method))) .AddBodyStatements( + MakeLocalAwaitProxyFunction(method, path), ReturnStatement( CastExpression( capTypeSyntax, @@ -883,7 +942,10 @@ namespace CapnpC.CSharp.Generator.CodeGen IdentifierName(nameof(Capnp.Rpc.IPromisedAnswer.Access)))) .AddArgumentListArguments( Argument( - accessPath.IdentifierName))))))); + accessPath.IdentifierName), + Argument( + InvocationExpression( + _names.AwaitProxy.IdentifierName)))))))); yield return pathDecl; yield return methodDecl; From b6c84c3c6c3ad48ef8953e7db4c2f0a758c9bb15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 21 Mar 2020 14:40:46 +0100 Subject: [PATCH 17/76] reorg file structure --- .../Capnp.Net.Runtime.Core21.csproj | 113 ------------------ .../Capnp.Net.Runtime.Tests.Core21.csproj | 56 --------- ....csproj => Capnp.Net.Runtime.Tests.csproj} | 0 Capnp.Net.sln | 2 +- appveyor.yml | 10 +- scripts/measure-coverage.ps1 | 20 +--- 6 files changed, 10 insertions(+), 191 deletions(-) delete mode 100644 Capnp.Net.Runtime.Core21/Capnp.Net.Runtime.Core21.csproj delete mode 100644 Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj rename Capnp.Net.Runtime.Tests/{Capnp.Net.Runtime.Tests.Std20.csproj => Capnp.Net.Runtime.Tests.csproj} (100%) diff --git a/Capnp.Net.Runtime.Core21/Capnp.Net.Runtime.Core21.csproj b/Capnp.Net.Runtime.Core21/Capnp.Net.Runtime.Core21.csproj deleted file mode 100644 index 60c4831..0000000 --- a/Capnp.Net.Runtime.Core21/Capnp.Net.Runtime.Core21.csproj +++ /dev/null @@ -1,113 +0,0 @@ - - - - netcoreapp2.1 - true - Capnp.Net.Runtime - Christian Köllner and contributors - - capnproto-dotnetcore - A Cap'n Proto implementation for .NET Core, runtime assembly for .NET Core 2.1 - Christian Köllner and contributors - MIT - - https://github.com/c80k/capnproto-dotnetcore - https://github.com/c80k/capnproto-dotnetcore - Capnp.Net.Runtime - Capnp - Git - capnp "Cap'n Proto" RPC serialization cerealization - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 deleted file mode 100644 index 42ee749..0000000 --- a/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj +++ /dev/null @@ -1,56 +0,0 @@ - - - - netcoreapp2.1 - - false - - Debug;Release - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj b/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.csproj similarity index 100% rename from Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj rename to Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.csproj diff --git a/Capnp.Net.sln b/Capnp.Net.sln index 8540d21..70a4fcf 100644 --- a/Capnp.Net.sln +++ b/Capnp.Net.sln @@ -7,7 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnp.Net.Runtime", "Capnp. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "capnpc-csharp", "capnpc-csharp\capnpc-csharp.csproj", "{D19E5EA7-D35B-4A1F-99CB-ED136316B577}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnp.Net.Runtime.Tests.Std20", "Capnp.Net.Runtime.Tests\Capnp.Net.Runtime.Tests.Std20.csproj", "{9ED38750-F83F-4B10-B3A3-4FD6183F9E86}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Capnp.Net.Runtime.Tests", "Capnp.Net.Runtime.Tests\Capnp.Net.Runtime.Tests.csproj", "{9ED38750-F83F-4B10-B3A3-4FD6183F9E86}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CapnpC.CSharp.Generator.Tests", "CapnpC.CSharp.Generator.Tests\CapnpC.CSharp.Generator.Tests.csproj", "{B77AC567-E232-4072-85C3-8689566BF3D4}" EndProject diff --git a/appveyor.yml b/appveyor.yml index fff160f..933127e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,9 +25,7 @@ before_build: - cmd: dotnet --version - cmd: msbuild -ver - cmd: dotnet restore ./Capnp.Net.Runtime/Capnp.Net.Runtime.csproj --verbosity m - - cmd: dotnet restore ./Capnp.Net.Runtime.Core21/Capnp.Net.Runtime.Core21.csproj --verbosity m - - cmd: dotnet restore ./Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.Std20.csproj --verbosity m - - cmd: dotnet restore ./Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj --verbosity m + - cmd: dotnet restore ./Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.csproj --verbosity m - cmd: dotnet restore ./CapnpC.CSharp.Generator/CapnpC.CSharp.Generator.csproj --verbosity m - cmd: dotnet restore ./CapnpC.CSharp.Generator.Tests/CapnpC.CSharp.Generator.Tests.csproj --verbosity m - cmd: dotnet restore ./CapnpC.CSharp.MsBuild.Generation/CapnpC.CSharp.MsBuild.Generation.csproj --verbosity m @@ -87,10 +85,10 @@ test_script: msbuild ./MsBuildGenerationTest/MsBuildGenerationTest.sln /p:Configuration="Debug" /p:PackageReferenceVersion="%VERSION%" vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Debug\net471\Capnp.Net.Runtime.Tests.Std20.dll vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Release\net471\Capnp.Net.Runtime.Tests.Std20.dll - vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Debug\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll - vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests.Core21\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll + vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Debug\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll + vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll powershell -File .\scripts\measure-coverage.ps1 - csmacnz.Coveralls --multiple -i "opencover=coverage\cov-Capnp.Net.Runtime-dnc21.xml;opencover=coverage\cov-Capnp.Net.Runtime-net471.xml;opencover=coverage\cov-CapnpC.CSharp.Generator.xml" --repoToken %COVERALLS_REPO_TOKEN% + csmacnz.Coveralls --multiple -i "opencover=coverage\cov-Capnp.Net.Runtime.xml;opencover=coverage\cov-CapnpC.CSharp.Generator.xml" --repoToken %COVERALLS_REPO_TOKEN% on_finish : # any cleanup in here deploy: diff --git a/scripts/measure-coverage.ps1 b/scripts/measure-coverage.ps1 index 0f3fa03..a438829 100644 --- a/scripts/measure-coverage.ps1 +++ b/scripts/measure-coverage.ps1 @@ -5,11 +5,8 @@ $coverageReportDir = "$rootDir\coverage\report" $openCover = "$env:LOCALAPPDATA\Apps\OpenCover\OpenCover.Console.exe" $vsTestConsole = where.exe vstest.console -$runtimeTestsDnc21 = "$rootDir\Capnp.Net.Runtime.Tests.Core21\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll" -$coverageOutputRuntimeDnc21 = "$coverageDir\cov-Capnp.Net.Runtime-dnc21.xml" - -$runtimeTestsNet471 = "$rootDir\Capnp.Net.Runtime.Tests\bin\Release\net471\Capnp.Net.Runtime.Tests.Std20.dll" -$coverageOutputRuntimeNet471 = "$coverageDir\cov-Capnp.Net.Runtime-net471.xml" +$runtimeTests = "$rootDir\Capnp.Net.Runtime.Tests\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.dll" +$coverageOutputRuntime = "$coverageDir\cov-Capnp.Net.Runtime.xml" $generatorTests = "$rootDir\CapnpC.CSharp.Generator.Tests\bin\Release\netcoreapp3.0\CapnpC.CSharp.Generator.Tests.dll" $coverageOutputGenerator = "$coverageDir\cov-CapnpC.CSharp.Generator.xml" @@ -25,17 +22,10 @@ If(!(test-path $coverageReportDir)) } & $openCover -target:"$vsTestConsole" ` - -targetArgs:"/inIsolation $runtimeTestsDnc21 /TestCaseFilter:`"TestCategory=Coverage`"" ` + -targetArgs:"/inIsolation $runtimeTests /TestCaseFilter:`"TestCategory=Coverage`"" ` -filter:"+[Capnp.Net.Runtime]Capnp.*" ` -excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" ` - -output:"$coverageOutputRuntimeDnc21" ` - -mergebyhash -register:user -oldStyle - -& $openCover -target:"$vsTestConsole" ` - -targetArgs:"/inIsolation $runtimeTestsNet471 /TestCaseFilter:`"TestCategory=Coverage`"" ` - -filter:"+[Capnp.Net.Runtime]Capnp.*" ` - -excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" ` - -output:"$coverageOutputRuntimeNet471" ` + -output:"$coverageOutputRuntime" ` -mergebyhash -register:user -oldStyle & $openCover -target:"$vsTestConsole" ` @@ -45,4 +35,4 @@ If(!(test-path $coverageReportDir)) -output:"$coverageOutputGenerator" ` -mergebyhash -register:user -oldStyle -ReportGenerator.exe -reports:"$coverageOutputRuntimeDnc21;$coverageOutputRuntimeNet471;$coverageOutputGenerator" -targetdir:"$coverageReportDir" -reportTypes:"Html;Xml" +ReportGenerator.exe -reports:"$coverageOutputRuntime;$coverageOutputGenerator" -targetdir:"$coverageReportDir" -reportTypes:"Html;Xml" From ec0df4872fa4fc8e2a29a4cc568e4835d1ef05cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 22 Mar 2020 00:12:50 +0100 Subject: [PATCH 18/76] bug fixes, stability improvements --- .../DeserializationTests.cs | 24 ++ Capnp.Net.Runtime.Tests/Dtbdct.cs | 6 + Capnp.Net.Runtime.Tests/LocalRpc.cs | 86 +++++- .../Mock/TestCapImplementations.cs | 52 ++-- Capnp.Net.Runtime.Tests/Mock/test.cs | 6 +- Capnp.Net.Runtime.Tests/TcpRpcInterop.cs | 39 +-- Capnp.Net.Runtime.Tests/TcpRpcPorted.cs | 27 ++ Capnp.Net.Runtime.Tests/Testsuite.cs | 105 ++++---- Capnp.Net.Runtime.Tests/Util/TestBase.cs | 46 +++- Capnp.Net.Runtime/Rpc/ConsumedCapability.cs | 5 + Capnp.Net.Runtime/Rpc/Impatient.cs | 38 +-- Capnp.Net.Runtime/Rpc/LocalAnswer.cs | 2 +- .../Rpc/LocalAnswerCapability.cs | 15 ++ .../Rpc/LocalAnswerCapabilityDeprecated.cs | 84 ------ Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 47 ++-- Capnp.Net.Runtime/Rpc/PromisedCapability.cs | 6 +- Capnp.Net.Runtime/Rpc/Proxy.cs | 5 + .../Rpc/RemoteAnswerCapabilityDeprecated.cs | 253 ------------------ .../Rpc/ResolvingCapabilityExtensions.cs | 18 +- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 3 + Capnp.Net.Runtime/Rpc/TcpRpcServer.cs | 2 + .../Embedded Resources/test.cs | 6 +- .../CodeGen/InterfaceSnippetGen.cs | 23 +- 23 files changed, 402 insertions(+), 496 deletions(-) delete mode 100644 Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs delete mode 100644 Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs diff --git a/Capnp.Net.Runtime.Tests/DeserializationTests.cs b/Capnp.Net.Runtime.Tests/DeserializationTests.cs index 51e50b8..d9b2861 100644 --- a/Capnp.Net.Runtime.Tests/DeserializationTests.cs +++ b/Capnp.Net.Runtime.Tests/DeserializationTests.cs @@ -767,5 +767,29 @@ namespace Capnp.Net.Runtime.Tests CollectionAssert.AreEqual(expected[i], voids[i].ToArray()); } } + + [TestMethod] + public void ListOfEmpty() + { + var expected = new TestEnum[] { TestEnum.bar, TestEnum.baz, TestEnum.corge }; + + var b = MessageBuilder.Create(); + var loes = b.CreateObject(); + loes.Init(12345678); + DeserializerState d = loes; + var ld = d.RequireList(); + Assert.AreEqual(ListKind.ListOfEmpty, ld.Kind); + if (!(ld is ListOfEmptyDeserializer loed)) + { + Assert.Fail("List did not deserialize back to ListOfEmptyDeserializer"); + return; + } + Assert.AreEqual(12345678, loed.Count); + Assert.ThrowsException(() => { var _ = loed[-1]; }); + Assert.ThrowsException(() => { var _ = loed[12345678]; }); + _ = loed[12345677]; + var kind = loed.Cast(_ => _.Kind).Take(1).Single(); + Assert.AreEqual(ObjectKind.Nil, kind); + } } } diff --git a/Capnp.Net.Runtime.Tests/Dtbdct.cs b/Capnp.Net.Runtime.Tests/Dtbdct.cs index 75d2a93..e5c8653 100644 --- a/Capnp.Net.Runtime.Tests/Dtbdct.cs +++ b/Capnp.Net.Runtime.Tests/Dtbdct.cs @@ -92,5 +92,11 @@ namespace Capnp.Net.Runtime.Tests { NewDtbdctTestbed().RunTest(Testsuite.Basic); } + + [TestMethod] + public void BootstrapReuse() + { + NewDtbdctTestbed().RunTest(Testsuite.BootstrapReuse); + } } } diff --git a/Capnp.Net.Runtime.Tests/LocalRpc.cs b/Capnp.Net.Runtime.Tests/LocalRpc.cs index fd4f87b..095e0d7 100644 --- a/Capnp.Net.Runtime.Tests/LocalRpc.cs +++ b/Capnp.Net.Runtime.Tests/LocalRpc.cs @@ -12,7 +12,7 @@ using System.Threading.Tasks; namespace Capnp.Net.Runtime.Tests { [TestClass] - public class LocalRpc + public class LocalRpc: TestBase { [TestMethod] public void DeferredLocalAnswer() @@ -29,5 +29,89 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual("bar", foo.Result); } } + + [TestMethod] + public void Embargo() + { + NewLocalTestbed().RunTest(Testsuite.Embargo); + } + + [TestMethod] + public void EmbargoError() + { + NewLocalTestbed().RunTest(Testsuite.EmbargoError); + } + + [TestMethod] + public void EmbargoNull() + { + NewLocalTestbed().RunTest(Testsuite.EmbargoNull); + } + + [TestMethod] + public void CallBrokenPromise() + { + NewLocalTestbed().RunTest(Testsuite.CallBrokenPromise); + } + + [TestMethod] + public void TailCall() + { + NewLocalTestbed().RunTest(Testsuite.TailCall); + } + + [TestMethod] + public void SendTwice() + { + NewLocalTestbed().RunTest(Testsuite.SendTwice); + } + + [TestMethod] + public void Cancel() + { + NewLocalTestbed().RunTest(Testsuite.Cancel); + } + + [TestMethod] + public void RetainAndRelease() + { + NewLocalTestbed().RunTest(Testsuite.RetainAndRelease); + } + + [TestMethod] + public void PromiseResolve() + { + NewLocalTestbed().RunTest(Testsuite.PromiseResolve); + } + + [TestMethod] + public void Cancelation() + { + NewLocalTestbed().RunTest(Testsuite.Cancelation); + } + + [TestMethod] + public void ReleaseOnCancel() + { + NewLocalTestbed().RunTest(Testsuite.ReleaseOnCancel); + } + + [TestMethod] + public void Release() + { + NewLocalTestbed().RunTest(Testsuite.Release); + } + + [TestMethod] + public void Pipeline() + { + NewLocalTestbed().RunTest(Testsuite.Pipeline); + } + + [TestMethod] + public void Basic() + { + NewLocalTestbed().RunTest(Testsuite.Basic); + } } } diff --git a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs index 34fd9fe..6f65819 100644 --- a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs @@ -420,9 +420,12 @@ namespace Capnp.Net.Runtime.Tests.GenImpls public void Dispose() { - _tcs?.SetResult(0); + _tcs?.TrySetResult(0); + IsDisposed = true; } + public bool IsDisposed { get; private set; } + public virtual Task Foo(uint i, bool j, CancellationToken cancellationToken) { Interlocked.Increment(ref _counters.CallCount); @@ -512,20 +515,26 @@ namespace Capnp.Net.Runtime.Tests.GenImpls public async Task<(string, TestPipeline.AnyBox)> GetAnyCap(uint n, BareProxy inCap, CancellationToken cancellationToken_) { - Interlocked.Increment(ref _counters.CallCount); - Assert.AreEqual(234u, n); - var s = await inCap.Cast(true).Foo(123, true, cancellationToken_); - Assert.AreEqual("foo", s); - return ("bar", new TestPipeline.AnyBox() { Cap = BareProxy.FromImpl(new TestExtendsImpl(_counters)) }); + using (inCap) + { + Interlocked.Increment(ref _counters.CallCount); + Assert.AreEqual(234u, n); + var s = await inCap.Cast(true).Foo(123, true, cancellationToken_); + Assert.AreEqual("foo", s); + return ("bar", new TestPipeline.AnyBox() { Cap = BareProxy.FromImpl(new TestExtendsImpl(_counters)) }); + } } public async Task<(string, TestPipeline.Box)> GetCap(uint n, ITestInterface inCap, CancellationToken cancellationToken_) { - Interlocked.Increment(ref _counters.CallCount); - Assert.AreEqual(234u, n); - var s = await inCap.Foo(123, true, cancellationToken_); - Assert.AreEqual("foo", s); - return ("bar", new TestPipeline.Box() { Cap = new TestExtendsImpl(_counters) }); + using (inCap) + { + Interlocked.Increment(ref _counters.CallCount); + Assert.AreEqual(234u, n); + var s = await inCap.Foo(123, true, cancellationToken_); + Assert.AreEqual("foo", s); + return ("bar", new TestPipeline.Box() { Cap = new TestExtendsImpl(_counters) }); + } } public Task TestPointers(ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_) @@ -558,8 +567,11 @@ namespace Capnp.Net.Runtime.Tests.GenImpls public async Task<(string, TestPipeline.Box)> GetCap(uint n, ITestInterface inCap, CancellationToken cancellationToken_ = default) { - await _deblock; - return ("hello", new TestPipeline.Box() { Cap = _timpl2 }); + using (inCap) + { + await _deblock; + return ("hello", new TestPipeline.Box() { Cap = _timpl2 }); + } } public Task TestPointers(ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_ = default) @@ -661,10 +673,15 @@ namespace Capnp.Net.Runtime.Tests.GenImpls public void Dispose() { + IsDisposed = true; } + public bool IsDisposed { get; private set; } + public Task Foo(int i, string t, CancellationToken cancellationToken_) { + Assert.IsFalse(IsDisposed); + Interlocked.Increment(ref _counters.CallCount); var result = new TestTailCallee.TailResult() @@ -710,9 +727,12 @@ namespace Capnp.Net.Runtime.Tests.GenImpls public async Task CallFooWhenResolved(ITestInterface cap, CancellationToken cancellationToken_) { Interlocked.Increment(ref _counters.CallCount); - await ((Proxy)cap).WhenResolved; - string s = await cap.Foo(123, true, cancellationToken_); - Assert.AreEqual("foo", s); + using (cap) + { + await ((Proxy)cap).WhenResolved; + string s = await cap.Foo(123, true, cancellationToken_); + Assert.AreEqual("foo", s); + } return "bar"; } diff --git a/Capnp.Net.Runtime.Tests/Mock/test.cs b/Capnp.Net.Runtime.Tests/Mock/test.cs index f7930f2..8108823 100644 --- a/Capnp.Net.Runtime.Tests/Mock/test.cs +++ b/Capnp.Net.Runtime.Tests/Mock/test.cs @@ -17501,21 +17501,21 @@ namespace Capnproto_test.Capnp.Test public static Capnproto_test.Capnp.Test.ITestInterface OutBox_Cap(this Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> task) { async Task AwaitProxy() => (await task).Item2?.Cap; - return (Capnproto_test.Capnp.Test.ITestInterface)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap, AwaitProxy())); + return (Capnproto_test.Capnp.Test.ITestInterface)CapabilityReflection.CreateProxy(Impatient.Access(task, Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap, AwaitProxy())); } static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap = new MemberAccessPath(1U, 0U); public static BareProxy OutBox_Cap(this Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> task) { async Task AwaitProxy() => (await task).Item2?.Cap; - return (BareProxy)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap, AwaitProxy())); + return (BareProxy)CapabilityReflection.CreateProxy(Impatient.Access(task, Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap, AwaitProxy())); } static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestTailCallee_foo_C = new MemberAccessPath(1U); public static Capnproto_test.Capnp.Test.ITestCallOrder C(this Task task) { async Task AwaitProxy() => (await task).C; - return (Capnproto_test.Capnp.Test.ITestCallOrder)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestTailCallee_foo_C, AwaitProxy())); + return (Capnproto_test.Capnp.Test.ITestCallOrder)CapabilityReflection.CreateProxy(Impatient.Access(task, Path_capnproto_test_capnp_test_TestTailCallee_foo_C, AwaitProxy())); } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs index 2f16eff..97228ca 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs @@ -2,6 +2,7 @@ using Capnp.Net.Runtime.Tests.GenImpls; using Capnp.Rpc; using Capnproto_test.Capnp.Test; +using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; @@ -63,21 +64,25 @@ namespace Capnp.Net.Runtime.Tests try { - _currentProcess.StandardError.ReadToEndAsync().ContinueWith(t => Console.Error.WriteLine(t.Result)); - var firstLine = _currentProcess.StandardOutput.ReadLineAsync(); - Assert.IsTrue(firstLine.Wait(MediumNonDbgTimeout), "Problem after launching test process"); - Assert.IsNotNull(firstLine.Result, "Problem after launching test process"); - Assert.IsTrue(firstLine.Result.StartsWith("Listening") || firstLine.Result.StartsWith("Connecting"), - "Problem after launching test process"); + try + { + _currentProcess.StandardError.ReadToEndAsync().ContinueWith(t => Console.Error.WriteLine(t.Result)); + var firstLine = _currentProcess.StandardOutput.ReadLineAsync(); + Assert.IsTrue(firstLine.Wait(MediumNonDbgTimeout), "Problem after launching test process"); + Assert.IsNotNull(firstLine.Result, "Problem after launching test process"); + Assert.IsTrue(firstLine.Result.StartsWith("Listening") || firstLine.Result.StartsWith("Connecting"), + "Problem after launching test process"); + } + catch (AssertFailedException exception) + { + Logger.LogError(exception.Message); + return false; + } test(_currentProcess.StandardOutput); return true; } - catch (AssertFailedException) - { - return false; - } finally { try @@ -220,6 +225,7 @@ namespace Capnp.Net.Runtime.Tests { AssertOutput(stdout, "Pipelining test start"); AssertOutput(stdout, "foo 123 1"); + AssertOutput(stdout, "~"); AssertOutput(stdout, "Pipelining test end"); Assert.AreEqual(3, counters.CallCount); }); @@ -342,17 +348,19 @@ namespace Capnp.Net.Runtime.Tests for (int i = 0; i < iterationCount; i++) { var task = main.GetHandle(default); - taskList.Add(task.ContinueWith(t => + async Task TerminateAnswer() { try { - t.Result.Dispose(); + using (var proxy = await task) + { + } } - catch (AggregateException ex) when (ex.InnerException is TaskCanceledException) + catch (TaskCanceledException) { } - })); - Impatient.GetAnswer(task).Dispose(); + } + taskList.Add(TerminateAnswer()); } // Ensure that all answers return (probably in canceled state) @@ -558,6 +566,7 @@ namespace Capnp.Net.Runtime.Tests AssertOutput(stdout, "PromiseResolve test start"); AssertOutput(stdout, "foo 123 1"); AssertOutput(stdout, "foo 123 1"); + AssertOutput(stdout, "~"); AssertOutput(stdout, "PromiseResolve test end"); Assert.AreEqual(3, counters.CallCount); }); diff --git a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs index 293e595..0066c40 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs @@ -139,5 +139,32 @@ namespace Capnp.Net.Runtime.Tests { NewLocalhostTcpTestbed().RunTest(Testsuite.CallBrokenPromise); } + + [TestMethod] + public void BootstrapReuse() + { + (var server, var client) = SetupClientServerPair(); + + var counters = new Counters(); + var impl = new TestInterfaceImpl(counters); + + using (server) + using (client) + { + client.WhenConnected.Wait(); + + server.Main = impl; + for (int i = 0; i < 10; i++) + { + using (var main = client.GetMain()) + { + ((Proxy)main).WhenResolved.Wait(MediumNonDbgTimeout); + } + Assert.IsFalse(impl.IsDisposed); + } + } + + Assert.IsTrue(impl.IsDisposed); + } } } diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs index 0d9821a..dc48702 100644 --- a/Capnp.Net.Runtime.Tests/Testsuite.cs +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -60,8 +60,8 @@ namespace Capnp.Net.Runtime.Tests using (var main = testbed.ConnectMain(impl)) { - var resolving = main as IResolvingCapability; - testbed.MustComplete(resolving.WhenResolved); + if (main is IResolvingCapability resolving) + testbed.MustComplete(resolving.WhenResolved); var cap = new TestCallOrderImpl(); cap.CountToDispose = 6; @@ -70,7 +70,7 @@ namespace Capnp.Net.Runtime.Tests var echo = main.Echo(cap, default); testbed.MustComplete(Task.CompletedTask); - using (var pipeline = echo.Eager()) + using (var pipeline = echo.Eager(true)) { var call0 = pipeline.GetCallSequence(0, default); var call1 = pipeline.GetCallSequence(1, default); @@ -120,15 +120,15 @@ namespace Capnp.Net.Runtime.Tests var impl = new TestMoreStuffImpl(counters); using (var main = testbed.ConnectMain(impl)) { - var resolving = main as IResolvingCapability; - testbed.MustComplete(resolving.WhenResolved); + if (main is IResolvingCapability resolving) + testbed.MustComplete(resolving.WhenResolved); var cap = new TaskCompletionSource(); var earlyCall = main.GetCallSequence(0, default); var echo = main.Echo(cap.Task.Eager(true), default); - using (var pipeline = echo.Eager()) + using (var pipeline = echo.Eager(true)) { var call0 = pipeline.GetCallSequence(0, default); var call1 = pipeline.GetCallSequence(1, default); @@ -161,20 +161,21 @@ namespace Capnp.Net.Runtime.Tests var impl = new TestMoreStuffImpl(counters); using (var main = testbed.ConnectMain(impl)) { - var resolving = main as IResolvingCapability; - testbed.MustComplete(resolving.WhenResolved); + if (main is IResolvingCapability resolving) + testbed.MustComplete(resolving.WhenResolved); var promise = main.GetNull(default); - var cap = promise.Eager(); + using (var cap = promise.Eager(true)) + { + var call0 = cap.GetCallSequence(0, default); - var call0 = cap.GetCallSequence(0, default); + testbed.MustComplete(promise); - testbed.MustComplete(promise); + var call1 = cap.GetCallSequence(1, default); - var call1 = cap.GetCallSequence(1, default); - - testbed.ExpectPromiseThrows(call0, call1); + testbed.ExpectPromiseThrows(call0, call1); + } // Verify that we're still connected (there were no protocol errors). testbed.MustComplete(main.GetCallSequence(1, default)); @@ -184,11 +185,11 @@ namespace Capnp.Net.Runtime.Tests public static void CallBrokenPromise(ITestbed testbed) { var counters = new Counters(); - var impl = new TestMoreStuffImpl(counters); + using (var impl = new TestMoreStuffImpl(counters)) using (var main = testbed.ConnectMain(impl)) { - var resolving = main as IResolvingCapability; - testbed.MustComplete(resolving.WhenResolved); + if (main is IResolvingCapability resolving) + testbed.MustComplete(resolving.WhenResolved); var tcs = new TaskCompletionSource(); @@ -231,6 +232,7 @@ namespace Capnp.Net.Runtime.Tests testbed.MustComplete(dependentCall0, dependentCall1, dependentCall2); + Assert.IsTrue(callee.IsDisposed); Assert.AreEqual(1, counters.CallCount); Assert.AreEqual(1, calleeCallCount.CallCount); } @@ -313,7 +315,7 @@ namespace Capnp.Net.Runtime.Tests var destructionTask = destructionPromise.Task; var counters = new Counters(); - var impl = new TestMoreStuffImpl(counters); + using (var impl = new TestMoreStuffImpl(counters)) using (var main = testbed.ConnectMain(impl)) { var holdTask = main.Hold(new TestInterfaceImpl(new Counters(), destructionPromise), default); @@ -366,12 +368,6 @@ namespace Capnp.Net.Runtime.Tests // Can't be destroyed, we haven't released it. Assert.IsFalse(destructionTask.IsCompleted); } - - // In deviation from original test, we have null the held capability on the main interface. - // This is because the main interface is the bootstrap capability and, as such, won't be disposed - // after disconnect. - var holdNullTask = main.Hold(null, default); - testbed.MustComplete(holdNullTask); } testbed.MustComplete(destructionTask); @@ -384,26 +380,27 @@ namespace Capnp.Net.Runtime.Tests using (var main = testbed.ConnectMain(impl)) { var tcs = new TaskCompletionSource(); - var eager = tcs.Task.Eager(true); + using (var eager = tcs.Task.Eager(true)) + { + var request = main.CallFoo(Proxy.Share(eager), default); + var request2 = main.CallFooWhenResolved(eager, default); - var request = main.CallFoo(eager, default); - var request2 = main.CallFooWhenResolved(eager, default); + var gcs = main.GetCallSequence(0, default); + testbed.MustComplete(gcs); + Assert.AreEqual(2u, gcs.Result); + Assert.AreEqual(3, counters.CallCount); - var gcs = main.GetCallSequence(0, default); - testbed.MustComplete(gcs); - Assert.AreEqual(2u, gcs.Result); - Assert.AreEqual(3, counters.CallCount); + var chainedCallCount = new Counters(); + var tiimpl = new TestInterfaceImpl(chainedCallCount); + tcs.SetResult(tiimpl); - var chainedCallCount = new Counters(); - var tiimpl = new TestInterfaceImpl(chainedCallCount); - tcs.SetResult(tiimpl); + testbed.MustComplete(request, request2); - testbed.MustComplete(request, request2); - - Assert.AreEqual("bar", request.Result); - Assert.AreEqual("bar", request2.Result); - Assert.AreEqual(3, counters.CallCount); - Assert.AreEqual(2, chainedCallCount.CallCount); + Assert.AreEqual("bar", request.Result); + Assert.AreEqual("bar", request2.Result); + Assert.AreEqual(3, counters.CallCount); + Assert.AreEqual(2, chainedCallCount.CallCount); + } } } @@ -488,15 +485,18 @@ namespace Capnp.Net.Runtime.Tests using (var outBox = request.OutBox_Cap()) { var pipelineRequest = outBox.Foo(321, false, default); - var pipelineRequest2 = ((Proxy)outBox).Cast(false).Grault(default); + using (var testx = ((Proxy)outBox).Cast(false)) + { + var pipelineRequest2 = testx.Grault(default); - testbed.MustComplete(pipelineRequest, pipelineRequest2); + testbed.MustComplete(pipelineRequest, pipelineRequest2); - Assert.AreEqual("bar", pipelineRequest.Result); - Common.CheckTestMessage(pipelineRequest2.Result); + Assert.AreEqual("bar", pipelineRequest.Result); + Common.CheckTestMessage(pipelineRequest2.Result); - Assert.AreEqual(3, counters.CallCount); - Assert.AreEqual(1, chainedCallCount.CallCount); + Assert.AreEqual(3, counters.CallCount); + Assert.AreEqual(1, chainedCallCount.CallCount); + } } } } @@ -519,5 +519,18 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(2, counters.CallCount); } } + + public static void BootstrapReuse(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestInterfaceImpl(counters); + for (int i = 0; i < 10; i++) + { + using (var main = testbed.ConnectMain(impl)) + { + } + Assert.IsFalse(impl.IsDisposed); + } + } } } diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index b64377f..422e7b3 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -147,6 +147,35 @@ namespace Capnp.Net.Runtime.Tests public int Channel2SendCount => _channel2.FrameCounter; } + protected class LocalTestbed : ITestbed, ITestController + { + long ITestbed.ClientSendCount => 0; + + public void RunTest(Action action) + { + action(this); + } + + T ITestbed.ConnectMain(T main) + { + return main; + } + + void ITestbed.FlushCommunication() + { + } + + void ITestbed.MustComplete(params Task[] tasks) + { + Assert.IsTrue(Task.WhenAll(tasks).IsCompleted); + } + + void ITestbed.MustNotComplete(params Task[] tasks) + { + Assert.IsFalse(Task.WhenAny(tasks).IsCompleted); + } + } + protected class DtbdctTestbed : ITestbed, ITestController { readonly DecisionTree _decisionTree = new DecisionTree(); @@ -154,7 +183,20 @@ namespace Capnp.Net.Runtime.Tests public void RunTest(Action action) { - _decisionTree.Iterate(() => action(this)); + _decisionTree.Iterate(() => { + + action(this); + _enginePair.FlushChannels(() => false); + + Assert.AreEqual(0, _enginePair.Endpoint1.ExportedCapabilityCount); + Assert.AreEqual(0, _enginePair.Endpoint1.ImportedCapabilityCount); + Assert.AreEqual(0, _enginePair.Endpoint2.ExportedCapabilityCount); + Assert.AreEqual(0, _enginePair.Endpoint2.ImportedCapabilityCount); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + }); } T ITestbed.ConnectMain(T main) @@ -290,6 +332,8 @@ namespace Capnp.Net.Runtime.Tests protected static DtbdctTestbed NewDtbdctTestbed() => new DtbdctTestbed(); protected static LocalhostTcpTestbed NewLocalhostTcpTestbed() => new LocalhostTcpTestbed(); + protected static LocalTestbed NewLocalTestbed() => new LocalTestbed(); + [TestInitialize] public void InitConsoleLogging() { diff --git a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs index 4342b84..452bcd3 100644 --- a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs @@ -25,5 +25,10 @@ namespace Capnp.Rpc [System.Runtime.CompilerServices.CallerMemberName] string methodName = "", [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0); + +#if DebugFinalizers + internal Proxy? OwningProxy { get; set; } + internal ConsumedCapability? ResolvingCap { get; set; } +#endif } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index b07e5ba..e0ede4e 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -92,35 +92,11 @@ namespace Capnp.Rpc return answer; } - static async Task AwaitProxy(Task task) where T: class + public static ConsumedCapability? Access(Task task, MemberAccessPath access, Task proxyTask) { - T item; - - try - { - item = await task; - } - catch (TaskCanceledException exception) - { - return new Proxy(LazyCapability.CreateCanceledCap(exception.CancellationToken)); - } - catch (System.Exception exception) - { - return new Proxy(LazyCapability.CreateBrokenCap(exception.Message)); - } - - switch (item) - { - case Proxy proxy: - return proxy; - - case null: - return CapabilityReflection.CreateProxy(null); - } - - var skel = Skeleton.GetOrCreateSkeleton(item!, false); - var localCap = LocalCapability.Create(skel); - return CapabilityReflection.CreateProxy(localCap); + var answer = TryGetAnswer(task); + if (answer != null) return answer.Access(access, proxyTask); + return new LazyCapability(proxyTask.AsProxyTask()); } /// @@ -138,9 +114,9 @@ namespace Capnp.Rpc /// quality as capability interface. [Obsolete("Call Eager(task, true) instead")] public static TInterface PseudoEager(this Task task) - where TInterface : class + where TInterface : class, IDisposable { - var lazyCap = new LazyCapability(AwaitProxy(task)); + var lazyCap = new LazyCapability(task.AsProxyTask()); return (CapabilityReflection.CreateProxy(lazyCap) as TInterface)!; } @@ -177,7 +153,7 @@ namespace Capnp.Rpc throw new ArgumentException("The task was not returned from a remote method invocation. See documentation for details."); } - var lazyCap = new LazyCapability(AwaitProxy(task)); + var lazyCap = new LazyCapability(task.AsProxyTask()); return (CapabilityReflection.CreateProxy(lazyCap) as TInterface)!; } else diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswer.cs b/Capnp.Net.Runtime/Rpc/LocalAnswer.cs index f88e27b..f1f3f86 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswer.cs @@ -27,7 +27,7 @@ namespace Capnp.Rpc public ConsumedCapability Access(MemberAccessPath access) { - return new LocalAnswerCapabilityDeprecated(WhenReturned, access); + return new LocalAnswerCapability(WhenReturned, access); } public ConsumedCapability Access(MemberAccessPath _, Task task) diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs index 9d6093e..ef5cc29 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs @@ -7,6 +7,15 @@ namespace Capnp.Rpc class LocalAnswerCapability : RefCountingCapability, IResolvingCapability { + static async Task TransferOwnershipToDummyProxy(Task answer, MemberAccessPath access) + { + var result = await answer; + var cap = access.Eval(result); + var proxy = new Proxy(cap); + cap?.Release(false); + return proxy; + } + readonly Task _whenResolvedProxy; public LocalAnswerCapability(Task proxyTask) @@ -17,6 +26,12 @@ namespace Capnp.Rpc WhenResolved = AwaitResolved(); } + public LocalAnswerCapability(Task answer, MemberAccessPath access): + this(TransferOwnershipToDummyProxy(answer, access)) + { + + } + internal override void Freeze(out IRpcEndpoint? boundEndpoint) { boundEndpoint = null; diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs deleted file mode 100644 index 3688638..0000000 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapabilityDeprecated.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Capnp.Rpc -{ - class LocalAnswerCapabilityDeprecated : RefCountingCapability, IResolvingCapability - { - readonly Task _answer; - readonly MemberAccessPath _access; - - public LocalAnswerCapabilityDeprecated(Task answer, MemberAccessPath access) - { - _answer = answer; - _access = access; - - async Task AwaitResolved() => access.Eval(await _answer); - WhenResolved = AwaitResolved(); - } - - internal override void Freeze(out IRpcEndpoint? boundEndpoint) - { - boundEndpoint = null; - } - - internal override void Unfreeze() - { - } - - - public Task WhenResolved { get; private set; } - - internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) - { - if (_answer.IsCompleted) - { - DeserializerState result; - try - { - result = _answer.Result; - } - catch (AggregateException exception) - { - throw exception.InnerException!; - } - - using var proxy = new Proxy(_access.Eval(result)); - proxy.Export(endpoint, writer); - return null; - } - else - { - return this.ExportAsSenderPromise(endpoint, writer); - } - } - - async Task CallImpl(ulong interfaceId, ushort methodId, DynamicSerializerState args, CancellationToken cancellationToken) - { - var cap = await WhenResolved; - - cancellationToken.ThrowIfCancellationRequested(); - - if (cap == null) - throw new RpcException("Broken capability"); - - using var proxy = new Proxy(cap); - var call = proxy.Call(interfaceId, methodId, args, default); - var whenReturned = call.WhenReturned; - - using var registration = cancellationToken.Register(() => call.Dispose()); - return await whenReturned; - } - - internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) - { - var cts = new CancellationTokenSource(); - return new LocalAnswer(cts, CallImpl(interfaceId, methodId, args, cts.Token)); - } - - protected override void ReleaseRemotely() - { - } - } -} \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index dcdd7be..548f907 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -126,17 +126,17 @@ namespace Capnp.Rpc lock (ReentrancyBlocker) { SetReturned(); + } - if (StateFlags.HasFlag(State.TailCall)) + if (StateFlags.HasFlag(State.TailCall)) + { + _tcs.TrySetException(new RpcException(ReturnDespiteTailCallMessage)); + } + else + { + if (!_tcs.TrySetResult(results)) { - _tcs.TrySetException(new RpcException(ReturnDespiteTailCallMessage)); - } - else - { - if (!_tcs.TrySetResult(results)) - { - ReleaseOutCaps(results); - } + ReleaseOutCaps(results); } } } @@ -146,15 +146,15 @@ namespace Capnp.Rpc lock (ReentrancyBlocker) { SetReturned(); + } - if (!StateFlags.HasFlag(State.TailCall)) - { - _tcs.TrySetException(new RpcException("Peer sent the results of this questions somewhere else. This was not expected and is a protocol error.")); - } - else - { - _tcs.TrySetResult(default); - } + if (!StateFlags.HasFlag(State.TailCall)) + { + _tcs.TrySetException(new RpcException("Peer sent the results of this questions somewhere else. This was not expected and is a protocol error.")); + } + else + { + _tcs.TrySetResult(default); } } @@ -163,9 +163,9 @@ namespace Capnp.Rpc lock (ReentrancyBlocker) { SetReturned(); - - _tcs.TrySetException(new RpcException(exception.Reason)); } + + _tcs.TrySetException(new RpcException(exception.Reason)); } internal void OnException(System.Exception exception) @@ -173,9 +173,9 @@ namespace Capnp.Rpc lock (ReentrancyBlocker) { SetReturned(); - - _tcs.TrySetException(exception); } + + _tcs.TrySetException(exception); } internal void OnCanceled() @@ -183,9 +183,9 @@ namespace Capnp.Rpc lock (ReentrancyBlocker) { SetReturned(); - - _tcs.TrySetCanceled(); } + + _tcs.TrySetCanceled(); } void DeleteMyQuestion() @@ -234,7 +234,6 @@ namespace Capnp.Rpc /// Access path /// Low-level capability /// The referenced member does not exist or does not resolve to a capability pointer. - [Obsolete("Please re-generate. Replaced by Access(MemberAccessPath access, Task task)")] public ConsumedCapability? Access(MemberAccessPath access) { lock (ReentrancyBlocker) diff --git a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs index ec9a97b..0099383 100644 --- a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs @@ -203,6 +203,9 @@ namespace Capnp.Rpc lock (_reentrancyBlocker) { +#if DebugFinalizers + resolvedCap.ResolvingCap = this; +#endif _resolvedCap.SetResult(resolvedCap); if (_pendingCallsOnPromise == 0) @@ -247,11 +250,10 @@ namespace Capnp.Rpc { if (!_released) { + _released = true; _ep.ReleaseImport(_remoteId); } - _ep.ReleaseImport(_remoteId); - try { using var _ = await _whenResolvedProxy; } catch { } } diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index 1d6c9e0..c4d0eed 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -120,6 +120,11 @@ namespace Capnp.Rpc ConsumedCap = cap; cap.AddRef(); + +#if DebugFinalizers + if (ConsumedCap != null) + ConsumedCap.OwningProxy = this; +#endif } internal Skeleton? GetProvider() diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs deleted file mode 100644 index f950659..0000000 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapabilityDeprecated.cs +++ /dev/null @@ -1,253 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Capnp.Rpc -{ -#if false - - class RemoteAnswerCapabilityDeprecated : RemoteResolvingCapability - { - // Set DebugEmbargos to true to get logging output for calls. RPC calls are expected to - // be on the critical path, hence very relevant for performance. We just can't afford - // additional stuff on this path. Even if the logger filters the outputs away, there is - // overhead for creating the Logger object, calling the Logger methods and deciding to - // filter the output. This justifies the precompiler switch. -#if DebugEmbargos - ILogger Logger { get; } = Logging.CreateLogger(); -#endif - - readonly PendingQuestion _question; - readonly MemberAccessPath _access; - ConsumedCapability? _resolvedCap; - - public RemoteAnswerCapabilityDeprecated(PendingQuestion question, MemberAccessPath access): base(question.RpcEndpoint) - { - _question = question ?? throw new ArgumentNullException(nameof(question)); - _access = access ?? throw new ArgumentNullException(nameof(access)); - - async Task AwaitWhenResolved() - { - await _question.WhenReturned; - - if (_question.IsTailCall) - throw new InvalidOperationException("Question is a tail call, so won't resolve back."); - - return ResolvedCap!; - } - - WhenResolved = AwaitWhenResolved(); - } - - async void ReAllowFinishWhenDone(Task task) - { - try - { - ++_pendingCallsOnPromise; - - await task; - } - catch - { - } - finally - { - lock (_question.ReentrancyBlocker) - { - --_pendingCallsOnPromise; - _question.AllowFinish(); - } - } - } - - protected override ConsumedCapability? ResolvedCap - { - get - { - lock (_question.ReentrancyBlocker) - { - if (_resolvedCap == null && !_question.IsTailCall && _question.IsReturned) - { - DeserializerState result; - try - { - result = _question.WhenReturned.Result; - } - catch (AggregateException exception) - { - throw exception.InnerException!; - } - - _resolvedCap = _access.Eval(result); - } - return _resolvedCap; - } - } - } - - public override Task WhenResolved { get; } - - protected override void GetMessageTarget(MessageTarget.WRITER wr) - { - wr.which = MessageTarget.WHICH.PromisedAnswer; - wr.PromisedAnswer.QuestionId = _question.QuestionId; - _access.Serialize(wr.PromisedAnswer); - } - - internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) - { - lock (_question.ReentrancyBlocker) - { - if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned) && - !_question.StateFlags.HasFlag(PendingQuestion.State.TailCall)) - { - if (ResolvedCap == null) - { - throw new RpcException("Answer did not resolve to expected capability"); - } - - return CallOnResolution(interfaceId, methodId, args); - } - else - { -#if DebugEmbargos - Logger.LogDebug("Call by proxy"); -#endif - if (_question.StateFlags.HasFlag(PendingQuestion.State.Disposed)) - { - throw new ObjectDisposedException(nameof(PendingQuestion)); - } - - if (_question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested)) - { - throw new InvalidOperationException("Finish request was already sent"); - } - - _question.DisallowFinish(); - ++_pendingCallsOnPromise; - var promisedAnswer = base.DoCall(interfaceId, methodId, args); - ReAllowFinishWhenDone(promisedAnswer.WhenReturned); - - async void DecrementPendingCallsOnPromiseWhenReturned() - { - try - { - await promisedAnswer.WhenReturned; - } - catch - { - } - finally - { - lock (_question.ReentrancyBlocker) - { - --_pendingCallsOnPromise; - } - } - } - - DecrementPendingCallsOnPromiseWhenReturned(); - return promisedAnswer; - } - } - } - - protected override Call.WRITER SetupMessage(DynamicSerializerState args, ulong interfaceId, ushort methodId) - { - var call = base.SetupMessage(args, interfaceId, methodId); - - call.Target.which = MessageTarget.WHICH.PromisedAnswer; - call.Target.PromisedAnswer.QuestionId = _question.QuestionId; - _access.Serialize(call.Target.PromisedAnswer); - - return call; - } - - internal override void Freeze(out IRpcEndpoint? boundEndpoint) - { - lock (_question.ReentrancyBlocker) - { - if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned) && - _pendingCallsOnPromise == 0) - { - if (ResolvedCap == null) - { - throw new RpcException("Answer did not resolve to expected capability"); - } - - ResolvedCap.Freeze(out boundEndpoint); - } - else - { - ++_pendingCallsOnPromise; - _question.DisallowFinish(); - boundEndpoint = _ep; - } - } - } - - internal override void Unfreeze() - { - lock (_question.ReentrancyBlocker) - { - if (_pendingCallsOnPromise > 0) - { - --_pendingCallsOnPromise; - _question.AllowFinish(); - } - else - { - ResolvedCap?.Unfreeze(); - } - } - } - - internal override void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) - { - lock (_question.ReentrancyBlocker) - { - if (_question.StateFlags.HasFlag(PendingQuestion.State.Disposed)) - throw new ObjectDisposedException(nameof(PendingQuestion)); - - if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned)) - { - ResolvedCap?.Export(endpoint, writer); - } - else - { - if (_question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested)) - throw new InvalidOperationException("Finish request was already sent"); - - if (endpoint == _ep) - { - writer.which = CapDescriptor.WHICH.ReceiverAnswer; - _access.Serialize(writer.ReceiverAnswer); - writer.ReceiverAnswer.QuestionId = _question.QuestionId; - } - else if (_question.IsTailCall) - { - // FIXME: Resource management! We should prevent finishing this - // cap as long as it is exported. Unfortunately, we cannot determine - // when it gets removed from the export table. - - var vine = Vine.Create(this); - uint id = endpoint.AllocateExport(vine, out bool first); - - writer.which = CapDescriptor.WHICH.SenderHosted; - writer.SenderHosted = id; - } - else - { - this.ExportAsSenderPromise(endpoint, writer); - } - } - } - } - - protected async override void ReleaseRemotely() - { - try { (await WhenResolved)?.Release(false); } - catch { } - } - } -#endif -} \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs index ade7ee8..0461d75 100644 --- a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs @@ -34,9 +34,23 @@ namespace Capnp.Rpc return null; } - public static async Task AsProxyTask(this Task task) + public static async Task AsProxyTask(this Task task) + where T: IDisposable? { - var obj = await task; + IDisposable? obj; + try + { + obj = await task; + } + catch (TaskCanceledException exception) + { + return new Proxy(LazyCapability.CreateCanceledCap(exception.CancellationToken)); + } + catch (System.Exception exception) + { + return new Proxy(LazyCapability.CreateBrokenCap(exception.Message)); + } + switch (obj) { case Proxy proxy: return proxy; diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 74ffc4b..8b6d9ce 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -132,6 +132,9 @@ namespace Capnp.Rpc public long SendCount => Interlocked.Read(ref _sendCount); public long RecvCount => Interlocked.Read(ref _recvCount); + public int ImportedCapabilityCount => _importTable.Count; + public int ExportedCapabilityCount => _exportTable.Count; + void Tx(WireFrame frame) { try diff --git a/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs b/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs index 2012f74..a4d4dc0 100644 --- a/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs +++ b/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs @@ -263,6 +263,8 @@ namespace Capnp.Rpc SafeJoin(connection.PumpRunner); } + _rpcEngine.BootstrapCap = null; + GC.SuppressFinalize(this); } diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs index 6053239..2f482e4 100644 --- a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs +++ b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs @@ -16717,21 +16717,21 @@ namespace Capnproto_test.Capnp.Test public static Capnproto_test.Capnp.Test.ITestInterface OutBox_Cap(this Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> task) { async Task AwaitProxy() => (await task).Item2?.Cap; - return (Capnproto_test.Capnp.Test.ITestInterface)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap, AwaitProxy())); + return (Capnproto_test.Capnp.Test.ITestInterface)CapabilityReflection.CreateProxy(Impatient.Access(task, Path_capnproto_test_capnp_test_TestPipeline_getCap_OutBox_Cap, AwaitProxy())); } static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap = new MemberAccessPath(1U, 0U); public static BareProxy OutBox_Cap(this Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> task) { async Task AwaitProxy() => (await task).Item2?.Cap; - return (BareProxy)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap, AwaitProxy())); + return (BareProxy)CapabilityReflection.CreateProxy(Impatient.Access(task, Path_capnproto_test_capnp_test_TestPipeline_getAnyCap_OutBox_Cap, AwaitProxy())); } static readonly MemberAccessPath Path_capnproto_test_capnp_test_TestTailCallee_foo_C = new MemberAccessPath(1U); public static Capnproto_test.Capnp.Test.ITestCallOrder C(this Task task) { async Task AwaitProxy() => (await task).C; - return (Capnproto_test.Capnp.Test.ITestCallOrder)CapabilityReflection.CreateProxy(Impatient.GetAnswer(task).Access(Path_capnproto_test_capnp_test_TestTailCallee_foo_C, AwaitProxy())); + return (Capnproto_test.Capnp.Test.ITestCallOrder)CapabilityReflection.CreateProxy(Impatient.Access(task, Path_capnproto_test_capnp_test_TestTailCallee_foo_C, AwaitProxy())); } } } \ No newline at end of file diff --git a/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs b/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs index f1940aa..676a09d 100644 --- a/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs +++ b/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs @@ -931,21 +931,16 @@ namespace CapnpC.CSharp.Generator.CodeGen InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, + IdentifierName(nameof(Capnp.Rpc.Impatient)), + IdentifierName(nameof(Capnp.Rpc.Impatient.Access)))) + .AddArgumentListArguments( + Argument( + _names.TaskParameter.IdentifierName), + Argument( + accessPath.IdentifierName), + Argument( InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(nameof(Capnp.Rpc.Impatient)), - IdentifierName(nameof(Capnp.Rpc.Impatient.GetAnswer)))) - .AddArgumentListArguments( - Argument( - _names.TaskParameter.IdentifierName)), - IdentifierName(nameof(Capnp.Rpc.IPromisedAnswer.Access)))) - .AddArgumentListArguments( - Argument( - accessPath.IdentifierName), - Argument( - InvocationExpression( - _names.AwaitProxy.IdentifierName)))))))); + _names.AwaitProxy.IdentifierName)))))))); yield return pathDecl; yield return methodDecl; From eb321e5a8ece55261c8eeae1f3d94a169831eabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 22 Mar 2020 13:57:02 +0100 Subject: [PATCH 19/76] cap. lifecycle fixes + more test cases --- Capnp.Net.Runtime.Tests/Dtbdct.cs | 18 +++++++++ Capnp.Net.Runtime.Tests/LocalRpc.cs | 19 ++++++++++ .../TcpRpcErrorHandling.cs | 1 + Capnp.Net.Runtime.Tests/TcpRpcPorted.cs | 18 +++++++++ Capnp.Net.Runtime.Tests/Testsuite.cs | 38 +++++++++++++++++++ Capnp.Net.Runtime.Tests/Util/TestBase.cs | 24 ++++++++++-- Capnp.Net.Runtime/DeserializerState.cs | 6 ++- Capnp.Net.Runtime/ObjectKind.cs | 2 - Capnp.Net.Runtime/Rpc/Impatient.cs | 1 + Capnp.Net.Runtime/Rpc/LazyCapability.cs | 20 +++++++++- .../Rpc/LocalAnswerCapability.cs | 3 ++ Capnp.Net.Runtime/Rpc/Proxy.cs | 22 +++++------ .../Rpc/RefCountingCapability.cs | 2 +- .../Rpc/RemoteAnswerCapability.cs | 14 ++++++- .../Rpc/RemoteResolvingCapability.cs | 8 +++- Capnp.Net.Runtime/SerializerState.cs | 16 +++++++- 16 files changed, 185 insertions(+), 27 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/Dtbdct.cs b/Capnp.Net.Runtime.Tests/Dtbdct.cs index e5c8653..eedecb3 100644 --- a/Capnp.Net.Runtime.Tests/Dtbdct.cs +++ b/Capnp.Net.Runtime.Tests/Dtbdct.cs @@ -98,5 +98,23 @@ namespace Capnp.Net.Runtime.Tests { NewDtbdctTestbed().RunTest(Testsuite.BootstrapReuse); } + + [TestMethod] + public void Ownership1() + { + NewDtbdctTestbed().RunTest(Testsuite.Ownership1); + } + + [TestMethod] + public void Ownership2() + { + NewDtbdctTestbed().RunTest(Testsuite.Ownership2); + } + + [TestMethod] + public void Ownership3() + { + NewDtbdctTestbed().RunTest(Testsuite.Ownership3); + } } } diff --git a/Capnp.Net.Runtime.Tests/LocalRpc.cs b/Capnp.Net.Runtime.Tests/LocalRpc.cs index 095e0d7..2100293 100644 --- a/Capnp.Net.Runtime.Tests/LocalRpc.cs +++ b/Capnp.Net.Runtime.Tests/LocalRpc.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class LocalRpc: TestBase { [TestMethod] @@ -113,5 +114,23 @@ namespace Capnp.Net.Runtime.Tests { NewLocalTestbed().RunTest(Testsuite.Basic); } + + [TestMethod] + public void Ownership1() + { + NewLocalTestbed().RunTest(Testsuite.Ownership1); + } + + [TestMethod] + public void Ownership2() + { + NewLocalTestbed().RunTest(Testsuite.Ownership2); + } + + [TestMethod] + public void Ownership3() + { + NewLocalTestbed().RunTest(Testsuite.Ownership3); + } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs b/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs index be58c28..8bd35b2 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; namespace Capnp.Net.Runtime.Tests { [TestClass] + [TestCategory("Coverage")] public class TcpRpcErrorHandling: TestBase { class MemStreamEndpoint : IEndpoint diff --git a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs index 0066c40..e878920 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs @@ -166,5 +166,23 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(impl.IsDisposed); } + + [TestMethod] + public void Ownership1() + { + NewLocalhostTcpTestbed().RunTest(Testsuite.Ownership1); + } + + [TestMethod] + public void Ownership2() + { + NewLocalhostTcpTestbed().RunTest(Testsuite.Ownership2); + } + + [TestMethod] + public void Ownership3() + { + NewLocalhostTcpTestbed().RunTest(Testsuite.Ownership3); + } } } diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs index dc48702..1b3486d 100644 --- a/Capnp.Net.Runtime.Tests/Testsuite.cs +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -532,5 +532,43 @@ namespace Capnp.Net.Runtime.Tests Assert.IsFalse(impl.IsDisposed); } } + + public static void Ownership1(ITestbed testbed) + { + var impl = new TestMoreStuffImpl(new Counters()); + using (var main = testbed.ConnectMain(impl)) + { + var tcs = new TaskCompletionSource(); + var ti = new TestInterfaceImpl(new Counters(), tcs); + testbed.MustComplete(main.CallFoo(ti, default)); + testbed.MustComplete(tcs.Task); + } + } + + public static void Ownership2(ITestbed testbed) + { + var impl = new TestMoreStuffImpl(new Counters()); + using (var main = testbed.ConnectMain(impl)) + using (var nullProxy = main.GetNull().Eager(true)) + { + var tcs = new TaskCompletionSource(); + var ti = new TestInterfaceImpl(new Counters(), tcs); + testbed.MustComplete(nullProxy.CallFoo(ti, default)); + testbed.MustComplete(tcs.Task); + } + } + + public static void Ownership3(ITestbed testbed) + { + var impl = new TestMoreStuffImpl(new Counters()); + using (var main = testbed.ConnectMain(impl)) + using (var nullProxy = main.GetNull(new CancellationToken(true)).Eager(true)) + { + var tcs = new TaskCompletionSource(); + var ti = new TestInterfaceImpl(new Counters(), tcs); + testbed.MustComplete(nullProxy.CallFoo(ti, default)); + testbed.MustComplete(tcs.Task); + } + } } } diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 422e7b3..2edffbc 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -167,12 +167,12 @@ namespace Capnp.Net.Runtime.Tests void ITestbed.MustComplete(params Task[] tasks) { - Assert.IsTrue(Task.WhenAll(tasks).IsCompleted); + Assert.IsTrue(tasks.All(t => t.IsCompleted)); } void ITestbed.MustNotComplete(params Task[] tasks) { - Assert.IsFalse(Task.WhenAny(tasks).IsCompleted); + Assert.IsFalse(tasks.Any(t => t.IsCompleted)); } } @@ -248,14 +248,30 @@ namespace Capnp.Net.Runtime.Tests return _client.GetMain(); } + static Task[] GulpExceptions(Task[] tasks) + { + async Task Gulp(Task t) + { + try + { + await t; + } + catch + { + } + } + + return tasks.Select(Gulp).ToArray(); + } + void ITestbed.MustComplete(params Task[] tasks) { - Assert.IsTrue(Task.WaitAll(tasks, MediumNonDbgTimeout)); + Assert.IsTrue(Task.WaitAll(GulpExceptions(tasks), MediumNonDbgTimeout)); } void ITestbed.MustNotComplete(params Task[] tasks) { - Assert.AreEqual(-1, Task.WaitAny(tasks, ShortTimeout)); + Assert.AreEqual(-1, Task.WaitAny(GulpExceptions(tasks), ShortTimeout)); } void ITestbed.FlushCommunication() diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs index ea02416..702176c 100644 --- a/Capnp.Net.Runtime/DeserializerState.cs +++ b/Capnp.Net.Runtime/DeserializerState.cs @@ -45,6 +45,7 @@ namespace Capnp /// The kind of object this state currently represents. /// public ObjectKind Kind { get; set; } + bool _disposed; /// /// The capabilities imported from the capability table. Only valid in RPC context. /// @@ -65,6 +66,7 @@ namespace Capnp StructPtrCount = 1; Kind = ObjectKind.Struct; Caps = null; + _disposed = false; } /// @@ -685,12 +687,14 @@ namespace Capnp public void Dispose() { - if (Caps != null) + if (Caps != null && !_disposed) { foreach (var cap in Caps) { cap?.Release(false); } + + _disposed = true; } } } diff --git a/Capnp.Net.Runtime/ObjectKind.cs b/Capnp.Net.Runtime/ObjectKind.cs index bdabf6f..80909eb 100644 --- a/Capnp.Net.Runtime/ObjectKind.cs +++ b/Capnp.Net.Runtime/ObjectKind.cs @@ -4,9 +4,7 @@ namespace Capnp { /// /// The different kinds of Cap'n Proto objects. - /// Despite this is a [Flags] enum, it does not make sense to mutually combine literals. /// - [Flags] public enum ObjectKind: byte { /// diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index e0ede4e..1e621b5 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -76,6 +76,7 @@ namespace Capnp.Rpc /// The underlying promise /// is null. /// The task was not registered using MakePipelineAware. + [Obsolete("Please re-generate capnp code-behind. GetAnswer(task).Access(...) was replaced by Access(task, ...)")] public static IPromisedAnswer GetAnswer(Task task) { if (!_taskTable.TryGetValue(task, out var answer)) diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index 2c06584..ae1eef4 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -91,12 +91,28 @@ namespace Capnp.Rpc async Task CallImpl(ulong interfaceId, ushort methodId, DynamicSerializerState args, CancellationToken cancellationToken) { - var cap = await WhenResolved; + ConsumedCapability? cap; + try + { + cap = await WhenResolved; + } + catch + { + args.Dispose(); + throw; + } - cancellationToken.ThrowIfCancellationRequested(); + if (cancellationToken.IsCancellationRequested) + { + args.Dispose(); + cancellationToken.ThrowIfCancellationRequested(); + } if (cap == null) + { + args.Dispose(); throw new RpcException("Broken capability"); + } using var proxy = new Proxy(cap); var call = proxy.Call(interfaceId, methodId, args, default); diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs index ef5cc29..696dbbb 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs @@ -72,7 +72,10 @@ namespace Capnp.Rpc cancellationToken.ThrowIfCancellationRequested(); if (proxy.IsNull) + { + args.Dispose(); throw new RpcException("Broken capability"); + } var call = proxy.Call(interfaceId, methodId, args, default); var whenReturned = call.WhenReturned; diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index c4d0eed..b6dd739 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -50,17 +50,9 @@ namespace Capnp.Rpc static async void DisposeCtrWhenReturned(CancellationTokenRegistration ctr, IPromisedAnswer answer) { - try - { - await answer.WhenReturned; - } - catch - { - } - finally - { - ctr.Dispose(); - } + try { await answer.WhenReturned; } + catch { } + finally { ctr.Dispose(); } } /// @@ -80,10 +72,16 @@ namespace Capnp.Rpc bool obsoleteAndIgnored, CancellationToken cancellationToken = default) { if (_disposedValue) + { + args.Dispose(); throw new ObjectDisposedException(nameof(Proxy)); + } if (ConsumedCap == null) + { + args.Dispose(); throw new InvalidOperationException("Cannot call null capability"); + } var answer = ConsumedCap.DoCall(interfaceId, methodId, args); @@ -172,7 +170,7 @@ namespace Capnp.Rpc ~Proxy() { #if DebugFinalizers - Logger.LogWarning($"Caught orphaned Proxy, created from here: {CreatorStackTrace}."); + Logger?.LogWarning($"Caught orphaned Proxy, created from here: {CreatorStackTrace}."); #endif Dispose(false); diff --git a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs index b6beae8..d47a46f 100644 --- a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs @@ -50,7 +50,7 @@ namespace Capnp.Rpc ~RefCountingCapability() { #if DebugFinalizers - Logger.LogWarning($"Caught orphaned capability, created from here: {CreatorStackTrace}."); + Logger?.LogWarning($"Caught orphaned capability, created from here: {CreatorStackTrace}."); #endif Dispose(false); diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index 8423581..4631f8b 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -112,9 +112,17 @@ namespace Capnp.Rpc if (!_question.StateFlags.HasFlag(PendingQuestion.State.TailCall) && _question.StateFlags.HasFlag(PendingQuestion.State.Returned)) { - if (ResolvedCap == null) + try { - throw new RpcException("Answer did not resolve to expected capability"); + if (ResolvedCap == null) + { + throw new RpcException("Answer did not resolve to expected capability"); + } + } + catch + { + args.Dispose(); + throw; } return CallOnResolution(interfaceId, methodId, args); @@ -126,11 +134,13 @@ namespace Capnp.Rpc #endif if (_question.StateFlags.HasFlag(PendingQuestion.State.Disposed)) { + args.Dispose(); throw new ObjectDisposedException(nameof(PendingQuestion)); } if (_question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested)) { + args.Dispose(); throw new InvalidOperationException("Finish request was already sent"); } diff --git a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs index 868e775..b6a9cf8 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs @@ -90,9 +90,13 @@ namespace Capnp.Rpc { // Two reasons for ignoring exceptions on the previous task (i.e. not _.Wait()ing): // 1. A faulting predecessor, especially due to cancellation, must not have any impact on this one. - // 2. A faulting disembargo request would be a fatal protocol error, resulting in Abort() - we're dead anyway. + // 2. A faulting disembargo request would imply that the other side cannot send pending requests anyway. - cancellationTokenSource.Token.ThrowIfCancellationRequested(); + if (cancellationTokenSource.Token.IsCancellationRequested) + { + args.Dispose(); + cancellationTokenSource.Token.ThrowIfCancellationRequested(); + } using var proxy = new Proxy(ResolvedCap); return proxy.Call(interfaceId, methodId, args, default); diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index 7bdb9e2..26549f7 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -11,7 +11,7 @@ namespace Capnp /// by the code generator. Particularly, those writer classes are actually specializations of SerializerState, adding convenience methods /// for accessing the struct's fields. /// - public class SerializerState : IStructSerializer + public class SerializerState : IStructSerializer, IDisposable { /// /// Constructs a SerializerState instance for use in RPC context. @@ -42,6 +42,7 @@ namespace Capnp internal uint CapabilityIndex { get; set; } SerializerState[]? _linkedStates; + bool _disposed; /// /// Constructs an unbound serializer state. @@ -1380,5 +1381,18 @@ namespace Capnp var cap = StructReadRawCap(slot); return new Rpc.BareProxy(cap); } + + public void Dispose() + { + if (Caps != null && !_disposed) + { + foreach (var cap in Caps) + { + cap?.Release(false); + } + + _disposed = true; + } + } } } \ No newline at end of file From 9dbf474334606f9ee23261058a7e46ef40577e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 22 Mar 2020 16:08:28 +0100 Subject: [PATCH 20/76] fine-tuning cap lifecycle mgmt. added missing xml doc. --- Capnp.Net.Runtime/Capnp.Net.Runtime.csproj | 2 +- Capnp.Net.Runtime/DeserializerState.cs | 9 +-- Capnp.Net.Runtime/Rpc/CapabilityReflection.cs | 3 - Capnp.Net.Runtime/Rpc/ConsumedCapability.cs | 6 +- Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs | 6 ++ Capnp.Net.Runtime/Rpc/Impatient.cs | 10 ++- .../Rpc/Interception/CensorCapability.cs | 2 +- .../Rpc/LocalAnswerCapability.cs | 2 +- Capnp.Net.Runtime/Rpc/LocalCapability.cs | 15 +--- Capnp.Net.Runtime/Rpc/PendingAnswer.cs | 2 +- Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 6 +- Capnp.Net.Runtime/Rpc/Proxy.cs | 10 ++- .../Rpc/RefCountingCapability.cs | 33 +-------- .../Rpc/RemoteAnswerCapability.cs | 2 +- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 71 ++++++++++++++++++- Capnp.Net.Runtime/SerializerState.cs | 6 +- 16 files changed, 114 insertions(+), 71 deletions(-) diff --git a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj index 6f81750..b7675b9 100644 --- a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj +++ b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj @@ -29,7 +29,7 @@ - DebugFinalizers + diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs index 702176c..735ae7e 100644 --- a/Capnp.Net.Runtime/DeserializerState.cs +++ b/Capnp.Net.Runtime/DeserializerState.cs @@ -636,9 +636,6 @@ namespace Capnp /// /// Capability interface /// index within this struct's pointer table - /// debugging aid - /// debugging aid - /// debugging aid /// capability instance or null if pointer was null /// negative index /// state does not represent a struct, invalid pointer, @@ -685,15 +682,19 @@ namespace Capnp return (Rpc.CapabilityReflection.CreateProxy(Caps[(int)CapabilityIndex]) as T)!; } + /// + /// Releases the capability table + /// public void Dispose() { if (Caps != null && !_disposed) { foreach (var cap in Caps) { - cap?.Release(false); + cap?.Release(); } + Caps = null; _disposed = true; } } diff --git a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs index 6e10a58..4edf578 100644 --- a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs +++ b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs @@ -251,9 +251,6 @@ namespace Capnp.Rpc /// /// Capability interface. Must be annotated with . /// low-level capability - /// debugging aid - /// debugging aid - /// debugging aid /// The Proxy instance which implements . /// is null. /// did not qualify as capability interface. diff --git a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs index 452bcd3..3faa492 100644 --- a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs @@ -20,11 +20,7 @@ namespace Capnp.Rpc internal abstract void Unfreeze(); internal abstract void AddRef(); - internal abstract void Release( - bool keepAlive, - [System.Runtime.CompilerServices.CallerMemberName] string methodName = "", - [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", - [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0); + internal abstract void Release(); #if DebugFinalizers internal Proxy? OwningProxy { get; set; } diff --git a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs index 6fc1788..729b34d 100644 --- a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs @@ -24,6 +24,12 @@ namespace Capnp.Rpc /// Pipelined low-level capability ConsumedCapability? Access(MemberAccessPath access); + /// + /// + /// + /// Creates a low-level capability for promise pipelining. + /// Task returning the proxy whose ownership will be taken over + /// ConsumedCapability? Access(MemberAccessPath access, Task proxyTask); } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index 1e621b5..7b2c7b3 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -93,6 +93,13 @@ namespace Capnp.Rpc return answer; } + /// + /// Returns a promise-pipelined capability for a remote method invocation Task. + /// + /// remote method invocation task + /// path to the desired capability + /// task returning a proxy to the desired capability + /// Pipelined low-level capability public static ConsumedCapability? Access(Task task, MemberAccessPath access, Task proxyTask) { var answer = TryGetAnswer(task); @@ -106,9 +113,6 @@ namespace Capnp.Rpc /// /// Capability interface type /// The task - /// debugging aid - /// debugging aid - /// debugging aid /// A proxy for the given task. /// is null. /// did not diff --git a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs index 3323c16..0889c87 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs @@ -18,7 +18,7 @@ namespace Capnp.Rpc.Interception protected override void ReleaseRemotely() { - InterceptedCapability.Release(false); + InterceptedCapability.Release(); } internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs index 696dbbb..08a5437 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs @@ -12,7 +12,7 @@ namespace Capnp.Rpc var result = await answer; var cap = access.Eval(result); var proxy = new Proxy(cap); - cap?.Release(false); + cap?.Release(); return proxy; } diff --git a/Capnp.Net.Runtime/Rpc/LocalCapability.cs b/Capnp.Net.Runtime/Rpc/LocalCapability.cs index 5ae7c91..3e1954a 100644 --- a/Capnp.Net.Runtime/Rpc/LocalCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalCapability.cs @@ -22,7 +22,6 @@ namespace Capnp.Rpc } public Skeleton ProvidedCap { get; } - int _releaseFlag; LocalCapability(Skeleton providedCap) { @@ -31,20 +30,12 @@ namespace Capnp.Rpc internal override void AddRef() { - if (0 == Interlocked.CompareExchange(ref _releaseFlag, 0, 1)) - ProvidedCap.Claim(); + ProvidedCap.Claim(); } - internal override void Release( - bool keepAlive, - [System.Runtime.CompilerServices.CallerMemberName] string methodName = "", - [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", - [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0) + internal override void Release() { - if (keepAlive) - Interlocked.Exchange(ref _releaseFlag, 1); - else - ProvidedCap.Relinquish(); + ProvidedCap.Relinquish(); } internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) diff --git a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs index 3b4bc38..4bc0f89 100644 --- a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs @@ -155,7 +155,7 @@ namespace Capnp.Rpc { foreach (var cap in aorcq.Answer.Caps) { - cap?.Release(false); + cap?.Release(); } } } diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index 548f907..6d4f34c 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -277,13 +277,13 @@ namespace Capnp.Rpc { foreach (var cap in inParams.Caps!) { - cap?.Release(false); + cap?.Release(); } } if (target != null) { - target.Release(false); + target.Release(); } } @@ -291,7 +291,7 @@ namespace Capnp.Rpc { foreach (var cap in outParams.Caps!) { - cap?.Release(false); + cap?.Release(); } } diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index b6dd739..22957a9 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -11,6 +11,12 @@ namespace Capnp.Rpc /// public class Proxy : IDisposable, IResolvingCapability { + /// + /// Creates a new proxy object for an existing implementation or proxy, sharing its ownership. + /// + /// Capability interface + /// instance to share + /// public static T Share(T obj) where T: class { if (obj is Proxy proxy) @@ -149,14 +155,14 @@ namespace Capnp.Rpc { if (disposing) { - ConsumedCap?.Release(false); + ConsumedCap?.Release(); } else { // When called from the Finalizer, we must not throw. // But when reference counting goes wrong, ConsumedCapability.Release() will throw an InvalidOperationException. // The only option here is to suppress that exception. - try { ConsumedCap?.Release(false); } + try { ConsumedCap?.Release(); } catch { } } diff --git a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs index d47a46f..7ad404e 100644 --- a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs @@ -26,17 +26,8 @@ namespace Capnp.Rpc // Value 0 has the special meaning of being in state C. long _refCount = 1; -#if DebugCapabilityLifecycle || DebugFinalizers - ILogger Logger { get; } = Logging.CreateLogger(); -#endif - -#if DebugCapabilityLifecycle - string? _releasingMethodName; - string? _releasingFilePath; - int _releasingLineNumber; -#endif - #if DebugFinalizers + ILogger Logger { get; } = Logging.CreateLogger(); string CreatorStackTrace { get; set; } #endif @@ -83,11 +74,7 @@ namespace Capnp.Rpc { lock (_reentrancyBlocker) { - if (_refCount == int.MinValue) - { - _refCount = 2; - } - else if (++_refCount <= 1) + if (++_refCount <= 1) { --_refCount; @@ -101,30 +88,16 @@ namespace Capnp.Rpc } } - internal sealed override void Release( - bool keepAlive, - [System.Runtime.CompilerServices.CallerMemberName] string methodName = "", - [System.Runtime.CompilerServices.CallerFilePath] string filePath = "", - [System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0) + internal sealed override void Release() { lock (_reentrancyBlocker) { switch (_refCount) { - case 2 when keepAlive: - _refCount = int.MinValue; - break; - case 1: // initial state, actually ref. count 0 case 2: // actually ref. count 1 _refCount = 0; -#if DebugCapabilityLifecycle - _releasingMethodName = methodName; - _releasingFilePath = filePath; - _releasingLineNumber = lineNumber; -#endif - Dispose(true); GC.SuppressFinalize(this); break; diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index 4631f8b..e2a49ac 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -42,7 +42,7 @@ namespace Capnp.Rpc var result = await question.WhenReturned; var cap = access.Eval(result); var proxy = new Proxy(cap); - cap?.Release(false); + cap?.Release(); return proxy; } diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 8b6d9ce..195fcd5 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -60,11 +60,25 @@ namespace Capnp.Rpc } } + /// + /// Stateful implementation for hosting a two-party RPC session. may own multiple mutually + /// independent endpoints. + /// public class RpcEndpoint : IEndpoint, IRpcEndpoint { + /// + /// Endpoint state + /// public enum EndpointState { + /// + /// Active means ready for exchanging RPC messages. + /// Active, + + /// + /// The session is closed, either deliberately or due to an error condition. + /// Dismissed } @@ -95,8 +109,14 @@ namespace Capnp.Rpc State = EndpointState.Active; } + /// + /// Session state + /// public EndpointState State { get; private set; } + /// + /// Closes the session, clears export table, terminates all pending questions and enters 'Dismissed' state. + /// public void Dismiss() { lock (_reentrancyBlocker) @@ -120,6 +140,10 @@ namespace Capnp.Rpc _tx.Dismiss(); } + /// + /// Feeds a frame for processing + /// + /// frame to process public void Forward(WireFrame frame) { if (State == EndpointState.Dismissed) @@ -129,11 +153,43 @@ namespace Capnp.Rpc ProcessFrame(frame); } + /// + /// Number of frames sent so far + /// public long SendCount => Interlocked.Read(ref _sendCount); + + /// + /// Number of frames received so far + /// public long RecvCount => Interlocked.Read(ref _recvCount); - public int ImportedCapabilityCount => _importTable.Count; - public int ExportedCapabilityCount => _exportTable.Count; + /// + /// Current number of entries in import table + /// + public int ImportedCapabilityCount + { + get + { + lock (_reentrancyBlocker) + { + return _importTable.Count; + } + } + } + + /// + /// Current number of entries in export table + /// + public int ExportedCapabilityCount + { + get + { + lock (_reentrancyBlocker) + { + return _exportTable.Count; + } + } + } void Tx(WireFrame frame) { @@ -1095,6 +1151,10 @@ namespace Capnp.Rpc } } + /// + /// Queries the peer for its bootstrap capability + /// + /// low-level capability public ConsumedCapability QueryMain() { var mb = MessageBuilder.Create(); @@ -1370,7 +1430,7 @@ namespace Capnp.Rpc else { postAction += cap.Export(this, capDesc); - cap.Release(false); + cap.Release(); } } @@ -1498,6 +1558,11 @@ namespace Capnp.Rpc readonly ConcurrentBag _inboundEndpoints = new ConcurrentBag(); + /// + /// Adds an endpoint + /// + /// endpoint for handling outgoing messages + /// endpoint for handling incoming messages public RpcEndpoint AddEndpoint(IEndpoint outboundEndpoint) { var inboundEndpoint = new RpcEndpoint(this, outboundEndpoint); diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index 26549f7..8a19bba 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -1382,15 +1382,19 @@ namespace Capnp return new Rpc.BareProxy(cap); } + /// + /// Releases the capability table + /// public void Dispose() { if (Caps != null && !_disposed) { foreach (var cap in Caps) { - cap?.Release(false); + cap?.Release(); } + Caps.Clear(); _disposed = true; } } From 6af523b261540063f46275d6c53fed6b75566617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Thu, 26 Mar 2020 21:30:30 +0100 Subject: [PATCH 21/76] support several new codegen annotations minor fixes improved CC --- Capnp.Net.Runtime.Tests/RpcSchemaTests.cs | 399 +++++ Capnp.Net.Runtime/Rpc/CapabilityReflection.cs | 2 +- Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 4 +- .../Rpc/RemoteAnswerCapability.cs | 8 +- Capnp.Net.Runtime/Rpc/RemoteCapability.cs | 2 +- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 44 +- Capnp.Net.Runtime/Rpc/rpc.cs | 436 ++--- .../CodeGenerator.feature | 3 +- .../CodeGenerator.feature.cs | 15 + .../Embedded Resources/rpc-csharp.capnp.bin | Bin 0 -> 66744 bytes .../FeatureSteps/CodeGeneratorSteps.cs | 4 +- .../No Resources/rpc-csharp.capnp | 1415 +++++++++++++++++ .../CodeGen/CodeGenerator.cs | 44 +- .../CodeGen/CommonSnippetGen.cs | 2 +- CapnpC.CSharp.Generator/CodeGen/GenNames.cs | 21 + CapnpC.CSharp.Generator/Model/GenFile.cs | 2 + CapnpC.CSharp.Generator/Model/SchemaModel.cs | 2 + .../Model/SupportedAnnotations.cs | 32 + include/csharp.capnp | 13 +- scripts/measure-coverage.ps1 | 11 +- 20 files changed, 2219 insertions(+), 240 deletions(-) create mode 100644 CapnpC.CSharp.Generator.Tests/Embedded Resources/rpc-csharp.capnp.bin create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/rpc-csharp.capnp diff --git a/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs b/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs index f8841ec..82ab2d0 100644 --- a/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs +++ b/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs @@ -1,5 +1,7 @@ using Capnp.Rpc; using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; namespace Capnp.Net.Runtime.Tests { @@ -366,5 +368,402 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual("reason", r.Unimplemented.Resolve.Exception.Reason); } } + + void ConstructReconstructTest(Func construct, Action verify) + where TD : class, ICapnpSerializable, new() + where TW: SerializerState, new() + { + var obj = construct(); + + var mb = MessageBuilder.Create(); + var root = mb.BuildRoot(); + obj.Serialize(root); + var d = (DeserializerState)root; + var obj2 = new TD(); + obj2.Deserialize(d); + + verify(obj2); + } + + [TestMethod] + public void DcMessageAbort() + { + ConstructReconstructTest( + () => new Message() + { + Abort = new Rpc.Exception() + { + Reason = "problem" + } + }, + msg => + { + Assert.IsNotNull(msg.Abort); + Assert.IsNull(msg.Accept); + Assert.AreEqual("problem", msg.Abort.Reason); + } + ); + } + + [TestMethod] + public void DcMessageAccept() + { + ConstructReconstructTest( + () => new Message() + { + Accept = new Accept() + { + QuestionId = 123u, + Embargo = true + } + }, + msg => + { + Assert.IsNotNull(msg.Accept); + Assert.AreEqual(123u, msg.Accept.QuestionId); + Assert.IsTrue(msg.Accept.Embargo); + } + ); + } + + [TestMethod] + public void DcMessageUnimplementedJoin() + { + ConstructReconstructTest( + () => new Message() + { + Unimplemented = new Message() + { + Join = new Join() + { + QuestionId = 456u, + Target = new MessageTarget() + { + ImportedCap = 789u + } + } + } + }, + msg => + { + Assert.IsNotNull(msg.Unimplemented); + Assert.IsNotNull(msg.Unimplemented.Join); + Assert.AreEqual(456u, msg.Unimplemented.Join.QuestionId); + Assert.IsNotNull(msg.Unimplemented.Join.Target); + Assert.AreEqual(789u, msg.Unimplemented.Join.Target.ImportedCap); + } + ); + } + + [TestMethod] + public void DcMessageCall() + { + ConstructReconstructTest( + () => new Message() + { + Call = new Call() + { + AllowThirdPartyTailCall = true, + InterfaceId = 0x12345678abcdef, + MethodId = 0x5555, + Params = new Payload() + { + CapTable = new List() + { + new CapDescriptor() + { + ReceiverAnswer = new PromisedAnswer() + { + QuestionId = 42u, + Transform = new List() + { + new PromisedAnswer.Op() + { + GetPointerField = 3 + } + } + }, + }, + new CapDescriptor() + { + ReceiverHosted = 7u + }, + new CapDescriptor() + { + SenderHosted = 8u + }, + new CapDescriptor() + { + SenderPromise = 9u + }, + new CapDescriptor() + { + ThirdPartyHosted = new ThirdPartyCapDescriptor() + { + VineId = 10u + } + } + } + }, + QuestionId = 57u, + SendResultsTo = new Call.sendResultsTo() + { + which = Call.sendResultsTo.WHICH.Caller + }, + Target = new MessageTarget() + { + PromisedAnswer = new PromisedAnswer() + { + QuestionId = 12u + } + } + } + }, + msg => + { + Assert.IsNotNull(msg.Call); + Assert.IsTrue(msg.Call.AllowThirdPartyTailCall); + Assert.AreEqual(0x12345678abcdeful, msg.Call.InterfaceId); + Assert.AreEqual(0x5555u, msg.Call.MethodId); + Assert.IsNotNull(msg.Call.Params); + Assert.IsNotNull(msg.Call.Params.CapTable); + Assert.AreEqual(5, msg.Call.Params.CapTable.Count); + Assert.IsNotNull(msg.Call.Params.CapTable[0].ReceiverAnswer); + Assert.AreEqual(42u, msg.Call.Params.CapTable[0].ReceiverAnswer.QuestionId); + Assert.IsNotNull(msg.Call.Params.CapTable[0].ReceiverAnswer.Transform); + Assert.AreEqual(1, msg.Call.Params.CapTable[0].ReceiverAnswer.Transform.Count); + Assert.AreEqual((ushort)3, msg.Call.Params.CapTable[0].ReceiverAnswer.Transform[0].GetPointerField); + Assert.AreEqual(7u, msg.Call.Params.CapTable[1].ReceiverHosted); + Assert.AreEqual(8u, msg.Call.Params.CapTable[2].SenderHosted); + Assert.AreEqual(9u, msg.Call.Params.CapTable[3].SenderPromise); + Assert.IsNotNull(msg.Call.Params.CapTable[4].ThirdPartyHosted); + Assert.AreEqual(10u, msg.Call.Params.CapTable[4].ThirdPartyHosted.VineId); + Assert.AreEqual(57u, msg.Call.QuestionId); + Assert.IsNotNull(msg.Call.SendResultsTo); + Assert.AreEqual(Call.sendResultsTo.WHICH.Caller, msg.Call.SendResultsTo.which); + Assert.IsNotNull(msg.Call.Target); + Assert.IsNotNull(msg.Call.Target.PromisedAnswer); + Assert.AreEqual(12u, msg.Call.Target.PromisedAnswer.QuestionId); + } + ); + } + + [TestMethod] + public void DcMessageReturnResults() + { + ConstructReconstructTest( + () => new Message() + { + Return = new Return() + { + AnswerId = 123u, + ReleaseParamCaps = false, + Results = new Payload() + { + CapTable = new List() + } + } + }, + msg => + { + Assert.IsNotNull(msg.Return); + Assert.AreEqual(123u, msg.Return.AnswerId); + Assert.IsFalse(msg.Return.ReleaseParamCaps); + Assert.IsNotNull(msg.Return.Results); + Assert.IsNotNull(msg.Return.Results.CapTable); + Assert.AreEqual(0, msg.Return.Results.CapTable.Count); + } + ); + } + + [TestMethod] + public void DcMessageReturnException() + { + ConstructReconstructTest( + () => new Message() + { + Return = new Return() + { + AnswerId = 123u, + ReleaseParamCaps = true, + Exception = new Rpc.Exception() + { + Reason = "bad", + TheType = Rpc.Exception.Type.overloaded + } + } + }, + msg => + { + Assert.IsNotNull(msg.Return); + Assert.AreEqual(123u, msg.Return.AnswerId); + Assert.IsTrue(msg.Return.ReleaseParamCaps); + Assert.IsNotNull(msg.Return.Exception); + Assert.AreEqual("bad", msg.Return.Exception.Reason); + Assert.AreEqual(Rpc.Exception.Type.overloaded, msg.Return.Exception.TheType); + } + ); + } + + [TestMethod] + public void DcMessageReturnTakeFromOtherQuestion() + { + ConstructReconstructTest( + () => new Message() + { + Return = new Return() + { + AnswerId = 123u, + ReleaseParamCaps = true, + TakeFromOtherQuestion = 321u + } + }, + msg => + { + Assert.IsNotNull(msg.Return); + Assert.AreEqual(123u, msg.Return.AnswerId); + Assert.IsTrue(msg.Return.ReleaseParamCaps); + Assert.AreEqual(321u, msg.Return.TakeFromOtherQuestion); + } + ); + } + + [TestMethod] + public void DcMessageFinish() + { + ConstructReconstructTest( + () => new Message() + { + Finish = new Finish() + { + QuestionId = 321u, + ReleaseResultCaps = true + } + }, + msg => + { + Assert.IsNotNull(msg.Finish); + Assert.AreEqual(321u, msg.Finish.QuestionId); + Assert.IsTrue(msg.Finish.ReleaseResultCaps); + } + ); + } + + [TestMethod] + public void DcMessageResolve() + { + ConstructReconstructTest( + () => new Message() + { + Resolve = new Resolve() + { + PromiseId = 555u, + Exception = new Rpc.Exception() + { + Reason = "error", + TheType = Rpc.Exception.Type.failed + } + } + }, + msg => + { + Assert.IsNotNull(msg.Resolve); + Assert.AreEqual(555u, msg.Resolve.PromiseId); + Assert.AreEqual("error", msg.Resolve.Exception.Reason); + Assert.AreEqual(Rpc.Exception.Type.failed, msg.Resolve.Exception.TheType); + } + ); + } + + [TestMethod] + public void DcMessageRelease() + { + ConstructReconstructTest( + () => new Message() + { + Release = new Release() + { + Id = 6000u, + ReferenceCount = 6u + } + }, + msg => + { + Assert.IsNotNull(msg.Release); + Assert.AreEqual(6000u, msg.Release.Id); + Assert.AreEqual(6u, msg.Release.ReferenceCount); + } + ); + } + + [TestMethod] + public void DcMessageBootstrap() + { + ConstructReconstructTest( + () => new Message() + { + Bootstrap = new Bootstrap() + { + QuestionId = 99u + } + }, + msg => + { + Assert.IsNotNull(msg.Bootstrap); + Assert.AreEqual(99u, msg.Bootstrap.QuestionId); + } + ); + } + + [TestMethod] + public void DcMessageProvide() + { + ConstructReconstructTest( + () => new Message() + { + Provide = new Provide() + { + Target = new MessageTarget() + { + ImportedCap = 7u + } + } + }, + msg => + { + Assert.IsNotNull(msg.Provide); + Assert.IsNotNull(msg.Provide.Target); + Assert.AreEqual(7u, msg.Provide.Target.ImportedCap); + } + ); + } + + [TestMethod] + public void DcMessageDisembargo() + { + ConstructReconstructTest( + () => new Message() + { + Disembargo = new Disembargo() + { + Context = new Disembargo.context() + { + ReceiverLoopback = 900u + }, + Target = new MessageTarget() + } + }, + msg => + { + Assert.IsNotNull(msg.Disembargo); + Assert.IsNotNull(msg.Disembargo.Context); + Assert.AreEqual(900u, msg.Disembargo.Context.ReceiverLoopback); + Assert.IsNotNull(msg.Disembargo.Target); + Assert.IsNull(msg.Disembargo.Target.ImportedCap); + Assert.IsNull(msg.Disembargo.Target.PromisedAnswer); + Assert.AreEqual(MessageTarget.WHICH.undefined, msg.Disembargo.Target.which); + } + ); + } } } diff --git a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs index 4edf578..ce0205a 100644 --- a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs +++ b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs @@ -229,7 +229,7 @@ namespace Capnp.Rpc } /// - /// Checkes whether a given type qualifies as cpapbility interface./> on failure. + /// Checks whether a given type qualifies as cpapbility interface. /// /// type to check /// true when is a capability interface diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index 6d4f34c..b660d6d 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -165,7 +165,7 @@ namespace Capnp.Rpc SetReturned(); } - _tcs.TrySetException(new RpcException(exception.Reason)); + _tcs.TrySetException(new RpcException(exception.Reason ?? "unknown reason")); } internal void OnException(System.Exception exception) @@ -313,7 +313,7 @@ namespace Capnp.Rpc } var msg = (Message.WRITER)inParams!.MsgBuilder!.Root!; - Debug.Assert(msg.Call.Target.which != MessageTarget.WHICH.undefined); + Debug.Assert(msg.Call!.Target.which != MessageTarget.WHICH.undefined); var call = msg.Call; call.QuestionId = QuestionId; call.SendResultsTo.which = IsTailCall ? diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index e2a49ac..fd47935 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -101,7 +101,7 @@ namespace Capnp.Rpc protected override void GetMessageTarget(MessageTarget.WRITER wr) { wr.which = MessageTarget.WHICH.PromisedAnswer; - wr.PromisedAnswer.QuestionId = _question.QuestionId; + wr.PromisedAnswer!.QuestionId = _question.QuestionId; _access.Serialize(wr.PromisedAnswer); } @@ -178,7 +178,7 @@ namespace Capnp.Rpc var call = base.SetupMessage(args, interfaceId, methodId); call.Target.which = MessageTarget.WHICH.PromisedAnswer; - call.Target.PromisedAnswer.QuestionId = _question.QuestionId; + call.Target.PromisedAnswer!.QuestionId = _question.QuestionId; _access.Serialize(call.Target.PromisedAnswer); return call; @@ -243,8 +243,8 @@ namespace Capnp.Rpc if (endpoint == _ep) { writer.which = CapDescriptor.WHICH.ReceiverAnswer; - _access.Serialize(writer.ReceiverAnswer); - writer.ReceiverAnswer.QuestionId = _question.QuestionId; + _access.Serialize(writer.ReceiverAnswer!); + writer.ReceiverAnswer!.QuestionId = _question.QuestionId; } else if (_question.IsTailCall) { diff --git a/Capnp.Net.Runtime/Rpc/RemoteCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteCapability.cs index f198b29..1852c56 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteCapability.cs @@ -29,7 +29,7 @@ namespace Capnp.Rpc callMsg.which = Message.WHICH.Call; - var call = callMsg.Call; + var call = callMsg.Call!; call.AllowThirdPartyTailCall = false; call.InterfaceId = interfaceId; call.MethodId = methodId; diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 195fcd5..11c99b5 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -210,7 +210,7 @@ namespace Capnp.Rpc var mb = MessageBuilder.Create(); var msg = mb.BuildRoot(); msg.which = Message.WHICH.Abort; - msg.Abort.Reason = reason; + msg.Abort!.Reason = reason; Tx(mb.Frame); } @@ -233,18 +233,18 @@ namespace Capnp.Rpc var mb = MessageBuilder.Create(); var msg = mb.BuildRoot(); msg.which = Message.WHICH.Resolve; - var resolve = msg.Resolve; + var resolve = msg.Resolve!; try { var resolvedCap = resolvedCapGetter(); resolve.which = Resolve.WHICH.Cap; - resolvedCap.Export(this, resolve.Cap); + resolvedCap.Export(this, resolve.Cap!); } catch (System.Exception ex) { resolve.which = Resolve.WHICH.Exception; - resolve.Exception.Reason = ex.Message; + resolve.Exception!.Reason = ex.Message; } resolve.PromiseId = preliminaryId; @@ -364,7 +364,7 @@ namespace Capnp.Rpc var ans = bootstrap.MsgBuilder!.BuildRoot(); ans.which = Message.WHICH.Return; - var ret = ans.Return; + var ret = ans.Return!; ret.AnswerId = q; Task bootstrapTask; @@ -374,7 +374,7 @@ namespace Capnp.Rpc { ret.which = Return.WHICH.Results; bootstrap.SetCapability(bootstrap.ProvideCapability(LocalCapability.Create(bootstrapCap))); - ret.Results.Content = bootstrap; + ret.Results!.Content = bootstrap; bootstrapTask = Task.FromResult(bootstrap); } @@ -383,7 +383,7 @@ namespace Capnp.Rpc Logger.LogWarning("Peer asked for bootstrap capability, but no bootstrap capability was set."); ret.which = Return.WHICH.Exception; - ret.Exception.Reason = "No bootstrap capability present"; + ret.Exception!.Reason = "No bootstrap capability present"; bootstrapTask = Task.FromException(new RpcException(ret.Exception.Reason)); } @@ -403,7 +403,7 @@ namespace Capnp.Rpc } - if (bootstrapCap != null) + if (ret.Results != null) { ExportCapTableAndSend(bootstrap, ret.Results); } @@ -420,7 +420,7 @@ namespace Capnp.Rpc { var rmsg = mb.BuildRoot(); rmsg.which = Message.WHICH.Return; - var ret = rmsg.Return; + var ret = rmsg.Return!; ret.AnswerId = req.QuestionId; return ret; @@ -488,7 +488,7 @@ namespace Capnp.Rpc { case Call.sendResultsTo.WHICH.Caller: ret.which = Return.WHICH.Results; - ret.Results.Content = results.Rewrap(); + ret.Results!.Content = results.Rewrap(); ret.ReleaseParamCaps = releaseParamCaps; ExportCapTableAndSend(results, ret.Results); pendingAnswer.CapTable = ret.Results.CapTable; @@ -530,7 +530,7 @@ namespace Capnp.Rpc ReturnCall(ret => { ret.which = Return.WHICH.Exception; - ret.Exception.Reason = exception.Message; + ret.Exception!.Reason = exception.Message; ret.ReleaseParamCaps = releaseParamCaps; }); } @@ -824,7 +824,7 @@ namespace Capnp.Rpc break; case Resolve.WHICH.Exception: - resolvableCap.Break(resolve.Exception.Reason); + resolvableCap.Break(resolve.Exception.Reason ?? "unknown reason"); break; default: @@ -844,8 +844,8 @@ namespace Capnp.Rpc mb.InitCapTable(); var wr = mb.BuildRoot(); wr.which = Message.WHICH.Disembargo; - wr.Disembargo.Context.which = Disembargo.context.WHICH.ReceiverLoopback; - wr.Disembargo.Context.ReceiverLoopback = disembargo.Context.SenderLoopback; + wr.Disembargo!.Context.which = Disembargo.context.WHICH.ReceiverLoopback; + wr.Disembargo!.Context.ReceiverLoopback = disembargo.Context.SenderLoopback; var reply = wr.Disembargo; switch (disembargo.Target.which) @@ -871,7 +871,7 @@ namespace Capnp.Rpc var promisedAnswer = disembargo.Target.PromisedAnswer; reply.Target.which = MessageTarget.WHICH.PromisedAnswer; var replyPromisedAnswer = reply.Target.PromisedAnswer; - replyPromisedAnswer.QuestionId = disembargo.Target.PromisedAnswer.QuestionId; + replyPromisedAnswer!.QuestionId = disembargo.Target.PromisedAnswer.QuestionId; int count = promisedAnswer.Transform.Count; replyPromisedAnswer.Transform.Init(count); @@ -1162,7 +1162,7 @@ namespace Capnp.Rpc var req = mb.BuildRoot(); req.which = Message.WHICH.Bootstrap; var pendingBootstrap = AllocateQuestion(null, null); - req.Bootstrap.QuestionId = pendingBootstrap.QuestionId; + req.Bootstrap!.QuestionId = pendingBootstrap.QuestionId; Tx(mb.Frame); @@ -1237,7 +1237,7 @@ namespace Capnp.Rpc mb.InitCapTable(); var reply = mb.BuildRoot(); reply.which = Message.WHICH.Unimplemented; - Reserializing.DeepCopy(msg, reply.Unimplemented.Rewrap()); + Reserializing.DeepCopy(msg, reply.Unimplemented!.Rewrap()); Tx(mb.Frame); } @@ -1472,8 +1472,8 @@ namespace Capnp.Rpc var mb = MessageBuilder.Create(); var msg = mb.BuildRoot(); msg.which = Message.WHICH.Finish; - msg.Finish.QuestionId = questionId; - msg.Finish.ReleaseResultCaps = false; + msg.Finish!.QuestionId = questionId; + msg.Finish!.ReleaseResultCaps = false; try { @@ -1518,8 +1518,8 @@ namespace Capnp.Rpc var mb = MessageBuilder.Create(); var msg = mb.BuildRoot(); msg.which = Message.WHICH.Release; - msg.Release.Id = importId; - msg.Release.ReferenceCount = (uint)count; + msg.Release!.Id = importId; + msg.Release!.ReferenceCount = (uint)count; try { @@ -1540,7 +1540,7 @@ namespace Capnp.Rpc mb.InitCapTable(); var msg = mb.BuildRoot(); msg.which = Message.WHICH.Disembargo; - describe(msg.Disembargo.Target); + describe(msg.Disembargo!.Target); var ctx = msg.Disembargo.Context; ctx.which = Disembargo.context.WHICH.SenderLoopback; ctx.SenderLoopback = id; diff --git a/Capnp.Net.Runtime/Rpc/rpc.cs b/Capnp.Net.Runtime/Rpc/rpc.cs index 066bd98..632c62e 100644 --- a/Capnp.Net.Runtime/Rpc/rpc.cs +++ b/Capnp.Net.Runtime/Rpc/rpc.cs @@ -1,17 +1,19 @@ #pragma warning disable CS1591 -#nullable disable using Capnp; using Capnp.Rpc; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; namespace Capnp.Rpc { + [TypeId(0x91b79f1f808db032UL)] public class Message : ICapnpSerializable { + public const UInt64 typeId = 0x91b79f1f808db032UL; public enum WHICH : ushort { Unimplemented = 0, @@ -58,13 +60,13 @@ namespace Capnp.Rpc Release = CapnpSerializable.Create(reader.Release); break; case WHICH.ObsoleteSave: - ObsoleteSave = CapnpSerializable.Create(reader.ObsoleteSave); + ObsoleteSave = CapnpSerializable.Create(reader.ObsoleteSave); break; case WHICH.Bootstrap: Bootstrap = CapnpSerializable.Create(reader.Bootstrap); break; case WHICH.ObsoleteDelete: - ObsoleteDelete = CapnpSerializable.Create(reader.ObsoleteDelete); + ObsoleteDelete = CapnpSerializable.Create(reader.ObsoleteDelete); break; case WHICH.Provide: Provide = CapnpSerializable.Create(reader.Provide); @@ -84,7 +86,7 @@ namespace Capnp.Rpc } private WHICH _which = WHICH.undefined; - private object _content; + private object? _content; public WHICH which { get => _which; @@ -147,46 +149,46 @@ namespace Capnp.Rpc switch (which) { case WHICH.Unimplemented: - Unimplemented?.serialize(writer.Unimplemented); + Unimplemented?.serialize(writer.Unimplemented!); break; case WHICH.Abort: - Abort?.serialize(writer.Abort); + Abort?.serialize(writer.Abort!); break; case WHICH.Call: - Call?.serialize(writer.Call); + Call?.serialize(writer.Call!); break; case WHICH.Return: - Return?.serialize(writer.Return); + Return?.serialize(writer.Return!); break; case WHICH.Finish: - Finish?.serialize(writer.Finish); + Finish?.serialize(writer.Finish!); break; case WHICH.Resolve: - Resolve?.serialize(writer.Resolve); + Resolve?.serialize(writer.Resolve!); break; case WHICH.Release: - Release?.serialize(writer.Release); + Release?.serialize(writer.Release!); break; case WHICH.ObsoleteSave: - writer.ObsoleteSave.SetObject(ObsoleteSave); + writer.ObsoleteSave!.SetObject(ObsoleteSave); break; case WHICH.Bootstrap: - Bootstrap?.serialize(writer.Bootstrap); + Bootstrap?.serialize(writer.Bootstrap!); break; case WHICH.ObsoleteDelete: - writer.ObsoleteDelete.SetObject(ObsoleteDelete); + writer.ObsoleteDelete!.SetObject(ObsoleteDelete); break; case WHICH.Provide: - Provide?.serialize(writer.Provide); + Provide?.serialize(writer.Provide!); break; case WHICH.Accept: - Accept?.serialize(writer.Accept); + Accept?.serialize(writer.Accept!); break; case WHICH.Join: - Join?.serialize(writer.Join); + Join?.serialize(writer.Join!); break; case WHICH.Disembargo: - Disembargo?.serialize(writer.Disembargo); + Disembargo?.serialize(writer.Disembargo!); break; } } @@ -200,9 +202,9 @@ namespace Capnp.Rpc { } - public Capnp.Rpc.Message Unimplemented + public Capnp.Rpc.Message? Unimplemented { - get => _which == WHICH.Unimplemented ? (Capnp.Rpc.Message)_content : null; + get => _which == WHICH.Unimplemented ? (Capnp.Rpc.Message?)_content : null; set { _which = WHICH.Unimplemented; @@ -210,9 +212,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Exception Abort + public Capnp.Rpc.Exception? Abort { - get => _which == WHICH.Abort ? (Capnp.Rpc.Exception)_content : null; + get => _which == WHICH.Abort ? (Capnp.Rpc.Exception?)_content : null; set { _which = WHICH.Abort; @@ -220,9 +222,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Call Call + public Capnp.Rpc.Call? Call { - get => _which == WHICH.Call ? (Capnp.Rpc.Call)_content : null; + get => _which == WHICH.Call ? (Capnp.Rpc.Call?)_content : null; set { _which = WHICH.Call; @@ -230,9 +232,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Return Return + public Capnp.Rpc.Return? Return { - get => _which == WHICH.Return ? (Capnp.Rpc.Return)_content : null; + get => _which == WHICH.Return ? (Capnp.Rpc.Return?)_content : null; set { _which = WHICH.Return; @@ -240,9 +242,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Finish Finish + public Capnp.Rpc.Finish? Finish { - get => _which == WHICH.Finish ? (Capnp.Rpc.Finish)_content : null; + get => _which == WHICH.Finish ? (Capnp.Rpc.Finish?)_content : null; set { _which = WHICH.Finish; @@ -250,9 +252,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Resolve Resolve + public Capnp.Rpc.Resolve? Resolve { - get => _which == WHICH.Resolve ? (Capnp.Rpc.Resolve)_content : null; + get => _which == WHICH.Resolve ? (Capnp.Rpc.Resolve?)_content : null; set { _which = WHICH.Resolve; @@ -260,9 +262,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Release Release + public Capnp.Rpc.Release? Release { - get => _which == WHICH.Release ? (Capnp.Rpc.Release)_content : null; + get => _which == WHICH.Release ? (Capnp.Rpc.Release?)_content : null; set { _which = WHICH.Release; @@ -270,9 +272,9 @@ namespace Capnp.Rpc } } - public AnyPointer ObsoleteSave + public object? ObsoleteSave { - get => _which == WHICH.ObsoleteSave ? (AnyPointer)_content : null; + get => _which == WHICH.ObsoleteSave ? (object?)_content : null; set { _which = WHICH.ObsoleteSave; @@ -280,9 +282,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Bootstrap Bootstrap + public Capnp.Rpc.Bootstrap? Bootstrap { - get => _which == WHICH.Bootstrap ? (Capnp.Rpc.Bootstrap)_content : null; + get => _which == WHICH.Bootstrap ? (Capnp.Rpc.Bootstrap?)_content : null; set { _which = WHICH.Bootstrap; @@ -290,9 +292,9 @@ namespace Capnp.Rpc } } - public AnyPointer ObsoleteDelete + public object? ObsoleteDelete { - get => _which == WHICH.ObsoleteDelete ? (AnyPointer)_content : null; + get => _which == WHICH.ObsoleteDelete ? (object?)_content : null; set { _which = WHICH.ObsoleteDelete; @@ -300,9 +302,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Provide Provide + public Capnp.Rpc.Provide? Provide { - get => _which == WHICH.Provide ? (Capnp.Rpc.Provide)_content : null; + get => _which == WHICH.Provide ? (Capnp.Rpc.Provide?)_content : null; set { _which = WHICH.Provide; @@ -310,9 +312,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Accept Accept + public Capnp.Rpc.Accept? Accept { - get => _which == WHICH.Accept ? (Capnp.Rpc.Accept)_content : null; + get => _which == WHICH.Accept ? (Capnp.Rpc.Accept?)_content : null; set { _which = WHICH.Accept; @@ -320,9 +322,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Join Join + public Capnp.Rpc.Join? Join { - get => _which == WHICH.Join ? (Capnp.Rpc.Join)_content : null; + get => _which == WHICH.Join ? (Capnp.Rpc.Join?)_content : null; set { _which = WHICH.Join; @@ -330,9 +332,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Disembargo Disembargo + public Capnp.Rpc.Disembargo? Disembargo { - get => _which == WHICH.Disembargo ? (Capnp.Rpc.Disembargo)_content : null; + get => _which == WHICH.Disembargo ? (Capnp.Rpc.Disembargo?)_content : null; set { _which = WHICH.Disembargo; @@ -381,99 +383,115 @@ namespace Capnp.Rpc set => this.WriteData(0U, (ushort)value, (ushort)0); } - public Capnp.Rpc.Message.WRITER Unimplemented + [DisallowNull] + public Capnp.Rpc.Message.WRITER? Unimplemented { get => which == WHICH.Unimplemented ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Exception.WRITER Abort + [DisallowNull] + public Capnp.Rpc.Exception.WRITER? Abort { get => which == WHICH.Abort ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Call.WRITER Call + [DisallowNull] + public Capnp.Rpc.Call.WRITER? Call { get => which == WHICH.Call ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Return.WRITER Return + [DisallowNull] + public Capnp.Rpc.Return.WRITER? Return { get => which == WHICH.Return ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Finish.WRITER Finish + [DisallowNull] + public Capnp.Rpc.Finish.WRITER? Finish { get => which == WHICH.Finish ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Resolve.WRITER Resolve + [DisallowNull] + public Capnp.Rpc.Resolve.WRITER? Resolve { get => which == WHICH.Resolve ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Release.WRITER Release + [DisallowNull] + public Capnp.Rpc.Release.WRITER? Release { get => which == WHICH.Release ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public DynamicSerializerState ObsoleteSave + [DisallowNull] + public DynamicSerializerState? ObsoleteSave { get => which == WHICH.ObsoleteSave ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Bootstrap.WRITER Bootstrap + [DisallowNull] + public Capnp.Rpc.Bootstrap.WRITER? Bootstrap { get => which == WHICH.Bootstrap ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public DynamicSerializerState ObsoleteDelete + [DisallowNull] + public DynamicSerializerState? ObsoleteDelete { get => which == WHICH.ObsoleteDelete ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Provide.WRITER Provide + [DisallowNull] + public Capnp.Rpc.Provide.WRITER? Provide { get => which == WHICH.Provide ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Accept.WRITER Accept + [DisallowNull] + public Capnp.Rpc.Accept.WRITER? Accept { get => which == WHICH.Accept ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Join.WRITER Join + [DisallowNull] + public Capnp.Rpc.Join.WRITER? Join { get => which == WHICH.Join ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Disembargo.WRITER Disembargo + [DisallowNull] + public Capnp.Rpc.Disembargo.WRITER? Disembargo { get => which == WHICH.Disembargo ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } } } + [TypeId(0xe94ccf8031176ec4UL)] public class Bootstrap : ICapnpSerializable { + public const UInt64 typeId = 0xe94ccf8031176ec4UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); QuestionId = reader.QuestionId; - DeprecatedObjectId = CapnpSerializable.Create(reader.DeprecatedObjectId); + DeprecatedObjectId = CapnpSerializable.Create(reader.DeprecatedObjectId); applyDefaults(); } @@ -498,7 +516,7 @@ namespace Capnp.Rpc set; } - public AnyPointer DeprecatedObjectId + public object? DeprecatedObjectId { get; set; @@ -540,8 +558,10 @@ namespace Capnp.Rpc } } + [TypeId(0x836a53ce789d4cd4UL)] public class Call : ICapnpSerializable { + public const UInt64 typeId = 0x836a53ce789d4cd4UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); @@ -550,7 +570,7 @@ namespace Capnp.Rpc InterfaceId = reader.InterfaceId; MethodId = reader.MethodId; Params = CapnpSerializable.Create(reader.Params); - SendResultsTo = CapnpSerializable.Create(reader.SendResultsTo); + SendResultsTo = CapnpSerializable.Create(reader.SendResultsTo); AllowThirdPartyTailCall = reader.AllowThirdPartyTailCall; applyDefaults(); } @@ -581,7 +601,7 @@ namespace Capnp.Rpc set; } - public Capnp.Rpc.MessageTarget Target + public Capnp.Rpc.MessageTarget? Target { get; set; @@ -599,13 +619,13 @@ namespace Capnp.Rpc set; } - public Capnp.Rpc.Payload Params + public Capnp.Rpc.Payload? Params { get; set; } - public Capnp.Rpc.Call.@sendResultsTo SendResultsTo + public Capnp.Rpc.Call.sendResultsTo? SendResultsTo { get; set; @@ -634,7 +654,7 @@ namespace Capnp.Rpc public ulong InterfaceId => ctx.ReadDataULong(64UL, 0UL); public ushort MethodId => ctx.ReadDataUShort(32UL, (ushort)0); public Capnp.Rpc.Payload.READER Params => ctx.ReadStruct(1, Capnp.Rpc.Payload.READER.create); - public @sendResultsTo.READER SendResultsTo => new @sendResultsTo.READER(ctx); + public sendResultsTo.READER SendResultsTo => new sendResultsTo.READER(ctx); public bool AllowThirdPartyTailCall => ctx.ReadDataBool(128UL, false); } @@ -675,9 +695,9 @@ namespace Capnp.Rpc set => Link(1, value); } - public @sendResultsTo.WRITER SendResultsTo + public sendResultsTo.WRITER SendResultsTo { - get => Rewrap<@sendResultsTo.WRITER>(); + get => Rewrap(); } public bool AllowThirdPartyTailCall @@ -687,8 +707,10 @@ namespace Capnp.Rpc } } - public class @sendResultsTo : ICapnpSerializable + [TypeId(0xdae8b0f61aab5f99UL)] + public class sendResultsTo : ICapnpSerializable { + public const UInt64 typeId = 0xdae8b0f61aab5f99UL; public enum WHICH : ushort { Caller = 0, @@ -709,7 +731,7 @@ namespace Capnp.Rpc which = reader.which; break; case WHICH.ThirdParty: - ThirdParty = CapnpSerializable.Create(reader.ThirdParty); + ThirdParty = CapnpSerializable.Create(reader.ThirdParty); break; } @@ -717,7 +739,7 @@ namespace Capnp.Rpc } private WHICH _which = WHICH.undefined; - private object _content; + private object? _content; public WHICH which { get => _which; @@ -749,7 +771,7 @@ namespace Capnp.Rpc case WHICH.Yourself: break; case WHICH.ThirdParty: - writer.ThirdParty.SetObject(ThirdParty); + writer.ThirdParty!.SetObject(ThirdParty); break; } } @@ -763,9 +785,9 @@ namespace Capnp.Rpc { } - public AnyPointer ThirdParty + public object? ThirdParty { - get => _which == WHICH.ThirdParty ? (AnyPointer)_content : null; + get => _which == WHICH.ThirdParty ? (object?)_content : null; set { _which = WHICH.ThirdParty; @@ -800,17 +822,20 @@ namespace Capnp.Rpc set => this.WriteData(48U, (ushort)value, (ushort)0); } - public DynamicSerializerState ThirdParty + [DisallowNull] + public DynamicSerializerState? ThirdParty { get => which == WHICH.ThirdParty ? BuildPointer(2) : default; - set => Link(2, value); + set => Link(2, value!); } } } } + [TypeId(0x9e19b28d3db3573aUL)] public class Return : ICapnpSerializable { + public const UInt64 typeId = 0x9e19b28d3db3573aUL; public enum WHICH : ushort { Results = 0, @@ -843,7 +868,7 @@ namespace Capnp.Rpc TakeFromOtherQuestion = reader.TakeFromOtherQuestion; break; case WHICH.AcceptFromThirdParty: - AcceptFromThirdParty = CapnpSerializable.Create(reader.AcceptFromThirdParty); + AcceptFromThirdParty = CapnpSerializable.Create(reader.AcceptFromThirdParty); break; } @@ -853,7 +878,7 @@ namespace Capnp.Rpc } private WHICH _which = WHICH.undefined; - private object _content; + private object? _content; public WHICH which { get => _which; @@ -890,20 +915,20 @@ namespace Capnp.Rpc switch (which) { case WHICH.Results: - Results?.serialize(writer.Results); + Results?.serialize(writer.Results!); break; case WHICH.Exception: - Exception?.serialize(writer.Exception); + Exception?.serialize(writer.Exception!); break; case WHICH.Canceled: break; case WHICH.ResultsSentElsewhere: break; case WHICH.TakeFromOtherQuestion: - writer.TakeFromOtherQuestion = TakeFromOtherQuestion.Value; + writer.TakeFromOtherQuestion = TakeFromOtherQuestion!.Value; break; case WHICH.AcceptFromThirdParty: - writer.AcceptFromThirdParty.SetObject(AcceptFromThirdParty); + writer.AcceptFromThirdParty!.SetObject(AcceptFromThirdParty); break; } @@ -933,9 +958,9 @@ namespace Capnp.Rpc } = true; - public Capnp.Rpc.Payload Results + public Capnp.Rpc.Payload? Results { - get => _which == WHICH.Results ? (Capnp.Rpc.Payload)_content : null; + get => _which == WHICH.Results ? (Capnp.Rpc.Payload?)_content : null; set { _which = WHICH.Results; @@ -943,9 +968,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Exception Exception + public Capnp.Rpc.Exception? Exception { - get => _which == WHICH.Exception ? (Capnp.Rpc.Exception)_content : null; + get => _which == WHICH.Exception ? (Capnp.Rpc.Exception?)_content : null; set { _which = WHICH.Exception; @@ -955,7 +980,7 @@ namespace Capnp.Rpc public uint? TakeFromOtherQuestion { - get => _which == WHICH.TakeFromOtherQuestion ? (uint? )_content : null; + get => _which == WHICH.TakeFromOtherQuestion ? (uint?)_content : null; set { _which = WHICH.TakeFromOtherQuestion; @@ -963,9 +988,9 @@ namespace Capnp.Rpc } } - public AnyPointer AcceptFromThirdParty + public object? AcceptFromThirdParty { - get => _which == WHICH.AcceptFromThirdParty ? (AnyPointer)_content : null; + get => _which == WHICH.AcceptFromThirdParty ? (object?)_content : null; set { _which = WHICH.AcceptFromThirdParty; @@ -1018,16 +1043,18 @@ namespace Capnp.Rpc set => this.WriteData(32UL, value, true); } - public Capnp.Rpc.Payload.WRITER Results + [DisallowNull] + public Capnp.Rpc.Payload.WRITER? Results { get => which == WHICH.Results ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Exception.WRITER Exception + [DisallowNull] + public Capnp.Rpc.Exception.WRITER? Exception { get => which == WHICH.Exception ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } public uint TakeFromOtherQuestion @@ -1036,16 +1063,19 @@ namespace Capnp.Rpc set => this.WriteData(64UL, value, 0U); } - public DynamicSerializerState AcceptFromThirdParty + [DisallowNull] + public DynamicSerializerState? AcceptFromThirdParty { get => which == WHICH.AcceptFromThirdParty ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } } } + [TypeId(0xd37d2eb2c2f80e63UL)] public class Finish : ICapnpSerializable { + public const UInt64 typeId = 0xd37d2eb2c2f80e63UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); @@ -1118,8 +1148,10 @@ namespace Capnp.Rpc } } + [TypeId(0xbbc29655fa89086eUL)] public class Resolve : ICapnpSerializable { + public const UInt64 typeId = 0xbbc29655fa89086eUL; public enum WHICH : ushort { Cap = 0, @@ -1145,7 +1177,7 @@ namespace Capnp.Rpc } private WHICH _which = WHICH.undefined; - private object _content; + private object? _content; public WHICH which { get => _which; @@ -1172,10 +1204,10 @@ namespace Capnp.Rpc switch (which) { case WHICH.Cap: - Cap?.serialize(writer.Cap); + Cap?.serialize(writer.Cap!); break; case WHICH.Exception: - Exception?.serialize(writer.Exception); + Exception?.serialize(writer.Exception!); break; } @@ -1197,9 +1229,9 @@ namespace Capnp.Rpc set; } - public Capnp.Rpc.CapDescriptor Cap + public Capnp.Rpc.CapDescriptor? Cap { - get => _which == WHICH.Cap ? (Capnp.Rpc.CapDescriptor)_content : null; + get => _which == WHICH.Cap ? (Capnp.Rpc.CapDescriptor?)_content : null; set { _which = WHICH.Cap; @@ -1207,9 +1239,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.Exception Exception + public Capnp.Rpc.Exception? Exception { - get => _which == WHICH.Exception ? (Capnp.Rpc.Exception)_content : null; + get => _which == WHICH.Exception ? (Capnp.Rpc.Exception?)_content : null; set { _which = WHICH.Exception; @@ -1253,22 +1285,26 @@ namespace Capnp.Rpc set => this.WriteData(0UL, value, 0U); } - public Capnp.Rpc.CapDescriptor.WRITER Cap + [DisallowNull] + public Capnp.Rpc.CapDescriptor.WRITER? Cap { get => which == WHICH.Cap ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.Exception.WRITER Exception + [DisallowNull] + public Capnp.Rpc.Exception.WRITER? Exception { get => which == WHICH.Exception ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } } } + [TypeId(0xad1a6c0d7dd07497UL)] public class Release : ICapnpSerializable { + public const UInt64 typeId = 0xad1a6c0d7dd07497UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); @@ -1340,13 +1376,15 @@ namespace Capnp.Rpc } } + [TypeId(0xf964368b0fbd3711UL)] public class Disembargo : ICapnpSerializable { + public const UInt64 typeId = 0xf964368b0fbd3711UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); Target = CapnpSerializable.Create(reader.Target); - Context = CapnpSerializable.Create(reader.Context); + Context = CapnpSerializable.Create(reader.Context); applyDefaults(); } @@ -1365,13 +1403,13 @@ namespace Capnp.Rpc { } - public Capnp.Rpc.MessageTarget Target + public Capnp.Rpc.MessageTarget? Target { get; set; } - public Capnp.Rpc.Disembargo.@context Context + public Capnp.Rpc.Disembargo.context? Context { get; set; @@ -1389,7 +1427,7 @@ namespace Capnp.Rpc public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); public Capnp.Rpc.MessageTarget.READER Target => ctx.ReadStruct(0, Capnp.Rpc.MessageTarget.READER.create); - public @context.READER Context => new @context.READER(ctx); + public context.READER Context => new context.READER(ctx); } public class WRITER : SerializerState @@ -1405,14 +1443,16 @@ namespace Capnp.Rpc set => Link(0, value); } - public @context.WRITER Context + public context.WRITER Context { - get => Rewrap<@context.WRITER>(); + get => Rewrap(); } } - public class @context : ICapnpSerializable + [TypeId(0xd562b4df655bdd4dUL)] + public class context : ICapnpSerializable { + public const UInt64 typeId = 0xd562b4df655bdd4dUL; public enum WHICH : ushort { SenderLoopback = 0, @@ -1445,7 +1485,7 @@ namespace Capnp.Rpc } private WHICH _which = WHICH.undefined; - private object _content; + private object? _content; public WHICH which { get => _which; @@ -1477,15 +1517,15 @@ namespace Capnp.Rpc switch (which) { case WHICH.SenderLoopback: - writer.SenderLoopback = SenderLoopback.Value; + writer.SenderLoopback = SenderLoopback!.Value; break; case WHICH.ReceiverLoopback: - writer.ReceiverLoopback = ReceiverLoopback.Value; + writer.ReceiverLoopback = ReceiverLoopback!.Value; break; case WHICH.Accept: break; case WHICH.Provide: - writer.Provide = Provide.Value; + writer.Provide = Provide!.Value; break; } } @@ -1501,7 +1541,7 @@ namespace Capnp.Rpc public uint? SenderLoopback { - get => _which == WHICH.SenderLoopback ? (uint? )_content : null; + get => _which == WHICH.SenderLoopback ? (uint?)_content : null; set { _which = WHICH.SenderLoopback; @@ -1511,7 +1551,7 @@ namespace Capnp.Rpc public uint? ReceiverLoopback { - get => _which == WHICH.ReceiverLoopback ? (uint? )_content : null; + get => _which == WHICH.ReceiverLoopback ? (uint?)_content : null; set { _which = WHICH.ReceiverLoopback; @@ -1521,7 +1561,7 @@ namespace Capnp.Rpc public uint? Provide { - get => _which == WHICH.Provide ? (uint? )_content : null; + get => _which == WHICH.Provide ? (uint?)_content : null; set { _which = WHICH.Provide; @@ -1579,14 +1619,16 @@ namespace Capnp.Rpc } } + [TypeId(0x9c6a046bfbc1ac5aUL)] public class Provide : ICapnpSerializable { + public const UInt64 typeId = 0x9c6a046bfbc1ac5aUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); QuestionId = reader.QuestionId; Target = CapnpSerializable.Create(reader.Target); - Recipient = CapnpSerializable.Create(reader.Recipient); + Recipient = CapnpSerializable.Create(reader.Recipient); applyDefaults(); } @@ -1612,13 +1654,13 @@ namespace Capnp.Rpc set; } - public Capnp.Rpc.MessageTarget Target + public Capnp.Rpc.MessageTarget? Target { get; set; } - public AnyPointer Recipient + public object? Recipient { get; set; @@ -1667,13 +1709,15 @@ namespace Capnp.Rpc } } + [TypeId(0xd4c9b56290554016UL)] public class Accept : ICapnpSerializable { + public const UInt64 typeId = 0xd4c9b56290554016UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); QuestionId = reader.QuestionId; - Provision = CapnpSerializable.Create(reader.Provision); + Provision = CapnpSerializable.Create(reader.Provision); Embargo = reader.Embargo; applyDefaults(); } @@ -1700,7 +1744,7 @@ namespace Capnp.Rpc set; } - public AnyPointer Provision + public object? Provision { get; set; @@ -1755,14 +1799,16 @@ namespace Capnp.Rpc } } + [TypeId(0xfbe1980490e001afUL)] public class Join : ICapnpSerializable { + public const UInt64 typeId = 0xfbe1980490e001afUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); QuestionId = reader.QuestionId; Target = CapnpSerializable.Create(reader.Target); - KeyPart = CapnpSerializable.Create(reader.KeyPart); + KeyPart = CapnpSerializable.Create(reader.KeyPart); applyDefaults(); } @@ -1788,13 +1834,13 @@ namespace Capnp.Rpc set; } - public Capnp.Rpc.MessageTarget Target + public Capnp.Rpc.MessageTarget? Target { get; set; } - public AnyPointer KeyPart + public object? KeyPart { get; set; @@ -1843,8 +1889,10 @@ namespace Capnp.Rpc } } + [TypeId(0x95bc14545813fbc1UL)] public class MessageTarget : ICapnpSerializable { + public const UInt64 typeId = 0x95bc14545813fbc1UL; public enum WHICH : ushort { ImportedCap = 0, @@ -1869,7 +1917,7 @@ namespace Capnp.Rpc } private WHICH _which = WHICH.undefined; - private object _content; + private object? _content; public WHICH which { get => _which; @@ -1896,10 +1944,10 @@ namespace Capnp.Rpc switch (which) { case WHICH.ImportedCap: - writer.ImportedCap = ImportedCap.Value; + writer.ImportedCap = ImportedCap!.Value; break; case WHICH.PromisedAnswer: - PromisedAnswer?.serialize(writer.PromisedAnswer); + PromisedAnswer?.serialize(writer.PromisedAnswer!); break; } } @@ -1915,7 +1963,7 @@ namespace Capnp.Rpc public uint? ImportedCap { - get => _which == WHICH.ImportedCap ? (uint? )_content : null; + get => _which == WHICH.ImportedCap ? (uint?)_content : null; set { _which = WHICH.ImportedCap; @@ -1923,9 +1971,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.PromisedAnswer PromisedAnswer + public Capnp.Rpc.PromisedAnswer? PromisedAnswer { - get => _which == WHICH.PromisedAnswer ? (Capnp.Rpc.PromisedAnswer)_content : null; + get => _which == WHICH.PromisedAnswer ? (Capnp.Rpc.PromisedAnswer?)_content : null; set { _which = WHICH.PromisedAnswer; @@ -1968,21 +2016,24 @@ namespace Capnp.Rpc set => this.WriteData(0UL, value, 0U); } - public Capnp.Rpc.PromisedAnswer.WRITER PromisedAnswer + [DisallowNull] + public Capnp.Rpc.PromisedAnswer.WRITER? PromisedAnswer { get => which == WHICH.PromisedAnswer ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } } } + [TypeId(0x9a0e61223d96743bUL)] public class Payload : ICapnpSerializable { + public const UInt64 typeId = 0x9a0e61223d96743bUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); - Content = CapnpSerializable.Create(reader.Content); - CapTable = reader.CapTable.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + Content = CapnpSerializable.Create(reader.Content); + CapTable = reader.CapTable?.ToReadOnlyList(_ => CapnpSerializable.Create(_)!); applyDefaults(); } @@ -2001,13 +2052,13 @@ namespace Capnp.Rpc { } - public AnyPointer Content + public object? Content { get; set; } - public IReadOnlyList CapTable + public IReadOnlyList? CapTable { get; set; @@ -2049,8 +2100,10 @@ namespace Capnp.Rpc } } + [TypeId(0x8523ddc40b86b8b0UL)] public class CapDescriptor : ICapnpSerializable { + public const UInt64 typeId = 0x8523ddc40b86b8b0UL; public enum WHICH : ushort { None = 0, @@ -2091,7 +2144,7 @@ namespace Capnp.Rpc } private WHICH _which = WHICH.undefined; - private object _content; + private object? _content; public WHICH which { get => _which; @@ -2131,19 +2184,19 @@ namespace Capnp.Rpc case WHICH.None: break; case WHICH.SenderHosted: - writer.SenderHosted = SenderHosted.Value; + writer.SenderHosted = SenderHosted!.Value; break; case WHICH.SenderPromise: - writer.SenderPromise = SenderPromise.Value; + writer.SenderPromise = SenderPromise!.Value; break; case WHICH.ReceiverHosted: - writer.ReceiverHosted = ReceiverHosted.Value; + writer.ReceiverHosted = ReceiverHosted!.Value; break; case WHICH.ReceiverAnswer: - ReceiverAnswer?.serialize(writer.ReceiverAnswer); + ReceiverAnswer?.serialize(writer.ReceiverAnswer!); break; case WHICH.ThirdPartyHosted: - ThirdPartyHosted?.serialize(writer.ThirdPartyHosted); + ThirdPartyHosted?.serialize(writer.ThirdPartyHosted!); break; } } @@ -2159,7 +2212,7 @@ namespace Capnp.Rpc public uint? SenderHosted { - get => _which == WHICH.SenderHosted ? (uint? )_content : null; + get => _which == WHICH.SenderHosted ? (uint?)_content : null; set { _which = WHICH.SenderHosted; @@ -2169,7 +2222,7 @@ namespace Capnp.Rpc public uint? SenderPromise { - get => _which == WHICH.SenderPromise ? (uint? )_content : null; + get => _which == WHICH.SenderPromise ? (uint?)_content : null; set { _which = WHICH.SenderPromise; @@ -2179,7 +2232,7 @@ namespace Capnp.Rpc public uint? ReceiverHosted { - get => _which == WHICH.ReceiverHosted ? (uint? )_content : null; + get => _which == WHICH.ReceiverHosted ? (uint?)_content : null; set { _which = WHICH.ReceiverHosted; @@ -2187,9 +2240,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.PromisedAnswer ReceiverAnswer + public Capnp.Rpc.PromisedAnswer? ReceiverAnswer { - get => _which == WHICH.ReceiverAnswer ? (Capnp.Rpc.PromisedAnswer)_content : null; + get => _which == WHICH.ReceiverAnswer ? (Capnp.Rpc.PromisedAnswer?)_content : null; set { _which = WHICH.ReceiverAnswer; @@ -2197,9 +2250,9 @@ namespace Capnp.Rpc } } - public Capnp.Rpc.ThirdPartyCapDescriptor ThirdPartyHosted + public Capnp.Rpc.ThirdPartyCapDescriptor? ThirdPartyHosted { - get => _which == WHICH.ThirdPartyHosted ? (Capnp.Rpc.ThirdPartyCapDescriptor)_content : null; + get => _which == WHICH.ThirdPartyHosted ? (Capnp.Rpc.ThirdPartyCapDescriptor?)_content : null; set { _which = WHICH.ThirdPartyHosted; @@ -2257,27 +2310,31 @@ namespace Capnp.Rpc set => this.WriteData(32UL, value, 0U); } - public Capnp.Rpc.PromisedAnswer.WRITER ReceiverAnswer + [DisallowNull] + public Capnp.Rpc.PromisedAnswer.WRITER? ReceiverAnswer { get => which == WHICH.ReceiverAnswer ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } - public Capnp.Rpc.ThirdPartyCapDescriptor.WRITER ThirdPartyHosted + [DisallowNull] + public Capnp.Rpc.ThirdPartyCapDescriptor.WRITER? ThirdPartyHosted { get => which == WHICH.ThirdPartyHosted ? BuildPointer(0) : default; - set => Link(0, value); + set => Link(0, value!); } } } + [TypeId(0xd800b1d6cd6f1ca0UL)] public class PromisedAnswer : ICapnpSerializable { + public const UInt64 typeId = 0xd800b1d6cd6f1ca0UL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); QuestionId = reader.QuestionId; - Transform = reader.Transform.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + Transform = reader.Transform?.ToReadOnlyList(_ => CapnpSerializable.Create(_)!); applyDefaults(); } @@ -2302,7 +2359,7 @@ namespace Capnp.Rpc set; } - public IReadOnlyList Transform + public IReadOnlyList? Transform { get; set; @@ -2343,8 +2400,10 @@ namespace Capnp.Rpc } } + [TypeId(0xf316944415569081UL)] public class Op : ICapnpSerializable { + public const UInt64 typeId = 0xf316944415569081UL; public enum WHICH : ushort { Noop = 0, @@ -2369,7 +2428,7 @@ namespace Capnp.Rpc } private WHICH _which = WHICH.undefined; - private object _content; + private object? _content; public WHICH which { get => _which; @@ -2397,7 +2456,7 @@ namespace Capnp.Rpc case WHICH.Noop: break; case WHICH.GetPointerField: - writer.GetPointerField = GetPointerField.Value; + writer.GetPointerField = GetPointerField!.Value; break; } } @@ -2413,7 +2472,7 @@ namespace Capnp.Rpc public ushort? GetPointerField { - get => _which == WHICH.GetPointerField ? (ushort? )_content : null; + get => _which == WHICH.GetPointerField ? (ushort?)_content : null; set { _which = WHICH.GetPointerField; @@ -2458,12 +2517,14 @@ namespace Capnp.Rpc } } + [TypeId(0xd37007fde1f0027dUL)] public class ThirdPartyCapDescriptor : ICapnpSerializable { + public const UInt64 typeId = 0xd37007fde1f0027dUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); - Id = CapnpSerializable.Create(reader.Id); + Id = CapnpSerializable.Create(reader.Id); VineId = reader.VineId; applyDefaults(); } @@ -2483,7 +2544,7 @@ namespace Capnp.Rpc { } - public AnyPointer Id + public object? Id { get; set; @@ -2531,8 +2592,10 @@ namespace Capnp.Rpc } } + [TypeId(0xd625b7063acf691aUL)] public class Exception : ICapnpSerializable { + public const UInt64 typeId = 0xd625b7063acf691aUL; void ICapnpSerializable.Deserialize(DeserializerState arg_) { var reader = READER.create(arg_); @@ -2560,7 +2623,7 @@ namespace Capnp.Rpc { } - public string Reason + public string? Reason { get; set; @@ -2595,7 +2658,7 @@ namespace Capnp.Rpc public static READER create(DeserializerState ctx) => new READER(ctx); public static implicit operator DeserializerState(READER reader) => reader.ctx; public static implicit operator READER(DeserializerState ctx) => new READER(ctx); - public string Reason => ctx.ReadText(0, ""); + public string? Reason => ctx.ReadText(0, null); public bool ObsoleteIsCallersFault => ctx.ReadDataBool(0UL, false); public ushort ObsoleteDurability => ctx.ReadDataUShort(16UL, (ushort)0); public Capnp.Rpc.Exception.Type TheType => (Capnp.Rpc.Exception.Type)ctx.ReadDataUShort(32UL, (ushort)0); @@ -2608,10 +2671,10 @@ namespace Capnp.Rpc this.SetStruct(1, 1); } - public string Reason + public string? Reason { - get => this.ReadText(0, ""); - set => this.WriteText(0, value, ""); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } public bool ObsoleteIsCallersFault @@ -2633,6 +2696,7 @@ namespace Capnp.Rpc } } + [TypeId(0xb28c96e23f4cbd58UL)] public enum Type : ushort { failed, @@ -2641,6 +2705,4 @@ namespace Capnp.Rpc unimplemented } } -} - -#nullable restore \ No newline at end of file +} \ No newline at end of file diff --git a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature index 6d8d53f..7baa276 100644 --- a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature +++ b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature @@ -70,4 +70,5 @@ Examples: | NullableDisable2.capnp.bin | false | false | errors | | NullableDisable2.capnp.bin | false | true | success | | NullableEnable2.capnp.bin | false | false | errors | - | NullableEnable2.capnp.bin | false | true | success | \ No newline at end of file + | NullableEnable2.capnp.bin | false | true | success | + | rpc-csharp.capnp.bin | true | true | warnings | \ No newline at end of file diff --git a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs index 3fa5c2c..10e1f06 100644 --- a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs +++ b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs @@ -647,6 +647,21 @@ this.ValidGeneratorOutput("NullableEnable2.capnp.bin", "false", "false", "errors { #line 50 this.ValidGeneratorOutput("NullableEnable2.capnp.bin", "false", "true", "success", ((string[])(null))); +#line hidden + } + + [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()] + [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Valid generator output: Variant 15")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "CodeGenerator")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("VariantName", "Variant 15")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:bin", "rpc-csharp.capnp.bin")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:nullablegen", "true")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:nullablesupp", "true")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:outcome", "warnings")] + public virtual void ValidGeneratorOutput_Variant15() + { +#line 50 +this.ValidGeneratorOutput("rpc-csharp.capnp.bin", "true", "true", "warnings", ((string[])(null))); #line hidden } } diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/rpc-csharp.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/rpc-csharp.capnp.bin new file mode 100644 index 0000000000000000000000000000000000000000..720907783602a0916c0a7c1ade509a2b8890a602 GIT binary patch literal 66744 zcmeIbe~{$qUEkNYryr<6!a5rX4k%hfR5!ccnbVyF*sI7e`{TGh-`%ceM-sXub<;D` zv)i{b-9vZJ&drro5yB*qVpTwe30&a>E0A&oF3Sg$L9r@ug&nxUF(}}&RdK~u6=hov zRVg`f%n?jp@6V6t`}B8u?oKDg`6s>G^X>1C=hx@?{Qi8N=lhxtpV#?vr&(CxFB|pDM zn;+we-{<&ND*Q*U?R5U*mniX5zyEh{z2yhr_%GkcGq0rwKO5)mB9FbU)A*H?Oc>_3vKb`uAG({`x8P{`4!X_m?TZ^<~uiGgZB37-zz}4La2;I0zm!9DbGa z?`l8H`F~s0`%?Ju8&U7?w(9*Y&KJS=!B2nu!{7E_|E(Vp-rvQ)#OJ%LS8pmkQNLc` ztPNka_tv}1W97%a!@qywb${#a|6p;w<+08ix}DDFIsFEXZ*4AjzLoQTR-Nb1-+A<} zJpDi2c?_{^vFv=1X@vFH%;;?*(b;ux1Z&$Q0-`hPk5tq;9%@7}-OuD9La zGw?6fdoGSy{zB_Kum9TUtq*+o??3u4+Vy&W^C|c)_+L=Uvo|&7SPUjO$mg@aX9JBljt@FJ8mhXAr4{!bAZ~RWX-gbZ2krk?U62~n6k=A)$ z{~LGxlOKM~kN?v@Y}ecFZx=i@_{K5IUud1@^*4XlXTSbG|IVF1XxH2B?`ObM)%%4w zX8A9*&hz^BefH7s{=$#_rRTnx3&N?S>%5=G&mgF*-ZRZNt?;rfl&Oh{e+x$15f>vLJga7pxwtn|pxF9$rov7Zs(DxD&>-T!SSuT$sIpzA~V0&eIdaFME=J;_k?fayUtZU=lz3mKk-TD&+yIp)A{p!lTWC; z#{1Y{I_=*abS{p^v*~QoPk>$O@9lBBvp$#|PDY*1L&MQXSp>C(;yPY$@;x!ynC8~1lQm-+{n2h;7z z@L)F9_$a?ml{;&r>Cu1-8@Gm&o$LL{?0EjkD^IKb;n*st9Ap9Boav-~{w~hXa7FX3 zJE;eM4`;gmur6~(}FY>U(-l*EixiY(RmL`oZ?x zUA3$yPXE00-Ip(q`Sg;Xnno^+`ul_FL4R9F$VYu^kH_ycf9vwPnsl6c_5)lK{^fk= zT=2+w$omO@oj=Dn;r<=`evxm&`#t5LBd z_WE0UgDWHb?Q{nF!`b6;?ecIk*q#l+X1{)Uyx$*=F75TF)4_CYv~zVd8%%Zq%M`nE zK|2&PleNY>%t*tFZ`92NaMZkhg0JJn+GsSM^@YYXG54wAd!apucvAE9a(FUV&uN4I zO6q$lpuO69+ml+=^ELbyyz}#Beq6{CjtLLcyv`%l^@GE$y&*(6)SQm`dwFXPKJ7`4 zhXm!Mr^N3ppU1Y`xsZ%CAK<8Z{tU;v4Qu}RkNsBm*w2nRo%m1t`!wgW5C0-Z@teCk z|F)E?Oa1^S4_4*=LX`W@qTJn`KPu%K=yf_j#C_3Gem)%K{!)~CP3QkE%3UXy*3MR{1NU;-sMOAQ@J0Ha|>Fj30q7r9^0->0M8-;Q!`?EI@zu9gMA%>5c))IYWND^c!iI$tW~Ffq#Kv)q58 zoOL>CN9BG!${mh|`v-f2{Q>m3!*i(n_DOv$PRk+hmkaTuzcrpnzsUQk@3f!G`|a!7 zq4(td)Cb$o<^A^cN$5*?KlR74Ebpg&+I}wYx35n^ zugm+X&$ge-`|a!FE%d{|Y;dD*VzqNm`+?T^Y4^8U`e?S7`g*IHGT-g%*`LddYlfgd zt-UOF+WmvjYqKAz$7i`b=KVa+V?Xrayq|i1-p^y+&+|M!6?$~uPdg#+=P~c+c^-FK zdU`&W_DMdM$Go5Cc|0NKT8g-My`)t7Cm`>lr>PFr>+(-$`sj(~)8}W+m;OV}#V2lY zl>BRCms)8)(&0YSoZ9m$Ctjd(l3o6MT}P+${ak;xDyQdF?!z2i-s-52*I_^T^C7-9 zAAFi~mHUevRc?ZHB;%y!o!mO{IqiPp?bWF)vB6~eQ2%g`&edZ+Q5hFbyPx%4KAiMZ zS62C2<}Ir4wEI$(^nB_?Ip6I%@_zgJ2|P-JlLs}kvL{{&Pkxd6wLJL+dmcH&G3Sk+ zeCF}wvs|h1>z6p!y!{$SmD5}=!joU+`WD~({0cu*?l(EAobYQAp8N*aAK{yyU+0I) z{SHT!la7<^iFWey+x)2esdiNEA97T=)NyjY({J~?+@J70?V~n6Y&Y-fxGwEaYJAW8 zPx~u)sJ-9fsP?}9a4?mfa&^Zas&yW}GXM9q`?GKWB!5Z&#(e2Uez&ii{w|v=I#TOU z?Pqm<+Wq~(?ACZENAv3G;GjS0?_<2>c+x-9?n~ZpU!M*}JNQ(f?distn-Kf>sBwC1 z^oM&!89C4G@_ByR{S$PS4jl@LGI|_eiq3?GHU0`8gctt{N8yFq?eR@I%YOVLu6)d{ z`yV~8a{rv8%AM&n_K(wzKlghaF8WXV`%n0*a{n7gmAkvLe`FP8+U(X3|@;RN?AJs4X-tLdKQ4xc?`4g)Dm3&nHX&>GB z6yJcu4eXmMd(*+ut--|Pr^qP`_V_pPl9Y6MXZt z%n$YVT^!XP)zjlED%Nj(^?88rC+wI1(eo3NDJo3k0PqS4bQ*9HR-1>1 z-sV^N+-ZC&@3-p_%wFKTVE#M+69pE{-z%jD$;$lvd;AbQ-@(!6FKJ*N!&bO2S(%^n z{7^ahH&t#Job=Vge=^vGL&B3UjSok&)8{GMKdl|X<@0<`z^@hX`byyUa{R>mI1fMZ zlV|;g{r!K7pX>|{2y*mss$JW9ifBg?#%X*vyL8(9Q}Hnae^J3Ac)n78Qp58kKgk}> z!&Cg^Lf+zdlAknq{N?bIuNGhbO6?vdadge6{Ay{C?9W&U_kNvn!|F&mg(r z`%<6N?(6zv7zK!H|4S%~?{rO7awml|*^YqNxJwxLs@U{4hR~6;8 z=h}FClm18_swrN2dp+J9*W0*WH_4!u5PuVa3lfHs);&f77-^IZqt8aW~Fi}EE zT7dY=8OjKW=~vqEDYd_}XngY4thT*6J`eNquhENZzk>AXdYs?Gx%iss#PzWz{+m8P zZgsBml^vU(lk)G6ia#RZt!JfA*YIoe(QWfSXRTlU@pybVnGW`Lzx!e4Z|w`Qujk2v4`lS*NqiZ_S_dyY~F4&iqIp zd?rsgO8-{5f1ji2)B6VmHU~SHg!a^F`mWvN&uRC=J}UWDqBDImZ_Lk{zj?p8;=k1Q zg?33Mc13}ghhx@UL!;9X9BV$ch`)J>c|B14t)_#tOGFQXqwy!SsMGKxdvn@-?7|Jt zB=RTUlm!+XHGc`e)9lC7%4=*3`6qgIogk;@-pcnid$^Up3dFzWIx(E4Su>^!$08?#meEd@&-Tt zoZu7l@L#Rr`)c{cxzd|X=Omv0+duXhnuoXW{3BJl#PhVjN8@qKeD%x7(1 zmU?J7*xM<*@U$v&?CtyN`$B#TBdZfX^<37Wk?Q;d{P{+X?tfa$Z-0XOHT-_mo+q!G zWAaB-9#2C*I!)eW-KX96dV;8U__XIa-CI9Iv9 zz%ls{KlzBaG#^r==k%%>=PLJMjw$|Yz*Dq3u z?q^=tgD7G;zwn?RGY{{@@AUI$zsrxA_wfXRU(bIcj+wXk2m_WJdNz*j{N?pG`u)sj zo5cA&U+>p5KjTXffag-sd4yU4IZ}p=0J7K8u2)^G~7}>X>nliy*DezwjPE z=K6qpzT3~aWuIIJaItm$v~|0gXZfjk{+{pg`f~linTO}=Z|5tWi~E^x`oy|F|H(M! z`rC5^n$-XN?4%ZQR_x^1WovOUeXusxBvOTt^TYxoc3np z-qxVkWD^c{R%s#g-0tdp>KnZt=^`Hk*C*fP=T~>|T@QDM1FE<+=mk0M^u`vIh-wdp z+qVZhy~6{qQ}t3sM{D3VDCE3Jy_gK#o*3Qi^{dYG#v{(DTNV=Sc$aUF#z!NyKnz|X z&z?A&&ih@gxyXj=-7;0Cw{>j&^QKmNy|rm?I##vb?^H8-x41CazBQ)1Rvm7V-ofx- zu!nrw>B(y{?NSUiV458|-y6<)M?)Um;W2a-YpIbtrC$P2jP+(WP_>hDd*J>=l@ za9<-7FtbnRtKSTC)H?*$N5FcZA!!ZSY;g0~#@Zjv3}g05O6W}wCxfo4@xIc?A&Ygk zhBpt#htt(=cY|9w(BA&xbk?K3;jZR`c~n97P10tWwEp(&5KtfI)J_+`@V;sHPJad* zEG6Oy%$OU2CUSec&$1viS;wB)cze9p8%!qSi38@=_;AmlPX`hXc`jZ`Co`@2o8G_xjF(A{dl`;EV8BD4=cmynGqEx8D%R)%% zr+EFjbIW^7)L!qMXV0B;pa-f^#aBjFqA2Ex^?EC0#m$au>MC>CG`4*>A;3EWMnlnw z@dTDyO?%_ro=ba;W%&@ayxH6I@YLqn)pAu!M%+1@yulq{otr=*q0l6be3}VNap-)}crp`gqs|N(| zY6gB{Tp;f}($8_y1&Az)967}w%$y|46f6rLs*Z~}pY5@%7v>omGKMk%J?FFqsGGfj zwM~IIk%&Ah-|6ilAFQB2)Va6+=U~7E?2xL3}P}6v$g3Oj6j&}LGQ}Sc!D9`(9i&! z*ndFLjWfU+Av*O-S+%mrCos;VKw9BHStHTHkDvX~ytNlWhIu znE_qop#=h^+nZ-slHNRfYcf8(dCSUQ3?keH+gj5o^l7P`NvA;yRDTOhW?q<_LVc?z z$0S8Mab3N>#8^I{85OD|T?H{sK}&UUFmO>%6QiB+?rv|qjf|Pn=JHfR?s`gH>6a

Hb*Y!L;p`AD87hfOO>50`u(Kz?c{HHzgW=7a$EI~BOJWUm;I%k?e~;BSJI6j` z$>+lZ!A*VKGhEK@Ug+82vSZauESr$<$)l*j!?;FGn2xXWQxK$y)gYRr=n&b)c=y!t zQ^*)(v8U@c=cYe<060#SQq*2)58cPd36bElLgyei!*q14Ac8rpzSvt9RvTM%R(}Uv zDC%1xRf5_?@KRP86Oz* zh1c1;>&Bdp`e<3|6bEi%P@%-mB){JWBSyrD@tUy9ThsGhQI6{e6wx$ST7@JA>gOT2 zwKvv78pVeAYOydSeqlsgQV=k*QLl&03G(GaHzvB~P?`uEnT#9|3E~~~)_N;{u6I#? zE|p(vJvgs0iakj{UIwL(NgRPbq!uwJnzLeH@|3iRes5nx7(6XakLfw;A9tB| zOe{?jo4S~s1o}pGh%WF@OthNs1oG%Usv8~mcKd{VCaY(=-E$ih+?Wiv*j%Ict`+L; zt+O~wf_rBul@l9tjS>Y#UDaHOcZNts6-eEtk8y13tXvF`r_F`1rMooW?nLb(Q@q_J zB$R0~mj}#RJSk2Lj{*|x^C3N&&V$GFeP6txZvuYrxcks#*x!ft2ht(h8u-p&I=pG6 z$33B7a+Qj~A{&p!E4QE))54euM;O##ayX(a0XS3_TwT&|r(+hR4VgOiiScU8Hf=mH zUF}`n@86`y+yn-uXu#MsM@9J-=IL}_e814<1L%X4I7Q=mvJWGmxhGGQdk`rgc({dx z1c19c1ALO|1U4Z{S3Q2RuvmJK?2(@r$6Ha!E-64TU)91$gw6oOk@skD9|H}r2=R<~ z`n`7wc$lITTQ+-Jb-4C8n4a~qKF|Po*+C*&9&h0y=w5jmFq`48z6MU+zf;yg3qtPY zp{KA@Wpt=k@5v5o_}**?2h#)rW-J=nRH!uj)2_56>9FXhS5aWlG=PoF6?|OGz@e!a z6p=lQ4xky0@%rc>JB{@4;6k^1jX5o5Oz*l)swrv#NHg`yw1%&=ne%lM(~>NEyyC~G*HpwPJ9E40|qOxO(Vj3G7E>$*uF=jY84?rB&&Gsmt!s0dmS zhI9c$vTFQ6!vmkEdWz`eaMq=Ac#EYB(!Nk&FcuO?ifYR1{^Xd&5g3(;mGU4HiHCx* z!&?l)#2ULh6Bx?%RnUZnsGV9@#=9%{2|%LJF}(LYd_>cx(TP{@_i<_>lWi^;AaVf8 zLl4H!ruqYCx?^_I+8;iH)e5?b>Wcfx{O?~NDA4j7KIYD>o|b`^d6fHJx^^F^rgN?3 zS9d3jfB`!&h7TpmF^7Bgn1aS|=6q0g#Yq3yNGklQ&V^A6or_luhQsiBm>xOp0epj< zoZIP0X*!M2H3gF@eHV}3$_iscZo4wL>R!o*Q2jup*p+NEKqbG>iv&H^(0h*-InItX zXa>X7*;WvV4arz7FfhlcEujIJc9D{K6izDQv8>bLvxikU3Lc?ykj82B zRz+RF^B!i9KK+0=GaG;&?~~h&!F-=xBRb7I{~~d@ufc z>xmeOxVC#N>1?5eZ-5;51|Up8Btmk?Twqn7D($h*dTQRO%2JpeNwCOpr5J{QII z2pt^=&xqz38HDquIEF5%`1_gCi>lR}Lno$F{7;WuqLjO~jY4&4P5Q532eFXLGJcZmq}g%gEMpWTWC&NsdxR zrXR`P)Q5&cFbOvl?F$=H5mJqqctub0!*t8}0E)2^>Z`^gnMW@W8JmHC=4IRz-(U!C zx198?BrMAa=KYY#<^r4-<<3gr;o0-(OVX3GQX?l->lo*LYzZN$6Xxy}AQF?3;ev7s z@ho%|UJ{+j*O;OdxClt%S@3Xp8~aS56$u*qIPChP;kE^?vK2$l+5@37Sd~a)mAN$@ z%QGUyA48@WYJ*QfblLb7{Ibw$*fUN^sgD@XVkD}x^yd(?=43Yxkf(3zkJiraMLx?(1C=f;tK1W0~%`hCn5TOJ| zd~zw=;4L+ae-)AA{?$u1ORgqXk#!pl4I5^-iRH8Hr7p@}A&%wHbGTX=GeQh11K6-h zT4T(>IXI<(A&vXOYv$^klM9tkKrYL%X+J`;t4TqL(IAk=DIF9HxDLXFd^pL>jA+s1 z<#cQUaXHhM#L1K%nL(X!Yt(&|Bq4~wG>nggtkg&sw#Ni%%{B-;1ZYHs=vGt_msP@W zXhD;8D~)&LqK{ral{(Vu%8rLaH3bE=1VWlM{*19vJatJR**tofKGMg&NKRGJTi-Dk zr)%`qGTEAXk!QN1I5Tw3P~L^^17}Sp<%C?_NyP>i)#xT=Ay-o?;eAqWf|Z46i+HFt zGw3bjEKT*hCzp1njzkO|mtyz9vpuO{K*7*bTv@8oJW=Isny1R>$Tn2MToxYXWJ&sEWNbq~X#jA1-d?dn<0CmEz6$X=^vlH(7WMD z3OF971EOj`thWq)O0QO5v#S(bRUQZS zV^Y9NSYwExTp~FHjxviVc$gZ#KLrfzotk~qMEU^tR0@gnuV649m6gfo@qa8OtE?7qm~>~R~}upwe73NrA4Y08}t6C#l~27B8p(9q-Z zI}sxzHzsCf**v?`zNx?FWZ62NLGcnU!0!k<)~q?_gQT9$<@J38=15vz=M4EknW_>z z2LCA2705!jNn)av!Rn*FyJ8`V>OW!nw>;snX2>!D2A! zn$uUHH*zSL4LR6m7e(2Y95YR7pGkfcAn*0wae}hxMiX!DMlbq%%!@#(iP8X3R;dFG ze2OI5)h2s>vCK2G=i$kdEzk+p$q2hupCl&P3-dKfhL-pA7_-9tWot-}@DRi~+XdV6?qAR;#x!esn(!9OwHCfqH2 zV}iAYSMDVjTzC4jDR~1-2b0fYGG+d$E)h-{q@qoPS}#ERD6_NK!G-(pCmZqRt=V*y zNxvU8bL)Oa+t;q+_cPML)2p{;`+MCg@M`!KXg3})QN}%uq>c~RV;uQUSZl>P0iwF< z=3_y;z{;9oiLAQYM71@NeNL!N6uN$_G*sTZdQ*?y5(2AYWr%>I6pu58fA-yah=p!5g*t#E`x=xT%f<`eW*$hWx;WPK) zt?@Vm!9pw|+=xasIFX2Py3vN*)N}L#`%*3Gx2eEJt1x+JnHy%9%bTGtteelV0SyQ% zuA4nv)4Lr|*gXxK$6Z9`JB{A&7RE;@TGp|{ctM-1_lnQB;hEr zkWm;S-gWfjKopa()Bch4Z!o=S2ja0TH02LcwF4L4ld70kRO<1v(}Ur}1jWb6bfAktDkukzVJ5AUdPd}#7s8p3TWOsYsndM!vVCCB^mu0@i(Fpd%9}ZU z=5F@Ch%FM8vz;NKpfmy4CP?HUJb1k1RM};z&JycYX0-UNu}%jLffeVJ^xk+e;pBJs z29h-Pl=)dJ2}6wnfN@L6aC?l%DS*zp#HqW>%)%B?>*KR?#ly7FbZ!8}UkCm>A0s#xp%6UN@bZvX*Ry#tb4J;=t8Kr+C%A@7p|eE4ZM`7R2YMIAEO__#wWp&jGKUL~?F_JP^zskuev{!s zc84W`s~DDrJaP=m*lrO>N&gsifvTksuroK>m)l_(oEC78t#g+`8 z4OKMr-mKHov+nTJT&gHZfh1lY*=btnuXl6OFJ$P(ALs_Wp}} zvaDgP5ts=VS}S#k?|UApeyn+?P)pp1++3JAqP~)dh)M_$g8eaHAY`m=Fc?j>{HV+c z@U$LT=(Vuc@PluzTN=lvgjAg&5_seE5-rh?RYVT147?1IXARNLMduuw(YqUftZZH# zi7%pu7uPC$bv|`@Jf|~O2oiOr{8ZDVlETh2mrkAsC_EmJD;3@?XF6HE?#;oi5%x@l zNt3}%VtJB1mMF>ycF51v@>w3*w+1SApeqvIxGndY9&SygteJ~W*TJI#PzkIml}!N6 zgmCqske38b6Me&fj0HkRnqHm_fG*sndy{!+DAv?5M^MvUtWoLg)MjgLce?0J-n>5> zwB&Z79*3R`n;PN~iAV&c9u;iCl##|M-5$CcQGIT+&`E2z8@VkDkweIBlv!X{^8n1i zy~E;@O56|X-^I%n@fNg!A~73hCAgh=FJ0kr6MQQ|GTg<04&dc|BhPlq%bbhJSU^-mm#sF}G3k`0$R}inj1adYVphDV`Q!_$8GiLBK-a25pEyt{%EaVpl=o>Ay&iU{;%YVx zUYF3w@0*$LYZ=*^fUv%Fc&xG^;?WgPcDfR_uti{|*0JJjQ}(H8)!(vB;togwaE_uN!stw&1ntcNG(P+!A`I{ znk6I3lx8JI4ty=egZ3uSj2Vqb+Ju=YH0W~X z4I@k>+?W&C3`fub15T(NF-cV;wXG&#(kHs^$QYb8M|iOrp`M&G^SqeQu}ptmvyU|G zoeL<@#ok$vuMxRSnhqAV*b98TN6c}}4YNMBg0c5VNo!ZUbDceH-iX5T1mCyuJ##nv z;&NQ4-S6l46z4yqbG~}d;TKBMYw7$C`;KwOqKDiU}dA$ zlr<-%yyCg4pHPBj12@4~H4_BDoTvetWl&Cc!c&N#C{<;5tv-8RCK6TfW;uGcX=hX4 z`D`=`FQ9ANl5tXQl*ueVI|*SH@<}$^R0J~G`g8A@Hwi=gvh3@to;!;WMss2?NM{SA z$G}2iMH(_@QhLk}C)NT3D1xQ2f4YlJFGlQ11Mh6$AL&3b-zG+6i$;FHHFc%gJI1DT z;C^k7oJGVcx@jhV%!a9kkSU8BQgIdNVy#0g>brxjzR<4%+nW2pmO9U#+z;e2$)THp ziiY4ckp?@RLV^f01SvqOY%8fbV~E67Eis49y8N6AN^OeIueKVn?dAX8Kg-AA&z zR*4}~CH{bu5kDm5>IIZw0Tf$DhR5BfN%Pb84?X(^_Wk1e7B{t@=Of6Q_f~NSDntz2 z(nqyNqMSy`pLTX2@KyZH$-vC7D7rM5 zfiJ%JCFaD?$p;w)u3B#YjBZ4DO9&TWaM@ii+5!V(4O0um>HahS-xBjDxWs-`M%$qt zgVsLYl=&cyXwP;PhvutU^D2ceZ9nSz-JQ;#<$9NOR~uqN2`wLYU5mJ5S}K+20m{`% zQ!{paB$nH{Tw}bhCpkl3w5QL@wYLanAg}AH-e9aMb+Kg63*S%yx@7Bt>0o%e$hE!A z8jA~|J~FtZO)*6NNA{)RFToOVi&(`df$BXsd^gzVz>~2xQ(tmvK+0xGNO7d@!*xZGlalQXshTq8T#&d&$S9H}IW6yvjC8Q%= zt`wI0iq~2o6U_yHVxXNV(!`jM7Fp4gs8U+II5iMQL^>1_rUA#xkKe%KZ%c#ST+Te| z8s^Gw^Ch-!%Bc{$8r+6B9pqJL$22MO5CLUf#dc<%l1O3e7C;{Zpla06Qy@6wogS06 zw%@xm?0206-`QKgerdJ0)}T>Lcd|so?4}i~ufJ#8M%ox%({_-%IZd9CO{CV_uzMi; z;T%~&OB`C+RK}{Vqq9!7#!ow%F-}0QIYdc@$r06{3UC|ViS?*}Vt=wV!~&btSq?5- zrB7KBOe}b9cpvj~Ef+=;DM+J$Ue&YY^Jzd`F-2zuLe34RP)oh1voSDP42`YVb~^%o-=kL5ID-08pYa zyHE$Qdn5ob$+|)xfB|0*rcE-4rR%r1SrC^N6A9xc5*s`p1OV4$?rK}N*ivCbSUcKZ zNHI5X_Pi92VjBmM`Zh5Y(O6}y7zw3Z(shx(bB1{F8oI~DAA3dXr^CEOFSl)^OyyN_ zSJ~6cP4#{+`~}Go8?(@e8;u!b0Aby9m=2yh*Smb>`udeiYa3TC_q0Xkn)%;ktGkSC zHiuX+dD^Q(^ai)|9WFLczJL!esU{K;YY>n2rsFi1m^x+=yg} zNM))oLLWVy+88*vW*DnHFwgLTxyoGb5Q9QK#jhDozfBmQ(SZNVR*ijb(nsG$^fJ=3PyPD+{5hp zGoBo4vJCi{Cd;Vx<~9ws=3sFC-ts$E-?jR*twowc|J1aPL{yL(=m9Ahq7d+0bLCIc z-bSjYe4&PJFa(3C3%&{?J@4C|6+Dfp1@`rBKs!6f>x12CH#TN{5TX7UtOo4fD*}N` zIZqz-9iW_ZYPW_Z>4CKlYQ9jVyRK-#>Zr>?v(XAkkO1>+(;9H|WK0)_4@w-;HJ1sM z-LHKn#65h-`c=SDtP&N2T^+CikHsOBozYDeJKj<#+Ul6sSXUz()FNq>I!ERhNMjiu zB8&M#24(q}w7d!=F!xV@(#QkY%Ee*V%N7waEeaH9MFY;VP4@txK>>*ODK~e#49;^tJfK;6Y z{J2OO1OxwNDEq1&&5h_lDH;`0fL$xSYv7LFpeHm~T6dngWN4)l2Zs})jwW~<5_+s* zQ;iT-#w+nNviR_43eA*g-SC!*yh5PNnD+otc%52wgTh8*Y)4l=*hdW%gFpdLoR9fn zpj!jmFNZ;zQ}-19Qwu65gO(R7c%G8Zs5<&)ig;NRAe|QRV!*W2FWMeqQ^V1r(J9$# z`%IF^z=8{$Z{KDRF9B#vg*G~$!U9TPYCyk4ABzfP&~LjE zm}=Y5))Z11fd_}=E^c2??_p$ivthfUSabU_dnO84D^5DRyA>dNsGAbjq8xnM+E+^p z6w_Aea?9IT` zO`~bBwqzDb!`99W*d*GDB?q9)R@YTP6UGYGE7>3Wjn%RO4wso(Et3d0_Q@uwx8=@C zg|18l@nfEPh^dM!2?CI@deTR%gcE>=TE*b7D1r73eu?*DH8yswA(8M3OI(a(Iwsp{ z!>Fo$%0-X7Cnvk2A@z7jynjD&4sR4g9GrHBtvyJf>9R?NeLVFE@NLdz**7L*>v+SSro zx8Ngn~3bMj}#=-boSb1x#)iaP$!RhF28yPFe@bUz${&8!gK~B7@wv@;8 z-R81p^#CstiYvT(mAyYtXjV}dwN}NTZBY(gj&-Msf!riQGBw#R1qN%rS$FOFWHsg> zd{-H$it4E>6^EcTaQJO$5M65GJ8l#;6E65g&b%5n^sFsp@e;<_Y_@>=hfENn(Bp~J zUg^RvfW_1rwE}{Eyf_3fKbUSDg1`gyN8!sfJ)Gf#3tZj2%-V(-yXgq6&qpe3ax8GB z?CjU?mWDhGpRqr>FH#i>rK)BN;stN-C5i_(;a{x6a-XtY@Z1GwzOl?wwv^cj=60&A z1Y6PwSJX}Uyro-83nDX{RC&x<)EP2f7|Bu-(Gd`f1g3C0C!U66UDa`85Fuh6vXqBL zp|N54md38N^+&M;!tISwOe3*$np3C|8Nk|rF^EG58ewY7!;D|LVwQxNkl z^K0H-62lONzWbHzhaL2D%kQFBnjPau=~JY$z`DN!^AD1sa&36nbHAuqFAwone{CRlVavkGiN5 zz9Ne}6j_QGCE!c6-8fYpvn4JBiy7b|#S7>pK#<48nWv1G4v66hLmIH)$C97za|EJG z{OT32A2Dk-)-B>VVB(SUmZs``(pzST41p9%mNfR*#45TGT3;>;zcLyam7LYmAh2d@ zGQKU9l%K$#ps$4$PHyQvl!+3Rfj<&pJ@IO_4O=uhXPuN15#HeTMh%A9-HiJcz6H<- zozJ0gE3Hh}Z@$fat^5bTmRC=mF$1I3(gEo_U`O=xel>=kOE*vsvOOLKpUMj{#LjX~ z4S9JD2#}S|x`Lm*fv!|79yaiLdcEyI0tdCBMW<+M0|bwO(38l~Y1SN)CnMJj>lo(V zqF$E8xyM`hOjF8FS+*wJ*JKl|%tJ#ttu@!ITL&N!hiHb{ZdB&%fIdhX zvm}7+c5kaYuEMJeu|aigp*_EqHJ&oHIc149~Mp=`6nYi#)VJ^-T&}4%X?bg3J3xwj4*AYPw=IT7_(wv&}1JI$mW5 zLqnR3C8lG`@+GTj%}!fPzWXFP$&)ZM?Q;QSG+-nc$~Dz9bS)WE8__o!0rReUm_$<{ zYQlozmqpkoY$jrv#gl_>h1|@;)sXb1!4J2}|1axC#{+5PnIy3>+eTPEsF_+95CDHbC zDz4oEq$YQsTyF5Ls;FgtcsZiY%yfo$aITBS`jGuDTGjb z&jR^Dr=kbfXjgE0mObA+80|A=?9{IhyCHAuDQ)r1}&n0dB2;c0Kd(FTuGH_ML=CkdgY83(-+#- zgH@KY(jV$;)@ue-+H#d4X9NafeBVrhc*a+IqiiW)0$tv$j7?A^M_)t<*JAFR0U4Ev znH$g>Sri6M3Oo0hOqWC7*3_r@Vub4k(>AcjD;UO{uQhNxo80tO{ryZs|fM zhLg+~-F)tPY)&6yYKn%L_#O-i+^L7@+gLj{x`{3!b)sFT?>f&dY1US=$$VujF%11L zVn5hNIF_hL5GlCTR%LQMnoX5tO@IE)TEz_zZ-uNoPD{muEM-)SUh{doq59CTHJtfc zAtI@y%DuHogJ;QLC3nmB;K`_rx*q7ZU?OeixqhIpapsR(s7ZVTF(|88YQMlFFn+bhg^xMbIt0M-bK>5pvdtizjF_A3mNkPq+4 z9F7hSZ42E?Y}mrfS_96x;oM5^aeonBkLgt~F$zx)^_C2!5*qc`o(#5NC}Q%{+awJw z&)Ea>DTKCc?wSF5Z+sKGmzWywIxCIvj*l{X!D%1Awjr=(=y`Xq4|O%(4y*TYw=#o{*Jkt zw0n=zz+fiOv!xEXX>#r2jcboy*|-8d*?TF{U}>()=-E`~wU@Z1lIWR@98vI9!$b3S z)geX`$phBQxH@4$8SjFT6>zkd`#Rq;g{7P8ljV|i-eVS=AQ+BQcLMkxpZ2Po#u$wX zgP+|Cd@g;v$L$Za4oEu4_89N|O@e$*KyQqMYr*$R*kV`$G&RX5lzwMP1KWG(p2h}6 ziX}g8IeqeA?0pid_sJACH@fpduH&;&;Pb3CrFOL5t@wi$tgn;y7AzC)DVx*R7SXL> zjN*mHeGM$K0%hU^gOvxz{7!5?+3E3BwwLhaOEj*0_ATBWul06cVm-va;P?r?cQN*l z(68^{xWx6p!|@ARcgM9C$bY}0Jr-R=4|=(1f}NLR`Wv-cUBf)8UMgTHC0hmXpgPdm zqNbEcQN3TOEo4Gt`2V*n#Q{IXQ~Rp7D+OVx-D%*NU z#Ct+R{etb~I5`9F>VCkqyM7hN#_$<&Dt(=s_bP(4s5YSEf zDtkwi-|szSj?bJ;ykOvfR45rI#;3HOnkj2fh&tcP@3+oCxz zh5TM@V#<(RW*D#Sb+n7H272jF|LI2Ob1~rICR6##D;f(-sL$QSX^;mr&6QEngDwMW zvHILDh6M=)!gM}}khSf}gROIF$s@WMU6W5mIAAz757AZ9_KBD8?aFy5Q1F;42ugE~ zU(7U{)P_}?&ga0x0Jp{OET~gl9vyp4Z(^=h){mME$s_kf(H&G?AcV!_D<1bm5WHamrE zP2QhDj=z7%*6}668hQ={F9mLj2ErpJ^vKU4-+zMZ7g?A8Q66~W9i7g{@kc*s>+Y=% z5)(t^_nrEbu4R~k_6y$O>mFhWg}*n3)EI*%-3eg&zRAKl(kRTSq*t~Oj|_o;3mb1k zs1&ZL8|r1#ZkE}*jXg*XU9Zinh0JcF4$?DMFj2uVUU-R!y-!0@X~>4n@X(u1o}r@e zFor#KTSL2_xH5rac%)@;O3nAAJEm0^*>3!ouD{P0H_->%-Ct{T6wRTSzsE2$UMvT| z{KqmuCIjz|Og?qhgS>162F<~(=*;@sV+#H;(%a<2OH1A%X$?R*w%f?EbTgy!&!YTM z#WHM^lDK8#wSBlZ;_Vm4f`MD0y?mHjK>SK)OxbrkhZap|)W`)Ayws_t7rrlJ zSiEaxVPyqAB~1$&(GBq5fWsO-)!cN#)V(5y6KSHpTpS9JPp>*MHUVi9A~ZF?fNJd2 zN20W1O-bUjDGl^>uB6}vp1XVOXo3t*ytbM`L^MsU`aVR;Lv4l&9k#)$;RDqQrar4q zVoiM}sUt{#hcG))>Gi=KEq+%9j|C+};)yGIiJ!bb)E>^u0G;IwH+fFVZANu|MpI)O zfmm;wX5Sq_xUrH=-3t@0V<`^c0Ays_WJ2qVQ&VV;EnRgcZ51N?VKPvFGN(&chaMss z!d*)0FflScZmIJgl94ZS1vv;?p>Ac^=6%$uF?@m-T-toPrzS*z4O*&=v3KN4%_)L| zkT>Tc{ZqNTTO*ogDVqf*vNK&$k&&w%{#hBJ{q6K1MId*BrDk2p#yo0@qwC3Bm0G%@ zc&IJ(vf&^y=*5X_r<5EH$i%nWXeoX%t1p0;rjX@nwH%wU=DX{@dQ zNrq~N%jT^p4cjPmr6q!FXIz%y7YK>9;;d%m&Jt`fCq5{RpmLzfbIQcXng>>eRamNl z9AG}Bo7rWSA`b{chnL6sOJI}>!mY!h&jQueW|WjpllJ7c_DU{uPkI2eK9pyy+8Q||w(5{X^r1A;+uvi5f`6l7K4}{? zZeGErVRAnCnZ1Ni)|@H8>n#LsB+;i3^Mo~1ua_gEO2Y(ci+a+Vq8V~l{88AMjktAj z36P4{?i&3no2N90BUhZD2@UujpDy4~Sz(@5Q@%=M8;p{v3d(YeOE8%DQ{G0Gw-reau$F)Dp@db`oIBK7c z4{}`MIMk76Kg#h7yx;ZrI6lJlKj8QT*S|ILCssIqgzIY@@8Nnsjy_*zKg~&^So&>< zlrD^j(3d>V;P^Xe|v$a`HC2GB9M8 zMde6H-fhfF*HM3#v_OlsF1|E+L5ks~)L6^@qJ`*-IlE6y|H4$w*F5JO7@zF|NxCQI z<>99_4a!si2GuFf z?oKUD4=hqb??jrC0WV-+8+j@KerN3Oco7Wx;*<|DHbu`9w=4=^v|e;P(NWsv5U{h> zd>-u{*=3`d3(}mo$a#Al!h{%tGe{r-)gV(-XxuxwqC|$KyOrP%aMo|o58C3 zTeiQ3O(ckiZba(ogmGi;^xs`=;x>;R_(r7nX#1dMpEtvI+mbrjROg25e{%@U>GdKa z+e9pyPZtf0UDNy8nEI11(IA| zP=N@TprJ_st&VA$FMP$wVtPwlj3}l-7rV_@%<)#WU2*Fc$UO~f)5f}qogOb(Ouroj zvW=Ets!OdLqlnl`)D3C8j%7>DLyrVa)JV{qa`I%n=|#(!G}^Uei$EpZmWO1fxD&>g z*UDVC4pv&KaXz~my-e2`59a3dQnHOTp~;qwbuQ{vqO@6QWH$Gg!Y8@l7SgEGS;;ZX3lV#-^+Dhs};hE5u*a1 zw0%nKryuoP+kzRx;_03{BLFz>rBhN;qvNpyxcTHH1q=!$^;z~au&NT}Y%`6r-`M8$ zvW7=tz=(fENYvcVn=I7DUEi zDNx26%qX+;oBaIKn{S-6rTNZv-@$4QT*li#vSRDe{2B|S*zLTAs(6?0eubP313j(O z&Sf$O?Y*t3!UrKhOWLz|!hSbKfV|)fG`Cf#RL6^5Y(IpeK6M@)?$Ro}dY`>INtQ9+ zA$1M3vW)m{3b1U#unxfFO^AxD>q<4*?S`=IYsMx~aD%bYsZoI$t<$VZRtnZX0b6g)FG} z1+`hGl&dU^q%vGWdTCsiP|sMzZ!}O5o!4TS;#PSX_;K&a;>V{0_I5FwAo_&tlx{TG zc`~#Y0~>)g0@5T(Qng-b=bQSb+Q1qRwYT&z+|O-H;VT;>`-G!jvq05+?_f z70;F5CnLa?B6+aK8ma;~kIfeoDOq_wchT^>}uq^)X9Cai&7tHH+tHO;VWO z3OS;GB=-^nnX$E$aW*r}yDCc8eHYBwN|WFUc&gnQf}^8m7=t?|$Rt`cn7Gp1?>%tg z0iMgPS}lVkrvJ35+rZY9Gh7%uiXzXwj~3LE|4`5|5fjOC z%ClhU#)!=!W7`AQL)o;c*)vD2+o~VEsl?!WDC)a2WCsq$#%=OelwE8~zWUn}ULXa5 zW66~6%9mfyKyhfQLP+6|1u)GtxUXo6MG2gjoF{Q+S&|Hd|BaT2UTy>gXji*e2y?(p z&7r8&8WC7|5vlZ{1N5WhgZ9#jf{3Dhi>8YghTwIl3$>Zs+upNdjCPJSOS!FU0e!Ce z)a;Cvwie4jY>9{MODZ9wnbSP68H}sBOE$f1AmMhpkZ_|BgV`Z}*1(caYStN;95+%e z6A73mvKXW%*y3mm3XO{%v7fUT7WLmyswC<(yjxt`G-^c+mQ0IrkM|NiHCBc)=CD=I zqZ?Y9%xTG=Hr!kP%s|H)HTClJw-psi0 zEj)FNcIFK-Z{^*AxcJI@_8KgJn?i5(TRxX=PXa{ z^k-Umr7b+!V1s?bgrlnCrnYYoSbgD7ck})IS>##b)%4I^r4Em@q*TBRWHmvhwU&(i z19C68gS_dv(4KaQr3ELo_t?=e0ykXEOtE+n@JZcY9%>EP07FMfT)vpwCT{j(_o8>4 z6`tgVgL(CxXH%=AN30=&?YI|GTPm0Bu;@(D{qp5*h)C9cYMZX0Bga)CU`4IK!p5&P z!gzJ$s^m&>oq#arP8ex#KCzpS3__4rO-?Jln`4*}K+;&_P4G)sR<5b$rSp1wFzFi> zH4Yg0TNCw44WWbNl;O6Po)*>BR_()>&?<9G(QWT>)7`FhS2fK^sS^^433cD{_VN7+ zw4sx^Iv#TBMl8}tv(v6IMLIIDN?9;Q;_J{GK5Z%rlcd$syf1?N3k?@!^QWTiWa91( zy$2i6J;dA_v##a_cJKPm1Enf+4FHHHNqDt;DVdwWMEI$-!jX3fgENqOMKU!pZv=YS zWs!24$)ZAQDOA%{i|U+XJGVy_Y45$`0^7W8P`EXgB1v-0p{0~5MBrW%si@%vW}-q` z@J~i&sxpjmEn)@Mai_Ic)+Y1l+F+SAsgsI(0vfb7y+%+tZu7{xU@4#D-Xk}zJ-#CS zm3g=>^%(Dl>EZ0;M&CE2B0CHtc%!bywjz*)5=3aB&K)4}*20%7gq)!NnQxuqbv$6K z4Nzo)!3l8ncC;6y>nFTGK{*%NP(p5)L`G+#ZfHrAtTi&2wNoVk$I8HX`=`d~k82u+ zVxDdXs3yIJg9bD|djN^N4yj2(WAAc%X)uOvx50}CPQi;n2Ln7Q^+X?17c*Pam1VbD zPJlr0gjv!_GmYa_HQ;KjlM>VQ3gqf@-4WFf#xGh@4x3Rn*e>21J&C!p4NbK>QoMDV zVTM)-EndO*ClBlzDh+xWxPlPrt?>#fyj;%NBrf!3oxFKb30y`05GvGK%q4rtT0VOT zwa}|JRvke_^O>`SJ3aBoWy)pK1_<$7YgF%wE`+5?6@z)V-GYduU`j&Kp-_M;>BYlV zJEMHm2>O8*CF`v%RBu{pu&>-g$(+*d*P4d{6mODf9JQziz`eZr)|3qEsiN1mAw|sh z@{(SoxiqgT%LXpV#2FtuZ@7^+mU_cIe3*sy_I#sOq~zG~TiKhO~{* zD(P``>ojUi9`{P0Idiu#@I`+hq;I)8F$t!_Qa0Y&p>VXJB(oLoJZWZY)n96(=`M}& z-V2BcH(}@>8JMi$2A3cyV!x<|9f`?N7OA&<# z{LGdl$%=ct?1v+(qor3IY8x1PJ7G|8S-ukrJ1v?rE$u|{8}w}Cf-M`97HuxOrO=w2 zwLhdqqLqQp7=h^bmJ;Jj<}ER^-3zlt4T=p{Fi|pP4;5`muJMPumxhGUQKQ2WnXk?S z(WT1k8SEiaD+rbNivm=qM3{MJZ0VC;%N=<`(Ms1MdNyV}YRo7UyE!@7Ug1egx+>oA z-UpPhXEs6hP-Rmsd#7k|h^v5MDgGfX!$;VA&^Y$HZ00QI4R6*EMgW&kf={f>C}V^j zo3)Yq>y#U=DbkGcRv}dn07~;vpp^7qKtc2ix~Q!2&?(Ld7((Wh<0Sp_TQE zq!FmB1{Qhe2%!WUMDJbnY7LR&nRhktuc9Z>Cw9Zq&O0=)i>?A%YimX=mBj4e7lAuS zT4wf`EpKTGwJR}I^CZWBUxq~&Te1)heAfJSX{ejJiZPwT1enZ)!I|+X4+a8<_YXXs z-u&iYB%c7lTHEkAoPP1f0><5B+S&pmgY35}gziznkq-Cc7_rmU)zw~eQ??$w(pMtM zKYtJFbI5m=6BKAT_2f!udT(5Bi`a zQ)do^sn*)XJ_JSTl?VlclngTWko$w>d6GkdQkLcAAwKDZl0psJXXf80$-r~D1(*HD1M2)N&UFA|_} zMc~8SFw;qJ4)lVPx<$@?Lol0ythwle;Rh?5umSYcx$DZLvIN4)5Ksstv7ESVF5nhnJ}R0HTtV1Y;g$s5`Dcc6?HIqNH6OGi4GDB#z(Z?uHqxfI(k~G zm>i?h$Rl%~3FWhBzCX!)KgPXv@}e$ls|#oeWgoM{EluCfOh^|jB{#dvI5WONX>i75 zH?JLRGJagpz(E9${I(SIWeCj%O+E7a(EvUsk%tUYk}rs%CZm7gZi8NHJ+bAs!K11;672}Gv zDbezx`TYoT=PdL4!Z$+C_8ukcfNEx*%UTzOHcWt7lP)Q6Ru`UOeAdI)#@+1|@@p=! z3yZ5O44Vofx0IXOTNkg2_9zfb9JF)nm?ai+$uRf)ch3uxv&8OrgDR?vXyvvPO_Vk` zjTWXyR9HQ1k19H06FMDPfG2fk9@Tmsc^PGv1-4sg0il9z8Jitz1MPFgLKX2p*ys+) zf;3nDs*MUUur`vkO}xy-_obl7)Q}>gI4d<5iKcOA84$9z&z_#?ZV!1|eqb!9(i1T~h6M4#}XW`ZW z7(uKyX}KKI`0W`MPnY#)u85g_4GvfS)s^I`rbvb~3`B=O^h%NBf6}mNExFnJvoJj6 zb2(as9)TdPpzUHhJqLouCU-X^yf~JBp}X`vRO!G}Q?N5;H}886(3t=>s4v9Wq$7DAPi}Wu_7a;a-RUGW!U^b9 zLxT+qv!%~2d^2j~*0625pqVLkYgy{!#q@T**yN}SteHk3E)fgF=!9iAj_4zV6Arfz08cg-xwTl3d=%rn@IbXqjtd8>?0T1vntSDsR>3^t+Ieh)6zn zb=Xp`^8$J0cOg(ehFMu<>n8); zoCEJ>js9S@LVqz00S42EAt>Hg(%U4Z6XKk!fp*Mqm--)BmKGzN<0{mNK$G{g?w0X~ ze(tW6LZ6M|(fQR3zw7t~+fLVA~P1dL?7ndpJ}yIuCJET6@63hGSi# z@G0>k7gqcFM4Kez^DJKn4_CVnqjfQ-Fd3}5xM=&@5sij>K>Bdu;dF_TPsUuYNoCu_-)@9(lhZubi zNe#5cK1#N#-ou0o!y*=ii+N|=D+$Y14!%#kA*#7aq!O8E)w48?>zp2HmV)FO)R9^q zzG9nhLt=4w<7%EuV^EEL&`86xWFKU9xy5{2+(bwbK-_6!nwFpdWYTs(CO0by=&{ka zuVHZPlw8>t&|#iF`eaw$fThr)bu@booT$>BS^+xW*A)A;MbbpaK~`1}$jTM}1qKE| z%~4Y&qMLp>Zmrd1xy)n-n9fS)iQRhxtH6wicPCzf2dx)`dI#s`f4foOYjYdSE3T5@ zJ0Ju5Wtf!)lIKFV6$na1W*$G0T#P>Wqei(B} zYsEC>3pIGyXLnQDpj3d|_(=9ySF$73CF!0}i=~h_bFcVt}{Wmy2~i#vXElk-q-}aMDrx-r}O*_nFT1Pp-fHn}7VCpGPEj wKE_x3Sjm4SkNGwm0!|LxU(O}_c)7beKl}TC_tsl}@Qwdc^-cKR-+K7}0T7L>+W-In literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/FeatureSteps/CodeGeneratorSteps.cs b/CapnpC.CSharp.Generator.Tests/FeatureSteps/CodeGeneratorSteps.cs index 8537a48..12b5070 100644 --- a/CapnpC.CSharp.Generator.Tests/FeatureSteps/CodeGeneratorSteps.cs +++ b/CapnpC.CSharp.Generator.Tests/FeatureSteps/CodeGeneratorSteps.cs @@ -241,14 +241,12 @@ namespace CapnpC.CSharp.Generator.Tests } } - catch (AssertFailedException) + finally { string generated = _result.GeneratedFiles.Single().GeneratedContent; string path = Path.ChangeExtension(Path.GetTempFileName(), ".capnp.cs"); File.WriteAllText(path, generated); Console.WriteLine($"Generated code was saved to {path}"); - - throw; } } } diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/rpc-csharp.capnp b/CapnpC.CSharp.Generator.Tests/No Resources/rpc-csharp.capnp new file mode 100644 index 0000000..fa0f149 --- /dev/null +++ b/CapnpC.CSharp.Generator.Tests/No Resources/rpc-csharp.capnp @@ -0,0 +1,1415 @@ +# Copyright (c) 2020 Christian Köllner and contributors +# This is a modified version of rpc.capnp, found in the original distribution +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xb312981b2552a250; +# Recall that Cap'n Proto RPC allows messages to contain references to remote objects that +# implement interfaces. These references are called "capabilities", because they both designate +# the remote object to use and confer permission to use it. +# +# Recall also that Cap'n Proto RPC has the feature that when a method call itself returns a +# capability, the caller can begin calling methods on that capability _before the first call has +# returned_. The caller essentially sends a message saying "Hey server, as soon as you finish +# that previous call, do this with the result!". Cap'n Proto's RPC protocol makes this possible. +# +# The protocol is significantly more complicated than most RPC protocols. However, this is +# implementation complexity that underlies an easy-to-grasp higher-level model of object oriented +# programming. That is, just like TCP is a surprisingly complicated protocol that implements a +# conceptually-simple byte stream abstraction, Cap'n Proto is a surprisingly complicated protocol +# that implements a conceptually-simple object abstraction. +# +# Cap'n Proto RPC is based heavily on CapTP, the object-capability protocol used by the E +# programming language: +# http://www.erights.org/elib/distrib/captp/index.html +# +# Cap'n Proto RPC takes place between "vats". A vat hosts some set of objects and talks to other +# vats through direct bilateral connections. Typically, there is a 1:1 correspondence between vats +# and processes (in the unix sense of the word), although this is not strictly always true (one +# process could run multiple vats, or a distributed virtual vat might live across many processes). +# +# Cap'n Proto does not distinguish between "clients" and "servers" -- this is up to the application. +# Either end of any connection can potentially hold capabilities pointing to the other end, and +# can call methods on those capabilities. In the doc comments below, we use the words "sender" +# and "receiver". These refer to the sender and receiver of an instance of the struct or field +# being documented. Sometimes we refer to a "third-party" that is neither the sender nor the +# receiver. Documentation is generally written from the point of view of the sender. +# +# It is generally up to the vat network implementation to securely verify that connections are made +# to the intended vat as well as to encrypt transmitted data for privacy and integrity. See the +# `VatNetwork` example interface near the end of this file. +# +# When a new connection is formed, the only interesting things that can be done are to send a +# `Bootstrap` (level 0) or `Accept` (level 3) message. +# +# Unless otherwise specified, messages must be delivered to the receiving application in the same +# order in which they were initiated by the sending application. The goal is to support "E-Order", +# which states that two calls made on the same reference must be delivered in the order which they +# were made: +# http://erights.org/elib/concurrency/partial-order.html +# +# Since the full protocol is complicated, we define multiple levels of support that an +# implementation may target. For many applications, level 1 support will be sufficient. +# Comments in this file indicate which level requires the corresponding feature to be +# implemented. +# +# * **Level 0:** The implementation does not support object references. Only the bootstrap interface +# can be called. At this level, the implementation does not support object-oriented protocols and +# is similar in complexity to JSON-RPC or Protobuf services. This level should be considered only +# a temporary stepping-stone toward level 1 as the lack of object references drastically changes +# how protocols are designed. Applications _should not_ attempt to design their protocols around +# the limitations of level 0 implementations. +# +# * **Level 1:** The implementation supports simple bilateral interaction with object references +# and promise pipelining, but interactions between three or more parties are supported only via +# proxying of objects. E.g. if Alice (in Vat A) wants to send Bob (in Vat B) a capability +# pointing to Carol (in Vat C), Alice must create a proxy of Carol within Vat A and send Bob a +# reference to that; Bob cannot form a direct connection to Carol. Level 1 implementations do +# not support checking if two capabilities received from different vats actually point to the +# same object ("join"), although they should be able to do this check on capabilities received +# from the same vat. +# +# * **Level 2:** The implementation supports saving persistent capabilities -- i.e. capabilities +# that remain valid even after disconnect, and can be restored on a future connection. When a +# capability is saved, the requester receives a `SturdyRef`, which is a token that can be used +# to restore the capability later. +# +# * **Level 3:** The implementation supports three-way interactions. That is, if Alice (in Vat A) +# sends Bob (in Vat B) a capability pointing to Carol (in Vat C), then Vat B will automatically +# form a direct connection to Vat C rather than have requests be proxied through Vat A. +# +# * **Level 4:** The entire protocol is implemented, including joins (checking if two capabilities +# are equivalent). +# +# Note that an implementation must also support specific networks (transports), as described in +# the "Network-specific Parameters" section below. An implementation might have different levels +# depending on the network used. +# +# New implementations of Cap'n Proto should start out targeting the simplistic two-party network +# type as defined in `rpc-twoparty.capnp`. With this network type, level 3 is irrelevant and +# levels 2 and 4 are much easier than usual to implement. When such an implementation is paired +# with a container proxy, the contained app effectively gets to make full use of the proxy's +# network at level 4. And since Cap'n Proto IPC is extremely fast, it may never make sense to +# bother implementing any other vat network protocol -- just use the correct container type and get +# it for free. + +using CSharp = import "/csharp.capnp"; +$CSharp.namespace("Capnp.Rpc"); +$CSharp.nullableEnable(true); +$CSharp.emitNullableDirective(false); +$CSharp.emitDomainClassesAndInterfaces(true); +$CSharp.typeVisibility(public); + +# ======================================================================================== +# The Four Tables +# +# Cap'n Proto RPC connections are stateful (although an application built on Cap'n Proto could +# export a stateless interface). As in CapTP, for each open connection, a vat maintains four state +# tables: questions, answers, imports, and exports. See the diagram at: +# http://www.erights.org/elib/distrib/captp/4tables.html +# +# The question table corresponds to the other end's answer table, and the imports table corresponds +# to the other end's exports table. +# +# The entries in each table are identified by ID numbers (defined below as 32-bit integers). These +# numbers are always specific to the connection; a newly-established connection starts with no +# valid IDs. Since low-numbered IDs will pack better, it is suggested that IDs be assigned like +# Unix file descriptors -- prefer the lowest-number ID that is currently available. +# +# IDs in the questions/answers tables are chosen by the questioner and generally represent method +# calls that are in progress. +# +# IDs in the imports/exports tables are chosen by the exporter and generally represent objects on +# which methods may be called. Exports may be "settled", meaning the exported object is an actual +# object living in the exporter's vat, or they may be "promises", meaning the exported object is +# the as-yet-unknown result of an ongoing operation and will eventually be resolved to some other +# object once that operation completes. Calls made to a promise will be forwarded to the eventual +# target once it is known. The eventual replacement object does *not* get the same ID as the +# promise, as it may turn out to be an object that is already exported (so already has an ID) or +# may even live in a completely different vat (and so won't get an ID on the same export table +# at all). +# +# IDs can be reused over time. To make this safe, we carefully define the lifetime of IDs. Since +# messages using the ID could be traveling in both directions simultaneously, we must define the +# end of life of each ID _in each direction_. The ID is only safe to reuse once it has been +# released by both sides. +# +# When a Cap'n Proto connection is lost, everything on the four tables is lost. All questions are +# canceled and throw exceptions. All imports become broken (all future calls to them throw +# exceptions). All exports and answers are implicitly released. The only things not lost are +# persistent capabilities (`SturdyRef`s). The application must plan for this and should respond by +# establishing a new connection and restoring from these persistent capabilities. + +using QuestionId = UInt32; +# **(level 0)** +# +# Identifies a question in the sender's question table (which corresponds to the receiver's answer +# table). The questioner (caller) chooses an ID when making a call. The ID remains valid in +# caller -> callee messages until a Finish message is sent, and remains valid in callee -> caller +# messages until a Return message is sent. + +using AnswerId = QuestionId; +# **(level 0)** +# +# Identifies an answer in the sender's answer table (which corresponds to the receiver's question +# table). +# +# AnswerId is physically equivalent to QuestionId, since the question and answer tables correspond, +# but we define a separate type for documentation purposes: we always use the type representing +# the sender's point of view. + +using ExportId = UInt32; +# **(level 1)** +# +# Identifies an exported capability or promise in the sender's export table (which corresponds +# to the receiver's import table). The exporter chooses an ID before sending a capability over the +# wire. If the capability is already in the table, the exporter should reuse the same ID. If the +# ID is a promise (as opposed to a settled capability), this must be indicated at the time the ID +# is introduced (e.g. by using `senderPromise` instead of `senderHosted` in `CapDescriptor`); in +# this case, the importer shall expect a later `Resolve` message that replaces the promise. +# +# ExportId/ImportIds are subject to reference counting. Whenever an `ExportId` is sent over the +# wire (from the exporter to the importer), the export's reference count is incremented (unless +# otherwise specified). The reference count is later decremented by a `Release` message. Since +# the `Release` message can specify an arbitrary number by which to reduce the reference count, the +# importer should usually batch reference decrements and only send a `Release` when it believes the +# reference count has hit zero. Of course, it is possible that a new reference to the export is +# in-flight at the time that the `Release` message is sent, so it is necessary for the exporter to +# keep track of the reference count on its end as well to avoid race conditions. +# +# When a connection is lost, all exports are implicitly released. It is not possible to restore +# a connection state after disconnect (although a transport layer could implement a concept of +# persistent connections if it is transparent to the RPC layer). + +using ImportId = ExportId; +# **(level 1)** +# +# Identifies an imported capability or promise in the sender's import table (which corresponds to +# the receiver's export table). +# +# ImportId is physically equivalent to ExportId, since the export and import tables correspond, +# but we define a separate type for documentation purposes: we always use the type representing +# the sender's point of view. +# +# An `ImportId` remains valid in importer -> exporter messages until the importer has sent +# `Release` messages that (it believes) have reduced the reference count to zero. + +# ======================================================================================== +# Messages + +struct Message { + # An RPC connection is a bi-directional stream of Messages. + + union { + unimplemented @0 :Message; + # The sender previously received this message from the peer but didn't understand it or doesn't + # yet implement the functionality that was requested. So, the sender is echoing the message + # back. In some cases, the receiver may be able to recover from this by pretending the sender + # had taken some appropriate "null" action. + # + # For example, say `resolve` is received by a level 0 implementation (because a previous call + # or return happened to contain a promise). The level 0 implementation will echo it back as + # `unimplemented`. The original sender can then simply release the cap to which the promise + # had resolved, thus avoiding a leak. + # + # For any message type that introduces a question, if the message comes back unimplemented, + # the original sender may simply treat it as if the question failed with an exception. + # + # In cases where there is no sensible way to react to an `unimplemented` message (without + # resource leaks or other serious problems), the connection may need to be aborted. This is + # a gray area; different implementations may take different approaches. + + abort @1 :Exception; + # Sent when a connection is being aborted due to an unrecoverable error. This could be e.g. + # because the sender received an invalid or nonsensical message or because the sender had an + # internal error. The sender will shut down the outgoing half of the connection after `abort` + # and will completely close the connection shortly thereafter (it's up to the sender how much + # of a time buffer they want to offer for the client to receive the `abort` before the + # connection is reset). + + # Level 0 features ----------------------------------------------- + + bootstrap @8 :Bootstrap; # Request the peer's bootstrap interface. + call @2 :Call; # Begin a method call. + return @3 :Return; # Complete a method call. + finish @4 :Finish; # Release a returned answer / cancel a call. + + # Level 1 features ----------------------------------------------- + + resolve @5 :Resolve; # Resolve a previously-sent promise. + release @6 :Release; # Release a capability so that the remote object can be deallocated. + disembargo @13 :Disembargo; # Lift an embargo used to enforce E-order over promise resolution. + + # Level 2 features ----------------------------------------------- + + obsoleteSave @7 :AnyPointer; + # Obsolete request to save a capability, resulting in a SturdyRef. This has been replaced + # by the `Persistent` interface defined in `persistent.capnp`. This operation was never + # implemented. + + obsoleteDelete @9 :AnyPointer; + # Obsolete way to delete a SturdyRef. This operation was never implemented. + + # Level 3 features ----------------------------------------------- + + provide @10 :Provide; # Provide a capability to a third party. + accept @11 :Accept; # Accept a capability provided by a third party. + + # Level 4 features ----------------------------------------------- + + join @12 :Join; # Directly connect to the common root of two or more proxied caps. + } +} + +# Level 0 message types ---------------------------------------------- + +struct Bootstrap { + # **(level 0)** + # + # Get the "bootstrap" interface exported by the remote vat. + # + # For level 0, 1, and 2 implementations, the "bootstrap" interface is simply the main interface + # exported by a vat. If the vat acts as a server fielding connections from clients, then the + # bootstrap interface defines the basic functionality available to a client when it connects. + # The exact interface definition obviously depends on the application. + # + # We call this a "bootstrap" because in an ideal Cap'n Proto world, bootstrap interfaces would + # never be used. In such a world, any time you connect to a new vat, you do so because you + # received an introduction from some other vat (see `ThirdPartyCapId`). Thus, the first message + # you send is `Accept`, and further communications derive from there. `Bootstrap` is not used. + # + # In such an ideal world, DNS itself would support Cap'n Proto -- performing a DNS lookup would + # actually return a new Cap'n Proto capability, thus introducing you to the target system via + # level 3 RPC. Applications would receive the capability to talk to DNS in the first place as + # an initial endowment or part of a Powerbox interaction. Therefore, an app can form arbitrary + # connections without ever using `Bootstrap`. + # + # Of course, in the real world, DNS is not Cap'n-Proto-based, and we don't want Cap'n Proto to + # require a whole new internet infrastructure to be useful. Therefore, we offer bootstrap + # interfaces as a way to get up and running without a level 3 introduction. Thus, bootstrap + # interfaces are used to "bootstrap" from other, non-Cap'n-Proto-based means of service discovery, + # such as legacy DNS. + # + # Note that a vat need not provide a bootstrap interface, and in fact many vats (especially those + # acting as clients) do not. In this case, the vat should either reply to `Bootstrap` with a + # `Return` indicating an exception, or should return a dummy capability with no methods. + + questionId @0 :QuestionId; + # A new question ID identifying this request, which will eventually receive a Return message + # containing the restored capability. + + deprecatedObjectId @1 :AnyPointer; + # ** DEPRECATED ** + # + # A Vat may export multiple bootstrap interfaces. In this case, `deprecatedObjectId` specifies + # which one to return. If this pointer is null, then the default bootstrap interface is returned. + # + # As of verison 0.5, use of this field is deprecated. If a service wants to export multiple + # bootstrap interfaces, it should instead define a single bootstrap interface that has methods + # that return each of the other interfaces. + # + # **History** + # + # In the first version of Cap'n Proto RPC (0.4.x) the `Bootstrap` message was called `Restore`. + # At the time, it was thought that this would eventually serve as the way to restore SturdyRefs + # (level 2). Meanwhile, an application could offer its "main" interface on a well-known + # (non-secret) SturdyRef. + # + # Since level 2 RPC was not implemented at the time, the `Restore` message was in practice only + # used to obtain the main interface. Since most applications had only one main interface that + # they wanted to restore, they tended to designate this with a null `objectId`. + # + # Unfortunately, the earliest version of the EZ RPC interfaces set a precedent of exporting + # multiple main interfaces by allowing them to be exported under string names. In this case, + # `objectId` was a Text value specifying the name. + # + # All of this proved problematic for several reasons: + # + # - The arrangement assumed that a client wishing to restore a SturdyRef would know exactly what + # machine to connect to and would be able to immediately restore a SturdyRef on connection. + # However, in practice, the ability to restore SturdyRefs is itself a capability that may + # require going through an authentication process to obtain. Thus, it makes more sense to + # define a "restorer service" as a full Cap'n Proto interface. If this restorer interface is + # offered as the vat's bootstrap interface, then this is equivalent to the old arrangement. + # + # - Overloading "Restore" for the purpose of obtaining well-known capabilities encouraged the + # practice of exporting singleton services with string names. If singleton services are desired, + # it is better to have one main interface that has methods that can be used to obtain each + # service, in order to get all the usual benefits of schemas and type checking. + # + # - Overloading "Restore" also had a security problem: Often, "main" or "well-known" + # capabilities exported by a vat are in fact not public: they are intended to be accessed only + # by clients who are capable of forming a connection to the vat. This can lead to trouble if + # the client itself has other clients and wishes to foward some `Restore` requests from those + # external clients -- it has to be very careful not to allow through `Restore` requests + # addressing the default capability. + # + # For example, consider the case of a sandboxed Sandstorm application and its supervisor. The + # application exports a default capability to its supervisor that provides access to + # functionality that only the supervisor is supposed to access. Meanwhile, though, applications + # may publish other capabilities that may be persistent, in which case the application needs + # to field `Restore` requests that could come from anywhere. These requests of course have to + # pass through the supervisor, as all communications with the outside world must. But, the + # supervisor has to be careful not to honor an external request addressing the application's + # default capability, since this capability is privileged. Unfortunately, the default + # capability cannot be given an unguessable name, because then the supervisor itself would not + # be able to address it! + # + # As of Cap'n Proto 0.5, `Restore` has been renamed to `Bootstrap` and is no longer planned for + # use in restoring SturdyRefs. + # + # Note that 0.4 also defined a message type called `Delete` that, like `Restore`, addressed a + # SturdyRef, but indicated that the client would not restore the ref again in the future. This + # operation was never implemented, so it was removed entirely. If a "delete" operation is desired, + # it should exist as a method on the same interface that handles restoring SturdyRefs. However, + # the utility of such an operation is questionable. You wouldn't be able to rely on it for + # garbage collection since a client could always disappear permanently without remembering to + # delete all its SturdyRefs, thus leaving them dangling forever. Therefore, it is advisable to + # design systems such that SturdyRefs never represent "owned" pointers. + # + # For example, say a SturdyRef points to an image file hosted on some server. That image file + # should also live inside a collection (a gallery, perhaps) hosted on the same server, owned by + # a user who can delete the image at any time. If the user deletes the image, the SturdyRef + # stops working. On the other hand, if the SturdyRef is discarded, this has no effect on the + # existence of the image in its collection. +} + +struct Call { + # **(level 0)** + # + # Message type initiating a method call on a capability. + + questionId @0 :QuestionId; + # A number, chosen by the caller, that identifies this call in future messages. This number + # must be different from all other calls originating from the same end of the connection (but + # may overlap with question IDs originating from the opposite end). A fine strategy is to use + # sequential question IDs, but the recipient should not assume this. + # + # A question ID can be reused once both: + # - A matching Return has been received from the callee. + # - A matching Finish has been sent from the caller. + + target @1 :MessageTarget; + # The object that should receive this call. + + interfaceId @2 :UInt64; + # The type ID of the interface being called. Each capability may implement multiple interfaces. + + methodId @3 :UInt16; + # The ordinal number of the method to call within the requested interface. + + allowThirdPartyTailCall @8 :Bool = false; + # Indicates whether or not the receiver is allowed to send a `Return` containing + # `acceptFromThirdParty`. Level 3 implementations should set this true. Otherwise, the callee + # will have to proxy the return in the case of a tail call to a third-party vat. + + params @4 :Payload; + # The call parameters. `params.content` is a struct whose fields correspond to the parameters of + # the method. + + sendResultsTo :union { + # Where should the return message be sent? + + caller @5 :Void; + # Send the return message back to the caller (the usual). + + yourself @6 :Void; + # **(level 1)** + # + # Don't actually return the results to the sender. Instead, hold on to them and await + # instructions from the sender regarding what to do with them. In particular, the sender + # may subsequently send a `Return` for some other call (which the receiver had previously made + # to the sender) with `takeFromOtherQuestion` set. The results from this call are then used + # as the results of the other call. + # + # When `yourself` is used, the receiver must still send a `Return` for the call, but sets the + # field `resultsSentElsewhere` in that `Return` rather than including the results. + # + # This feature can be used to implement tail calls in which a call from Vat A to Vat B ends up + # returning the result of a call from Vat B back to Vat A. + # + # In particular, the most common use case for this feature is when Vat A makes a call to a + # promise in Vat B, and then that promise ends up resolving to a capability back in Vat A. + # Vat B must forward all the queued calls on that promise back to Vat A, but can set `yourself` + # in the calls so that the results need not pass back through Vat B. + # + # For example: + # - Alice, in Vat A, calls foo() on Bob in Vat B. + # - Alice makes a pipelined call bar() on the promise returned by foo(). + # - Later on, Bob resolves the promise from foo() to point at Carol, who lives in Vat A (next + # to Alice). + # - Vat B dutifully forwards the bar() call to Carol. Let us call this forwarded call bar'(). + # Notice that bar() and bar'() are travelling in opposite directions on the same network + # link. + # - The `Call` for bar'() has `sendResultsTo` set to `yourself`. + # - Vat B sends a `Return` for bar() with `takeFromOtherQuestion` set in place of the results, + # with the value set to the question ID of bar'(). Vat B does not wait for bar'() to return, + # as doing so would introduce unnecessary round trip latency. + # - Vat A receives bar'() and delivers it to Carol. + # - When bar'() returns, Vat A sends a `Return` for bar'() to Vat B, with `resultsSentElsewhere` + # set in place of results. + # - Vat A sends a `Finish` for the bar() call to Vat B. + # - Vat B receives the `Finish` for bar() and sends a `Finish` for bar'(). + + thirdParty @7 :RecipientId; + # **(level 3)** + # + # The call's result should be returned to a different vat. The receiver (the callee) expects + # to receive an `Accept` message from the indicated vat, and should return the call's result + # to it, rather than to the sender of the `Call`. + # + # This operates much like `yourself`, above, except that Carol is in a separate Vat C. `Call` + # messages are sent from Vat A -> Vat B and Vat B -> Vat C. A `Return` message is sent from + # Vat B -> Vat A that contains `acceptFromThirdParty` in place of results. When Vat A sends + # an `Accept` to Vat C, it receives back a `Return` containing the call's actual result. Vat C + # also sends a `Return` to Vat B with `resultsSentElsewhere`. + } +} + +struct Return { + # **(level 0)** + # + # Message type sent from callee to caller indicating that the call has completed. + + answerId @0 :AnswerId; + # Equal to the QuestionId of the corresponding `Call` message. + + releaseParamCaps @1 :Bool = true; + # If true, all capabilities that were in the params should be considered released. The sender + # must not send separate `Release` messages for them. Level 0 implementations in particular + # should always set this true. This defaults true because if level 0 implementations forget to + # set it they'll never notice (just silently leak caps), but if level >=1 implementations forget + # to set it to false they'll quickly get errors. + # + # The receiver should act as if the sender had sent a release message with count=1 for each + # CapDescriptor in the original Call message. + + union { + results @2 :Payload; + # The result. + # + # For regular method calls, `results.content` points to the result struct. + # + # For a `Return` in response to an `Accept` or `Bootstrap`, `results` contains a single + # capability (rather than a struct), and `results.content` is just a capability pointer with + # index 0. A `Finish` is still required in this case. + + exception @3 :Exception; + # Indicates that the call failed and explains why. + + canceled @4 :Void; + # Indicates that the call was canceled due to the caller sending a Finish message + # before the call had completed. + + resultsSentElsewhere @5 :Void; + # This is set when returning from a `Call` that had `sendResultsTo` set to something other + # than `caller`. + # + # It doesn't matter too much when this is sent, as the receiver doesn't need to do anything + # with it, but the C++ implementation appears to wait for the call to finish before sending + # this. + + takeFromOtherQuestion @6 :QuestionId; + # The sender has also sent (before this message) a `Call` with the given question ID and with + # `sendResultsTo.yourself` set, and the results of that other call should be used as the + # results here. `takeFromOtherQuestion` can only used once per question. + + acceptFromThirdParty @7 :ThirdPartyCapId; + # **(level 3)** + # + # The caller should contact a third-party vat to pick up the results. An `Accept` message + # sent to the vat will return the result. This pairs with `Call.sendResultsTo.thirdParty`. + # It should only be used if the corresponding `Call` had `allowThirdPartyTailCall` set. + } +} + +struct Finish { + # **(level 0)** + # + # Message type sent from the caller to the callee to indicate: + # 1) The questionId will no longer be used in any messages sent by the callee (no further + # pipelined requests). + # 2) If the call has not returned yet, the caller no longer cares about the result. If nothing + # else cares about the result either (e.g. there are no other outstanding calls pipelined on + # the result of this one) then the callee may wish to immediately cancel the operation and + # send back a Return message with "canceled" set. However, implementations are not required + # to support premature cancellation -- instead, the implementation may wait until the call + # actually completes and send a normal `Return` message. + # + # TODO(someday): Should we separate (1) and implicitly releasing result capabilities? It would be + # possible and useful to notify the server that it doesn't need to keep around the response to + # service pipeline requests even though the caller still wants to receive it / hasn't yet + # finished processing it. It could also be useful to notify the server that it need not marshal + # the results because the caller doesn't want them anyway, even if the caller is still sending + # pipelined calls, although this seems less useful (just saving some bytes on the wire). + + questionId @0 :QuestionId; + # ID of the call whose result is to be released. + + releaseResultCaps @1 :Bool = true; + # If true, all capabilities that were in the results should be considered released. The sender + # must not send separate `Release` messages for them. Level 0 implementations in particular + # should always set this true. This defaults true because if level 0 implementations forget to + # set it they'll never notice (just silently leak caps), but if level >=1 implementations forget + # set it false they'll quickly get errors. +} + +# Level 1 message types ---------------------------------------------- + +struct Resolve { + # **(level 1)** + # + # Message type sent to indicate that a previously-sent promise has now been resolved to some other + # object (possibly another promise) -- or broken, or canceled. + # + # Keep in mind that it's possible for a `Resolve` to be sent to a level 0 implementation that + # doesn't implement it. For example, a method call or return might contain a capability in the + # payload. Normally this is fine even if the receiver is level 0, because they will implicitly + # release all such capabilities on return / finish. But if the cap happens to be a promise, then + # a follow-up `Resolve` may be sent regardless of this release. The level 0 receiver will reply + # with an `unimplemented` message, and the sender (of the `Resolve`) can respond to this as if the + # receiver had immediately released any capability to which the promise resolved. + # + # When implementing promise resolution, it's important to understand how embargos work and the + # tricky case of the Tribble 4-way race condition. See the comments for the Disembargo message, + # below. + + promiseId @0 :ExportId; + # The ID of the promise to be resolved. + # + # Unlike all other instances of `ExportId` sent from the exporter, the `Resolve` message does + # _not_ increase the reference count of `promiseId`. In fact, it is expected that the receiver + # will release the export soon after receiving `Resolve`, and the sender will not send this + # `ExportId` again until it has been released and recycled. + # + # When an export ID sent over the wire (e.g. in a `CapDescriptor`) is indicated to be a promise, + # this indicates that the sender will follow up at some point with a `Resolve` message. If the + # same `promiseId` is sent again before `Resolve`, still only one `Resolve` is sent. If the + # same ID is sent again later _after_ a `Resolve`, it can only be because the export's + # reference count hit zero in the meantime and the ID was re-assigned to a new export, therefore + # this later promise does _not_ correspond to the earlier `Resolve`. + # + # If a promise ID's reference count reaches zero before a `Resolve` is sent, the `Resolve` + # message may or may not still be sent (the `Resolve` may have already been in-flight when + # `Release` was sent, but if the `Release` is received before `Resolve` then there is no longer + # any reason to send a `Resolve`). Thus a `Resolve` may be received for a promise of which + # the receiver has no knowledge, because it already released it earlier. In this case, the + # receiver should simply release the capability to which the promise resolved. + + union { + cap @1 :CapDescriptor; + # The object to which the promise resolved. + # + # The sender promises that from this point forth, until `promiseId` is released, it shall + # simply forward all messages to the capability designated by `cap`. This is true even if + # `cap` itself happens to desigate another promise, and that other promise later resolves -- + # messages sent to `promiseId` shall still go to that other promise, not to its resolution. + # This is important in the case that the receiver of the `Resolve` ends up sending a + # `Disembargo` message towards `promiseId` in order to control message ordering -- that + # `Disembargo` really needs to reflect back to exactly the object designated by `cap` even + # if that object is itself a promise. + + exception @2 :Exception; + # Indicates that the promise was broken. + } +} + +struct Release { + # **(level 1)** + # + # Message type sent to indicate that the sender is done with the given capability and the receiver + # can free resources allocated to it. + + id @0 :ImportId; + # What to release. + + referenceCount @1 :UInt32; + # The amount by which to decrement the reference count. The export is only actually released + # when the reference count reaches zero. +} + +struct Disembargo { + # **(level 1)** + # + # Message sent to indicate that an embargo on a recently-resolved promise may now be lifted. + # + # Embargos are used to enforce E-order in the presence of promise resolution. That is, if an + # application makes two calls foo() and bar() on the same capability reference, in that order, + # the calls should be delivered in the order in which they were made. But if foo() is called + # on a promise, and that promise happens to resolve before bar() is called, then the two calls + # may travel different paths over the network, and thus could arrive in the wrong order. In + # this case, the call to `bar()` must be embargoed, and a `Disembargo` message must be sent along + # the same path as `foo()` to ensure that the `Disembargo` arrives after `foo()`. Once the + # `Disembargo` arrives, `bar()` can then be delivered. + # + # There are two particular cases where embargos are important. Consider object Alice, in Vat A, + # who holds a promise P, pointing towards Vat B, that eventually resolves to Carol. The two + # cases are: + # - Carol lives in Vat A, i.e. next to Alice. In this case, Vat A needs to send a `Disembargo` + # message that echos through Vat B and back, to ensure that all pipelined calls on the promise + # have been delivered. + # - Carol lives in a different Vat C. When the promise resolves, a three-party handoff occurs + # (see `Provide` and `Accept`, which constitute level 3 of the protocol). In this case, we + # piggyback on the state that has already been set up to handle the handoff: the `Accept` + # message (from Vat A to Vat C) is embargoed, as are all pipelined messages sent to it, while + # a `Disembargo` message is sent from Vat A through Vat B to Vat C. See `Accept.embargo` for + # an example. + # + # Note that in the case where Carol actually lives in Vat B (i.e., the same vat that the promise + # already pointed at), no embargo is needed, because the pipelined calls are delivered over the + # same path as the later direct calls. + # + # Keep in mind that promise resolution happens both in the form of Resolve messages as well as + # Return messages (which resolve PromisedAnswers). Embargos apply in both cases. + # + # An alternative strategy for enforcing E-order over promise resolution could be for Vat A to + # implement the embargo internally. When Vat A is notified of promise resolution, it could + # send a dummy no-op call to promise P and wait for it to complete. Until that call completes, + # all calls to the capability are queued locally. This strategy works, but is pessimistic: + # in the three-party case, it requires an A -> B -> C -> B -> A round trip before calls can start + # being delivered directly to from Vat A to Vat C. The `Disembargo` message allows latency to be + # reduced. (In the two-party loopback case, the `Disembargo` message is just a more explicit way + # of accomplishing the same thing as a no-op call, but isn't any faster.) + # + # *The Tribble 4-way Race Condition* + # + # Any implementation of promise resolution and embargos must be aware of what we call the + # "Tribble 4-way race condition", after Dean Tribble, who explained the problem in a lively + # Friam meeting. + # + # Embargos are designed to work in the case where a two-hop path is being shortened to one hop. + # But sometimes there are more hops. Imagine that Alice has a reference to a remote promise P1 + # that eventually resolves to _another_ remote promise P2 (in a third vat), which _at the same + # time_ happens to resolve to Bob (in a fourth vat). In this case, we're shortening from a 3-hop + # path (with four parties) to a 1-hop path (Alice -> Bob). + # + # Extending the embargo/disembargo protocol to be able to shorted multiple hops at once seems + # difficult. Instead, we make a rule that prevents this case from coming up: + # + # One a promise P has been resolved to a remote object reference R, then all further messages + # received addressed to P will be forwarded strictly to R. Even if it turns out later that R is + # itself a promise, and has resolved to some other object Q, messages sent to P will still be + # forwarded to R, not directly to Q (R will of course further forward the messages to Q). + # + # This rule does not cause a significant performance burden because once P has resolved to R, it + # is expected that people sending messages to P will shortly start sending them to R instead and + # drop P. P is at end-of-life anyway, so it doesn't matter if it ignores chances to further + # optimize its path. + + target @0 :MessageTarget; + # What is to be disembargoed. + + using EmbargoId = UInt32; + # Used in `senderLoopback` and `receiverLoopback`, below. + + context :union { + senderLoopback @1 :EmbargoId; + # The sender is requesting a disembargo on a promise that is known to resolve back to a + # capability hosted by the sender. As soon as the receiver has echoed back all pipelined calls + # on this promise, it will deliver the Disembargo back to the sender with `receiverLoopback` + # set to the same value as `senderLoopback`. This value is chosen by the sender, and since + # it is also consumed be the sender, the sender can use whatever strategy it wants to make sure + # the value is unambiguous. + # + # The receiver must verify that the target capability actually resolves back to the sender's + # vat. Otherwise, the sender has committed a protocol error and should be disconnected. + + receiverLoopback @2 :EmbargoId; + # The receiver previously sent a `senderLoopback` Disembargo towards a promise resolving to + # this capability, and that Disembargo is now being echoed back. + + accept @3 :Void; + # **(level 3)** + # + # The sender is requesting a disembargo on a promise that is known to resolve to a third-party + # capability that the sender is currently in the process of accepting (using `Accept`). + # The receiver of this `Disembargo` has an outstanding `Provide` on said capability. The + # receiver should now send a `Disembargo` with `provide` set to the question ID of that + # `Provide` message. + # + # See `Accept.embargo` for an example. + + provide @4 :QuestionId; + # **(level 3)** + # + # The sender is requesting a disembargo on a capability currently being provided to a third + # party. The question ID identifies the `Provide` message previously sent by the sender to + # this capability. On receipt, the receiver (the capability host) shall release the embargo + # on the `Accept` message that it has received from the third party. See `Accept.embargo` for + # an example. + } +} + +# Level 2 message types ---------------------------------------------- + +# See persistent.capnp. + +# Level 3 message types ---------------------------------------------- + +struct Provide { + # **(level 3)** + # + # Message type sent to indicate that the sender wishes to make a particular capability implemented + # by the receiver available to a third party for direct access (without the need for the third + # party to proxy through the sender). + # + # (In CapTP, `Provide` and `Accept` are methods of the global `NonceLocator` object exported by + # every vat. In Cap'n Proto, we bake this into the core protocol.) + + questionId @0 :QuestionId; + # Question ID to be held open until the recipient has received the capability. A result will be + # returned once the third party has successfully received the capability. The sender must at some + # point send a `Finish` message as with any other call, and that message can be used to cancel the + # whole operation. + + target @1 :MessageTarget; + # What is to be provided to the third party. + + recipient @2 :RecipientId; + # Identity of the third party that is expected to pick up the capability. +} + +struct Accept { + # **(level 3)** + # + # Message type sent to pick up a capability hosted by the receiving vat and provided by a third + # party. The third party previously designated the capability using `Provide`. + # + # This message is also used to pick up a redirected return -- see `Return.acceptFromThirdParty`. + + questionId @0 :QuestionId; + # A new question ID identifying this accept message, which will eventually receive a Return + # message containing the provided capability (or the call result in the case of a redirected + # return). + + provision @1 :ProvisionId; + # Identifies the provided object to be picked up. + + embargo @2 :Bool; + # If true, this accept shall be temporarily embargoed. The resulting `Return` will not be sent, + # and any pipelined calls will not be delivered, until the embargo is released. The receiver + # (the capability host) will expect the provider (the vat that sent the `Provide` message) to + # eventually send a `Disembargo` message with the field `context.provide` set to the question ID + # of the original `Provide` message. At that point, the embargo is released and the queued + # messages are delivered. + # + # For example: + # - Alice, in Vat A, holds a promise P, which currently points toward Vat B. + # - Alice calls foo() on P. The `Call` message is sent to Vat B. + # - The promise P in Vat B ends up resolving to Carol, in Vat C. + # - Vat B sends a `Provide` message to Vat C, identifying Vat A as the recipient. + # - Vat B sends a `Resolve` message to Vat A, indicating that the promise has resolved to a + # `ThirdPartyCapId` identifying Carol in Vat C. + # - Vat A sends an `Accept` message to Vat C to pick up the capability. Since Vat A knows that + # it has an outstanding call to the promise, it sets `embargo` to `true` in the `Accept` + # message. + # - Vat A sends a `Disembargo` message to Vat B on promise P, with `context.accept` set. + # - Alice makes a call bar() to promise P, which is now pointing towards Vat C. Alice doesn't + # know anything about the mechanics of promise resolution happening under the hood, but she + # expects that bar() will be delivered after foo() because that is the order in which she + # initiated the calls. + # - Vat A sends the bar() call to Vat C, as a pipelined call on the result of the `Accept` (which + # hasn't returned yet, due to the embargo). Since calls to the newly-accepted capability + # are embargoed, Vat C does not deliver the call yet. + # - At some point, Vat B forwards the foo() call from the beginning of this example on to Vat C. + # - Vat B forwards the `Disembargo` from Vat A on to vat C. It sets `context.provide` to the + # question ID of the `Provide` message it had sent previously. + # - Vat C receives foo() before `Disembargo`, thus allowing it to correctly deliver foo() + # before delivering bar(). + # - Vat C receives `Disembargo` from Vat B. It can now send a `Return` for the `Accept` from + # Vat A, as well as deliver bar(). +} + +# Level 4 message types ---------------------------------------------- + +struct Join { + # **(level 4)** + # + # Message type sent to implement E.join(), which, given a number of capabilities that are + # expected to be equivalent, finds the underlying object upon which they all agree and forms a + # direct connection to it, skipping any proxies that may have been constructed by other vats + # while transmitting the capability. See: + # http://erights.org/elib/equality/index.html + # + # Note that this should only serve to bypass fully-transparent proxies -- proxies that were + # created merely for convenience, without any intention of hiding the underlying object. + # + # For example, say Bob holds two capabilities hosted by Alice and Carol, but he expects that both + # are simply proxies for a capability hosted elsewhere. He then issues a join request, which + # operates as follows: + # - Bob issues Join requests on both Alice and Carol. Each request contains a different piece + # of the JoinKey. + # - Alice is proxying a capability hosted by Dana, so forwards the request to Dana's cap. + # - Dana receives the first request and sees that the JoinKeyPart is one of two. She notes that + # she doesn't have the other part yet, so she records the request and responds with a + # JoinResult. + # - Alice relays the JoinAswer back to Bob. + # - Carol is also proxying a capability from Dana, and so forwards her Join request to Dana as + # well. + # - Dana receives Carol's request and notes that she now has both parts of a JoinKey. She + # combines them in order to form information needed to form a secure connection to Bob. She + # also responds with another JoinResult. + # - Bob receives the responses from Alice and Carol. He uses the returned JoinResults to + # determine how to connect to Dana and attempts to form the connection. Since Bob and Dana now + # agree on a secret key that neither Alice nor Carol ever saw, this connection can be made + # securely even if Alice or Carol is conspiring against the other. (If Alice and Carol are + # conspiring _together_, they can obviously reproduce the key, but this doesn't matter because + # the whole point of the join is to verify that Alice and Carol agree on what capability they + # are proxying.) + # + # If the two capabilities aren't actually proxies of the same object, then the join requests + # will come back with conflicting `hostId`s and the join will fail before attempting to form any + # connection. + + questionId @0 :QuestionId; + # Question ID used to respond to this Join. (Note that this ID only identifies one part of the + # request for one hop; each part has a different ID and relayed copies of the request have + # (probably) different IDs still.) + # + # The receiver will reply with a `Return` whose `results` is a JoinResult. This `JoinResult` + # is relayed from the joined object's host, possibly with transformation applied as needed + # by the network. + # + # Like any return, the result must be released using a `Finish`. However, this release + # should not occur until the joiner has either successfully connected to the joined object. + # Vats relaying a `Join` message similarly must not release the result they receive until the + # return they relayed back towards the joiner has itself been released. This allows the + # joined object's host to detect when the Join operation is canceled before completing -- if + # it receives a `Finish` for one of the join results before the joiner successfully + # connects. It can then free any resources it had allocated as part of the join. + + target @1 :MessageTarget; + # The capability to join. + + keyPart @2 :JoinKeyPart; + # A part of the join key. These combine to form the complete join key, which is used to establish + # a direct connection. + + # TODO(before implementing): Change this so that multiple parts can be sent in a single Join + # message, so that if multiple join parts are going to cross the same connection they can be sent + # together, so that the receive can potentially optimize its handling of them. In the case where + # all parts are bundled together, should the recipient be expected to simply return a cap, so + # that the caller can immediately start pipelining to it? +} + +# ======================================================================================== +# Common structures used in messages + +struct MessageTarget { + # The target of a `Call` or other messages that target a capability. + + union { + importedCap @0 :ImportId; + # This message is to a capability or promise previously imported by the caller (exported by + # the receiver). + + promisedAnswer @1 :PromisedAnswer; + # This message is to a capability that is expected to be returned by another call that has not + # yet been completed. + # + # At level 0, this is supported only for addressing the result of a previous `Bootstrap`, so + # that initial startup doesn't require a round trip. + } +} + +struct Payload { + # Represents some data structure that might contain capabilities. + + content @0 :AnyPointer; + # Some Cap'n Proto data structure. Capability pointers embedded in this structure index into + # `capTable`. + + capTable @1 :List(CapDescriptor); + # Descriptors corresponding to the cap pointers in `content`. +} + +struct CapDescriptor { + # **(level 1)** + # + # When an application-defined type contains an interface pointer, that pointer contains an index + # into the message's capability table -- i.e. the `capTable` part of the `Payload`. Each + # capability in the table is represented as a `CapDescriptor`. The runtime API should not reveal + # the CapDescriptor directly to the application, but should instead wrap it in some kind of + # callable object with methods corresponding to the interface that the capability implements. + # + # Keep in mind that `ExportIds` in a `CapDescriptor` are subject to reference counting. See the + # description of `ExportId`. + # + # Note that it is currently not possible to include a broken capability in the CapDescriptor + # table. Instead, create a new export (`senderPromise`) for each broken capability and then + # immediately follow the payload-bearing Call or Return message with one Resolve message for each + # broken capability, resolving it to an exception. + + union { + none @0 :Void; + # There is no capability here. This `CapDescriptor` should not appear in the payload content. + # A `none` CapDescriptor can be generated when an application inserts a capability into a + # message and then later changes its mind and removes it -- rewriting all of the other + # capability pointers may be hard, so instead a tombstone is left, similar to the way a removed + # struct or list instance is zeroed out of the message but the space is not reclaimed. + # Hopefully this is unusual. + + senderHosted @1 :ExportId; + # The ID of a capability in the sender's export table (receiver's import table). It may be a + # newly allocated table entry, or an existing entry (increments the reference count). + + senderPromise @2 :ExportId; + # A promise that the sender will resolve later. The sender will send exactly one Resolve + # message at a future point in time to replace this promise. Note that even if the same + # `senderPromise` is received multiple times, only one `Resolve` is sent to cover all of + # them. If `senderPromise` is released before the `Resolve` is sent, the sender (of this + # `CapDescriptor`) may choose not to send the `Resolve` at all. + + receiverHosted @3 :ImportId; + # A capability (or promise) previously exported by the receiver (imported by the sender). + + receiverAnswer @4 :PromisedAnswer; + # A capability expected to be returned in the results of a currently-outstanding call posed + # by the sender. + + thirdPartyHosted @5 :ThirdPartyCapDescriptor; + # **(level 3)** + # + # A capability that lives in neither the sender's nor the receiver's vat. The sender needs + # to form a direct connection to a third party to pick up the capability. + # + # Level 1 and 2 implementations that receive a `thirdPartyHosted` may simply send calls to its + # `vine` instead. + } +} + +struct PromisedAnswer { + # **(mostly level 1)** + # + # Specifies how to derive a promise from an unanswered question, by specifying the path of fields + # to follow from the root of the eventual result struct to get to the desired capability. Used + # to address method calls to a not-yet-returned capability or to pass such a capability as an + # input to some other method call. + # + # Level 0 implementations must support `PromisedAnswer` only for the case where the answer is + # to a `Bootstrap` message. In this case, `path` is always empty since `Bootstrap` always returns + # a raw capability. + + questionId @0 :QuestionId; + # ID of the question (in the sender's question table / receiver's answer table) whose answer is + # expected to contain the capability. + + transform @1 :List(Op); + # Operations / transformations to apply to the result in order to get the capability actually + # being addressed. E.g. if the result is a struct and you want to call a method on a capability + # pointed to by a field of the struct, you need a `getPointerField` op. + + struct Op { + union { + noop @0 :Void; + # Does nothing. This member is mostly defined so that we can make `Op` a union even + # though (as of this writing) only one real operation is defined. + + getPointerField @1 :UInt16; + # Get a pointer field within a struct. The number is an index into the pointer section, NOT + # a field ordinal, so that the receiver does not need to understand the schema. + + # TODO(someday): We could add: + # - For lists, the ability to address every member of the list, or a slice of the list, the + # result of which would be another list. This is useful for implementing the equivalent of + # a SQL table join (not to be confused with the `Join` message type). + # - Maybe some ability to test a union. + # - Probably not a good idea: the ability to specify an arbitrary script to run on the + # result. We could define a little stack-based language where `Op` specifies one + # "instruction" or transformation to apply. Although this is not a good idea + # (over-engineered), any narrower additions to `Op` should be designed as if this + # were the eventual goal. + } + } +} + +struct ThirdPartyCapDescriptor { + # **(level 3)** + # + # Identifies a capability in a third-party vat that the sender wants the receiver to pick up. + + id @0 :ThirdPartyCapId; + # Identifies the third-party host and the specific capability to accept from it. + + vineId @1 :ExportId; + # A proxy for the third-party object exported by the sender. In CapTP terminology this is called + # a "vine", because it is an indirect reference to the third-party object that snakes through the + # sender vat. This serves two purposes: + # + # * Level 1 and 2 implementations that don't understand how to connect to a third party may + # simply send calls to the vine. Such calls will be forwarded to the third-party by the + # sender. + # + # * Level 3 implementations must release the vine only once they have successfully picked up the + # object from the third party. This ensures that the capability is not released by the sender + # prematurely. + # + # The sender will close the `Provide` request that it has sent to the third party as soon as + # it receives either a `Call` or a `Release` message directed at the vine. +} + +struct Exception { + # **(level 0)** + # + # Describes an arbitrary error that prevented an operation (e.g. a call) from completing. + # + # Cap'n Proto exceptions always indicate that something went wrong. In other words, in a fantasy + # world where everything always works as expected, no exceptions would ever be thrown. Clients + # should only ever catch exceptions as a means to implement fault-tolerance, where "fault" can + # mean: + # - Bugs. + # - Invalid input. + # - Configuration errors. + # - Network problems. + # - Insufficient resources. + # - Version skew (unimplemented functionality). + # - Other logistical problems. + # + # Exceptions should NOT be used to flag application-specific conditions that a client is expected + # to handle in an application-specific way. Put another way, in the Cap'n Proto world, + # "checked exceptions" (where an interface explicitly defines the exceptions it throws and + # clients are forced by the type system to handle those exceptions) do NOT make sense. + + reason @0 :Text; + # Human-readable failure description. + + type @3 :Type; + # The type of the error. The purpose of this enum is not to describe the error itself, but + # rather to describe how the client might want to respond to the error. + + enum Type { + failed @0; + # A generic problem occurred, and it is believed that if the operation were repeated without + # any change in the state of the world, the problem would occur again. + # + # A client might respond to this error by logging it for investigation by the developer and/or + # displaying it to the user. + + overloaded @1; + # The request was rejected due to a temporary lack of resources. + # + # Examples include: + # - There's not enough CPU time to keep up with incoming requests, so some are rejected. + # - The server ran out of RAM or disk space during the request. + # - The operation timed out (took significantly longer than it should have). + # + # A client might respond to this error by scheduling to retry the operation much later. The + # client should NOT retry again immediately since this would likely exacerbate the problem. + + disconnected @2; + # The method failed because a connection to some necessary capability was lost. + # + # Examples include: + # - The client introduced the server to a third-party capability, the connection to that third + # party was subsequently lost, and then the client requested that the server use the dead + # capability for something. + # - The client previously requested that the server obtain a capability from some third party. + # The server returned a capability to an object wrapping the third-party capability. Later, + # the server's connection to the third party was lost. + # - The capability has been revoked. Revocation does not necessarily mean that the client is + # no longer authorized to use the capability; it is often used simply as a way to force the + # client to repeat the setup process, perhaps to efficiently move them to a new back-end or + # get them to recognize some other change that has occurred. + # + # A client should normally respond to this error by releasing all capabilities it is currently + # holding related to the one it called and then re-creating them by restoring SturdyRefs and/or + # repeating the method calls used to create them originally. In other words, disconnect and + # start over. This should in turn cause the server to obtain a new copy of the capability that + # it lost, thus making everything work. + # + # If the client receives another `disconnencted` error in the process of rebuilding the + # capability and retrying the call, it should treat this as an `overloaded` error: the network + # is currently unreliable, possibly due to load or other temporary issues. + + unimplemented @3; + # The server doesn't implement the requested method. If there is some other method that the + # client could call (perhaps an older and/or slower interface), it should try that instead. + # Otherwise, this should be treated like `failed`. + } + + obsoleteIsCallersFault @1 :Bool; + # OBSOLETE. Ignore. + + obsoleteDurability @2 :UInt16; + # OBSOLETE. See `type` instead. +} + +# ======================================================================================== +# Network-specific Parameters +# +# Some parts of the Cap'n Proto RPC protocol are not specified here because different vat networks +# may wish to use different approaches to solving them. For example, on the public internet, you +# may want to authenticate vats using public-key cryptography, but on a local intranet with trusted +# infrastructure, you may be happy to authenticate based on network address only, or some other +# lightweight mechanism. +# +# To accommodate this, we specify several "parameter" types. Each type is defined here as an +# alias for `AnyPointer`, but a specific network will want to define a specific set of types to use. +# All vats in a vat network must agree on these parameters in order to be able to communicate. +# Inter-network communication can be accomplished through "gateways" that perform translation +# between the primitives used on each network; these gateways may need to be deeply stateful, +# depending on the translations they perform. +# +# For interaction over the global internet between parties with no other prior arrangement, a +# particular set of bindings for these types is defined elsewhere. (TODO(someday): Specify where +# these common definitions live.) +# +# Another common network type is the two-party network, in which one of the parties typically +# interacts with the outside world entirely through the other party. In such a connection between +# Alice and Bob, all objects that exist on Bob's other networks appear to Alice as if they were +# hosted by Bob himself, and similarly all objects on Alice's network (if she even has one) appear +# to Bob as if they were hosted by Alice. This network type is interesting because from the point +# of view of a simple application that communicates with only one other party via the two-party +# protocol, there are no three-party interactions at all, and joins are unusually simple to +# implement, so implementing at level 4 is barely more complicated than implementing at level 1. +# Moreover, if you pair an app implementing the two-party network with a container that implements +# some other network, the app can then participate on the container's network just as if it +# implemented that network directly. The types used by the two-party network are defined in +# `rpc-twoparty.capnp`. +# +# The things that we need to parameterize are: +# - How to store capabilities long-term without holding a connection open (mostly level 2). +# - How to authenticate vats in three-party introductions (level 3). +# - How to implement `Join` (level 4). +# +# Persistent references +# --------------------- +# +# **(mostly level 2)** +# +# We want to allow some capabilities to be stored long-term, even if a connection is lost and later +# recreated. ExportId is a short-term identifier that is specific to a connection, so it doesn't +# help here. We need a way to specify long-term identifiers, as well as a strategy for +# reconnecting to a referenced capability later. +# +# Three-party interactions +# ------------------------ +# +# **(level 3)** +# +# In cases where more than two vats are interacting, we have situations where VatA holds a +# capability hosted by VatB and wants to send that capability to VatC. This can be accomplished +# by VatA proxying requests on the new capability, but doing so has two big problems: +# - It's inefficient, requiring an extra network hop. +# - If VatC receives another capability to the same object from VatD, it is difficult for VatC to +# detect that the two capabilities are really the same and to implement the E "join" operation, +# which is necessary for certain four-or-more-party interactions, such as the escrow pattern. +# See: http://www.erights.org/elib/equality/grant-matcher/index.html +# +# Instead, we want a way for VatC to form a direct, authenticated connection to VatB. +# +# Join +# ---- +# +# **(level 4)** +# +# The `Join` message type and corresponding operation arranges for a direct connection to be formed +# between the joiner and the host of the joined object, and this connection must be authenticated. +# Thus, the details are network-dependent. + +using SturdyRef = AnyPointer; +# **(level 2)** +# +# Identifies a persisted capability that can be restored in the future. How exactly a SturdyRef +# is restored to a live object is specified along with the SturdyRef definition (i.e. not by +# rpc.capnp). +# +# Generally a SturdyRef needs to specify three things: +# - How to reach the vat that can restore the ref (e.g. a hostname or IP address). +# - How to authenticate the vat after connecting (e.g. a public key fingerprint). +# - The identity of a specific object hosted by the vat. Generally, this is an opaque pointer whose +# format is defined by the specific vat -- the client has no need to inspect the object ID. +# It is important that the objec ID be unguessable if the object is not public (and objects +# should almost never be public). +# +# The above are only suggestions. Some networks might work differently. For example, a private +# network might employ a special restorer service whose sole purpose is to restore SturdyRefs. +# In this case, the entire contents of SturdyRef might be opaque, because they are intended only +# to be forwarded to the restorer service. + +using ProvisionId = AnyPointer; +# **(level 3)** +# +# The information that must be sent in an `Accept` message to identify the object being accepted. +# +# In a network where each vat has a public/private key pair, this could simply be the public key +# fingerprint of the provider vat along with a nonce matching the one in the `RecipientId` used +# in the `Provide` message sent from that provider. + +using RecipientId = AnyPointer; +# **(level 3)** +# +# The information that must be sent in a `Provide` message to identify the recipient of the +# capability. +# +# In a network where each vat has a public/private key pair, this could simply be the public key +# fingerprint of the recipient along with a nonce matching the one in the `ProvisionId`. + +using ThirdPartyCapId = AnyPointer; +# **(level 3)** +# +# The information needed to connect to a third party and accept a capability from it. +# +# In a network where each vat has a public/private key pair, this could be a combination of the +# third party's public key fingerprint, hints on how to connect to the third party (e.g. an IP +# address), and the nonce used in the corresponding `Provide` message's `RecipientId` as sent +# to that third party (used to identify which capability to pick up). + +using JoinKeyPart = AnyPointer; +# **(level 4)** +# +# A piece of a secret key. One piece is sent along each path that is expected to lead to the same +# place. Once the pieces are combined, a direct connection may be formed between the sender and +# the receiver, bypassing any men-in-the-middle along the paths. See the `Join` message type. +# +# The motivation for Joins is discussed under "Supporting Equality" in the "Unibus" protocol +# sketch: http://www.erights.org/elib/distrib/captp/unibus.html +# +# In a network where each vat has a public/private key pair and each vat forms no more than one +# connection to each other vat, Joins will rarely -- perhaps never -- be needed, as objects never +# need to be transparently proxied and references to the same object sent over the same connection +# have the same export ID. Thus, a successful join requires only checking that the two objects +# come from the same connection and have the same ID, and then completes immediately. +# +# However, in networks where two vats may form more than one connection between each other, or +# where proxying of objects occurs, joins are necessary. +# +# Typically, each JoinKeyPart would include a fixed-length data value such that all value parts +# XOR'd together forms a shared secret that can be used to form an encrypted connection between +# the joiner and the joined object's host. Each JoinKeyPart should also include an indication of +# how many parts to expect and a hash of the shared secret (used to match up parts). + +using JoinResult = AnyPointer; +# **(level 4)** +# +# Information returned as the result to a `Join` message, needed by the joiner in order to form a +# direct connection to a joined object. This might simply be the address of the joined object's +# host vat, since the `JoinKey` has already been communicated so the two vats already have a shared +# secret to use to authenticate each other. +# +# The `JoinResult` should also contain information that can be used to detect when the Join +# requests ended up reaching different objects, so that this situation can be detected easily. +# This could be a simple matter of including a sequence number -- if the joiner receives two +# `JoinResult`s with sequence number 0, then they must have come from different objects and the +# whole join is a failure. + +# ======================================================================================== +# Network interface sketch +# +# The interfaces below are meant to be pseudo-code to illustrate how the details of a particular +# vat network might be abstracted away. They are written like Cap'n Proto interfaces, but in +# practice you'd probably define these interfaces manually in the target programming language. A +# Cap'n Proto RPC implementation should be able to use these interfaces without knowing the +# definitions of the various network-specific parameters defined above. + +# interface VatNetwork { +# # Represents a vat network, with the ability to connect to particular vats and receive +# # connections from vats. +# # +# # Note that methods returning a `Connection` may return a pre-existing `Connection`, and the +# # caller is expected to find and share state with existing users of the connection. +# +# # Level 0 features ----------------------------------------------- +# +# connect(vatId :VatId) :Connection; +# # Connect to the given vat. The transport should return a promise that does not +# # resolve until authentication has completed, but allows messages to be pipelined in before +# # that; the transport either queues these messages until authenticated, or sends them encrypted +# # such that only the authentic vat would be able to decrypt them. The latter approach avoids a +# # round trip for authentication. +# +# accept() :Connection; +# # Wait for the next incoming connection and return it. Only connections formed by +# # connect() are returned by this method. +# +# # Level 4 features ----------------------------------------------- +# +# newJoiner(count :UInt32) :NewJoinerResponse; +# # Prepare a new Join operation, which will eventually lead to forming a new direct connection +# # to the host of the joined capability. `count` is the number of capabilities to join. +# +# struct NewJoinerResponse { +# joinKeyParts :List(JoinKeyPart); +# # Key parts to send in Join messages to each capability. +# +# joiner :Joiner; +# # Used to establish the final connection. +# } +# +# interface Joiner { +# addJoinResult(result :JoinResult) :Void; +# # Add a JoinResult received in response to one of the `Join` messages. All `JoinResult`s +# # returned from all paths must be added before trying to connect. +# +# connect() :ConnectionAndProvisionId; +# # Try to form a connection to the joined capability's host, verifying that it has received +# # all of the JoinKeyParts. Once the connection is formed, the caller should send an `Accept` +# # message on it with the specified `ProvisionId` in order to receive the final capability. +# } +# +# acceptConnectionFromJoiner(parts :List(JoinKeyPart), paths :List(VatPath)) +# :ConnectionAndProvisionId; +# # Called on a joined capability's host to receive the connection from the joiner, once all +# # key parts have arrived. The caller should expect to receive an `Accept` message over the +# # connection with the given ProvisionId. +# } +# +# interface Connection { +# # Level 0 features ----------------------------------------------- +# +# send(message :Message) :Void; +# # Send the message. Returns successfully when the message (and all preceding messages) has +# # been acknowledged by the recipient. +# +# receive() :Message; +# # Receive the next message, and acknowledges receipt to the sender. Messages are received in +# # the order in which they are sent. +# +# # Level 3 features ----------------------------------------------- +# +# introduceTo(recipient :Connection) :IntroductionInfo; +# # Call before starting a three-way introduction, assuming a `Provide` message is to be sent on +# # this connection and a `ThirdPartyCapId` is to be sent to `recipient`. +# +# struct IntroductionInfo { +# sendToRecipient :ThirdPartyCapId; +# sendToTarget :RecipientId; +# } +# +# connectToIntroduced(capId :ThirdPartyCapId) :ConnectionAndProvisionId; +# # Given a ThirdPartyCapId received over this connection, connect to the third party. The +# # caller should then send an `Accept` message over the new connection. +# +# acceptIntroducedConnection(recipientId :RecipientId) :Connection; +# # Given a RecipientId received in a `Provide` message on this `Connection`, wait for the +# # recipient to connect, and return the connection formed. Usually, the first message received +# # on the new connection will be an `Accept` message. +# } +# +# struct ConnectionAndProvisionId { +# # **(level 3)** +# +# connection :Connection; +# # Connection on which to issue `Accept` message. +# +# provision :ProvisionId; +# # `ProvisionId` to send in the `Accept` message. +# } diff --git a/CapnpC.CSharp.Generator/CodeGen/CodeGenerator.cs b/CapnpC.CSharp.Generator/CodeGen/CodeGenerator.cs index 3b8f809..a0ec9fc 100644 --- a/CapnpC.CSharp.Generator/CodeGen/CodeGenerator.cs +++ b/CapnpC.CSharp.Generator/CodeGen/CodeGenerator.cs @@ -61,9 +61,18 @@ IEnumerable TransformStruct(TypeDefinition def) { - var topDecl = ClassDeclaration(_names.MakeTypeName(def).Identifier) - .AddModifiers(Public) - .AddBaseListTypes(SimpleBaseType(_names.Type(Nullability.NonNullable))); + var topDecl = ClassDeclaration(_names.MakeTypeName(def).Identifier) + .AddModifiers(_names.TypeVisibilityModifier); + + if (_names.EmitDomainClassesAndInterfaces) + { + topDecl = topDecl.AddBaseListTypes(SimpleBaseType(_names.Type(Nullability.NonNullable))); + } + else + { + topDecl = topDecl.AddModifiers(Static); + } + if (def.GenericParameters.Count > 0) { @@ -80,9 +89,14 @@ topDecl = topDecl.AddMembers(_commonGen.MakeUnionSelectorEnum(def)); } - topDecl = topDecl.AddMembers(_domClassGen.MakeDomainClassMembers(def)); - topDecl = topDecl.AddMembers(_readerGen.MakeReaderStruct(def)); - topDecl = topDecl.AddMembers(_writerGen.MakeWriterStruct(def)); + if (_names.EmitDomainClassesAndInterfaces) + { + topDecl = topDecl.AddMembers(_domClassGen.MakeDomainClassMembers(def)); + } + + topDecl = topDecl.AddMembers( + _readerGen.MakeReaderStruct(def), + _writerGen.MakeWriterStruct(def)); foreach (var nestedGroup in def.NestedGroups) { @@ -99,6 +113,9 @@ IEnumerable TransformInterface(TypeDefinition def) { + if (!_names.EmitDomainClassesAndInterfaces) + yield break; + yield return _interfaceGen.MakeInterface(def); yield return _interfaceGen.MakeProxy(def); yield return _interfaceGen.MakeSkeleton(def); @@ -168,7 +185,7 @@ if (classDecl == null) { classDecl = ClassDeclaration(_names.MakePipeliningSupportExtensionClassName(file).Identifier) - .AddModifiers(Public, Static, Partial); + .AddModifiers(_names.TypeVisibilityModifier, Static, Partial); } classDecl = classDecl.AddMembers(members); @@ -187,6 +204,8 @@ internal string Transform(GenFile file) { _names.NullableEnable = file.NullableEnable ?? _options.NullableEnableDefault; + _names.EmitDomainClassesAndInterfaces = file.EmitDomainClassesAndInterfaces; + _names.TypeVisibility = file.TypeVisibility; NameSyntax topNamespace = GenNames.NamespaceName(file.Namespace) ?? _names.TopNamespace; @@ -211,11 +230,14 @@ ns = ns.AddMembers(Transform(def).ToArray()); } - var psc = TransformForPipeliningSupport(file); - - if (psc != null) + if (_names.EmitDomainClassesAndInterfaces) { - ns = ns.AddMembers(psc); + var psc = TransformForPipeliningSupport(file); + + if (psc != null) + { + ns = ns.AddMembers(psc); + } } var cu = CompilationUnit().AddUsings( diff --git a/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs b/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs index 72de969..549a272 100644 --- a/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs +++ b/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs @@ -51,7 +51,7 @@ namespace CapnpC.CSharp.Generator.CodeGen { var decl = EnumDeclaration(_names.GetCodeIdentifier(def)) .WithAttributeLists(MakeTypeIdAttributeLists(def.Id)) - .AddModifiers(Public) + .AddModifiers(_names.TypeVisibilityModifier) .AddBaseListTypes(SimpleBaseType(_names.Type(Nullability.NonNullable))); foreach (var enumerant in def.Enumerants.OrderBy(e => e.CodeOrder)) diff --git a/CapnpC.CSharp.Generator/CodeGen/GenNames.cs b/CapnpC.CSharp.Generator/CodeGen/GenNames.cs index 95f1889..688f49a 100644 --- a/CapnpC.CSharp.Generator/CodeGen/GenNames.cs +++ b/CapnpC.CSharp.Generator/CodeGen/GenNames.cs @@ -1,4 +1,5 @@ using CapnpC.CSharp.Generator.Model; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System; @@ -74,6 +75,8 @@ namespace CapnpC.CSharp.Generator.CodeGen public string SkeletonClassFormat { get; } public Name AwaitProxy { get; } public bool NullableEnable { get; set; } + public bool EmitDomainClassesAndInterfaces { get; set; } + public SupportedAnnotations.TypeVisibility TypeVisibility { get; set; } public GenNames(GeneratorOptions options) { TopNamespace = new Name(options.TopNamespaceName).IdentifierName; @@ -708,5 +711,23 @@ namespace CapnpC.CSharp.Generator.CodeGen PostfixUnaryExpression(SyntaxKind.SuppressNullableWarningExpression, expression) : expression; } + + public SyntaxToken TypeVisibilityModifier + { + get + { + switch (TypeVisibility) + { + case SupportedAnnotations.TypeVisibility.Public: + return Token(SyntaxKind.PublicKeyword); + + case SupportedAnnotations.TypeVisibility.Internal: + return Token(SyntaxKind.InternalKeyword); + + default: + throw new NotImplementedException(); + } + } + } } } diff --git a/CapnpC.CSharp.Generator/Model/GenFile.cs b/CapnpC.CSharp.Generator/Model/GenFile.cs index 098c8a6..ac0c35d 100644 --- a/CapnpC.CSharp.Generator/Model/GenFile.cs +++ b/CapnpC.CSharp.Generator/Model/GenFile.cs @@ -13,6 +13,8 @@ namespace CapnpC.CSharp.Generator.Model public string[] Namespace { get; set; } public bool? NullableEnable { get; set; } public bool EmitNullableDirective { get; set; } + public bool EmitDomainClassesAndInterfaces { get; set; } + public SupportedAnnotations.TypeVisibility TypeVisibility { get; set; } public IEnumerable NestedTypes { get => this.GetNestedTypes(); } public ICollection NestedDefinitions { get; } = new List(); diff --git a/CapnpC.CSharp.Generator/Model/SchemaModel.cs b/CapnpC.CSharp.Generator/Model/SchemaModel.cs index 8c0e9d6..8213ffd 100644 --- a/CapnpC.CSharp.Generator/Model/SchemaModel.cs +++ b/CapnpC.CSharp.Generator/Model/SchemaModel.cs @@ -94,6 +94,8 @@ namespace CapnpC.CSharp.Generator.Model file.Name = name; file.NullableEnable = GetNullableEnable(node); file.EmitNullableDirective = GetEmitNullableDirective(node) ?? false; + file.EmitDomainClassesAndInterfaces = GetEmitDomainClassesAndInterfaces(node) ?? true; + file.TypeVisibility = GetTypeVisibility(node) ?? TypeVisibility.Public; return ProcessNodePass1(id, name, state) as GenFile; } diff --git a/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs b/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs index 5951f16..cd78387 100644 --- a/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs +++ b/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs @@ -19,9 +19,17 @@ namespace CapnpC.CSharp.Generator.Model public const ulong NullableEnable = 0xeb0d831668c6eda1; public const ulong Name = 0xeb0d831668c6eda2; public const ulong EmitNullableDirective = 0xeb0d831668c6eda3; + public const ulong EmitDomainClassesAndInterfaces = 0xeb0d831668c6eda4; + public const ulong TypeVisibility = 0xeb0d831668c6eda6; } } + public enum TypeVisibility + { + Public = 0, + Internal = 1 + } + public static string[] GetNamespaceAnnotation(Schema.Node.Reader fileNode) { foreach (var annotation in fileNode.Annotations) @@ -98,5 +106,29 @@ namespace CapnpC.CSharp.Generator.Model } return null; } + + public static bool? GetEmitDomainClassesAndInterfaces(Schema.Node.Reader node) + { + foreach (var annotation in node.Annotations) + { + if (annotation.Id == AnnotationIds.Cs.EmitDomainClassesAndInterfaces && annotation.Value.IsBool) + { + return annotation.Value.Bool; + } + } + return null; + } + + public static TypeVisibility? GetTypeVisibility(Schema.Node.Reader node) + { + foreach (var annotation in node.Annotations) + { + if (annotation.Id == AnnotationIds.Cs.TypeVisibility && annotation.Value.IsEnum) + { + return (TypeVisibility)annotation.Value.Enum; + } + } + return null; + } } } diff --git a/include/csharp.capnp b/include/csharp.capnp index 19aabd2..879d533 100644 --- a/include/csharp.capnp +++ b/include/csharp.capnp @@ -1,6 +1,11 @@ @0xeb0d831668c6edab; $namespace("Capnp.Annotations"); +enum TypeVisibility @0xeb0d831668c6eda5 { + public @0; + internal @1; +} + annotation namespace @0xeb0d831668c6eda0 (file) : Text; # C# namespace for code generation @@ -8,7 +13,13 @@ annotation nullableEnable @0xeb0d831668c6eda1 (file) : Bool; # Whether to generate C# nullable reference types annotation emitNullableDirective @0xeb0d831668c6eda3 (file) : Bool; -# Whether to surround the generated with with #nullable enable/disable ... #nullable restore +# Whether to surround the generated code with #nullable enable/disable ... #nullable restore + +annotation emitDomainClassesAndInterfaces @0xeb0d831668c6eda4 (file) : Bool; +# Whether generate domain classes and interfaces (default is 'true' if annotation is missing) + +annotation typeVisibility @0xeb0d831668c6eda6 (file) : TypeVisibility; +# Visibility of generated types annotation name @0xeb0d831668c6eda2 (field, enumerant, struct, enum, interface, method, param, group, union) : Text; # C# member name for code generation diff --git a/scripts/measure-coverage.ps1 b/scripts/measure-coverage.ps1 index a438829..c16ed26 100644 --- a/scripts/measure-coverage.ps1 +++ b/scripts/measure-coverage.ps1 @@ -4,12 +4,10 @@ $coverageDir = "$rootDir\coverage" $coverageReportDir = "$rootDir\coverage\report" $openCover = "$env:LOCALAPPDATA\Apps\OpenCover\OpenCover.Console.exe" $vsTestConsole = where.exe vstest.console +$coverageOutput = "$coverageDir\coverage.xml" $runtimeTests = "$rootDir\Capnp.Net.Runtime.Tests\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.dll" -$coverageOutputRuntime = "$coverageDir\cov-Capnp.Net.Runtime.xml" - $generatorTests = "$rootDir\CapnpC.CSharp.Generator.Tests\bin\Release\netcoreapp3.0\CapnpC.CSharp.Generator.Tests.dll" -$coverageOutputGenerator = "$coverageDir\cov-CapnpC.CSharp.Generator.xml" If(!(test-path $coverageDir)) { @@ -25,14 +23,15 @@ If(!(test-path $coverageReportDir)) -targetArgs:"/inIsolation $runtimeTests /TestCaseFilter:`"TestCategory=Coverage`"" ` -filter:"+[Capnp.Net.Runtime]Capnp.*" ` -excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" ` - -output:"$coverageOutputRuntime" ` + -output:"$coverageOutput" ` -mergebyhash -register:user -oldStyle & $openCover -target:"$vsTestConsole" ` -targetArgs:"/inIsolation $generatorTests" ` -filter:"+[CapnpC.CSharp.Generator]CapnpC.CSharp.Generator.* -[CapnpC.CSharp.Generator]CapnpC.CSharp.Generator.Schema.*" ` -excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" ` - -output:"$coverageOutputGenerator" ` + -output:"$coverageOutput" ` + -mergeoutput ` -mergebyhash -register:user -oldStyle -ReportGenerator.exe -reports:"$coverageOutputRuntime;$coverageOutputGenerator" -targetdir:"$coverageReportDir" -reportTypes:"Html;Xml" +ReportGenerator.exe -reports:"$coverageOutput" -targetdir:"$coverageReportDir" -reportTypes:"Html" From 2369b4788a60ed64a6b029d1b07858a46f08a2d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 29 Mar 2020 00:07:16 +0100 Subject: [PATCH 22/76] fixes + new tests --- Capnp.Net.Runtime.Tests/Dtbdct.cs | 46 +- ...pcErrorHandling.cs => EdgeCaseHandling.cs} | 580 +++++++++++++++++- Capnp.Net.Runtime.Tests/LocalRpc.cs | 8 +- .../Mock/TestCapImplementations.cs | 109 ++++ Capnp.Net.Runtime.Tests/TcpRpc.cs | 30 +- .../TcpRpcAdvancedStuff.cs | 6 +- Capnp.Net.Runtime.Tests/TcpRpcInterop.cs | 50 +- Capnp.Net.Runtime.Tests/TcpRpcPorted.cs | 2 +- Capnp.Net.Runtime.Tests/Testsuite.cs | 183 +++++- Capnp.Net.Runtime.Tests/Util/TestBase.cs | 19 +- Capnp.Net.Runtime/Rpc/Impatient.cs | 23 +- Capnp.Net.Runtime/Rpc/LazyCapability.cs | 3 +- Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 3 + Capnp.Net.Runtime/Rpc/Proxy.cs | 20 +- .../Rpc/ResolvingCapabilityExtensions.cs | 14 +- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 322 +++++----- Capnp.Net.Runtime/SerializerState.cs | 8 +- 17 files changed, 1170 insertions(+), 256 deletions(-) rename Capnp.Net.Runtime.Tests/{TcpRpcErrorHandling.cs => EdgeCaseHandling.cs} (50%) diff --git a/Capnp.Net.Runtime.Tests/Dtbdct.cs b/Capnp.Net.Runtime.Tests/Dtbdct.cs index eedecb3..fa48434 100644 --- a/Capnp.Net.Runtime.Tests/Dtbdct.cs +++ b/Capnp.Net.Runtime.Tests/Dtbdct.cs @@ -10,9 +10,15 @@ namespace Capnp.Net.Runtime.Tests public class Dtbdct: TestBase { [TestMethod] - public void Embargo() + public void EmbargoOnPromisedAnswer() { - NewDtbdctTestbed().RunTest(Testsuite.Embargo); + NewDtbdctTestbed().RunTest(Testsuite.EmbargoOnPromisedAnswer); + } + + [TestMethod] + public void EmbargoOnImportedCap() + { + NewDtbdctTestbed().RunTest(Testsuite.EmbargoOnImportedCap); } [TestMethod] @@ -63,6 +69,18 @@ namespace Capnp.Net.Runtime.Tests NewDtbdctTestbed().RunTest(Testsuite.PromiseResolve); } + [TestMethod] + public void PromiseResolveLate() + { + NewDtbdctTestbed().RunTest(Testsuite.PromiseResolveLate); + } + + [TestMethod] + public void PromiseResolveError() + { + NewDtbdctTestbed().RunTest(Testsuite.PromiseResolveError); + } + [TestMethod] public void Cancelation() { @@ -116,5 +134,29 @@ namespace Capnp.Net.Runtime.Tests { NewDtbdctTestbed().RunTest(Testsuite.Ownership3); } + + [TestMethod] + public void SillySkeleton() + { + NewDtbdctTestbed().RunTest(Testsuite.SillySkeleton); + } + + [TestMethod] + public void ImportReceiverAnswer() + { + NewDtbdctTestbed().RunTest(Testsuite.ImportReceiverAnswer); + } + + [TestMethod] + public void ImportReceiverAnswerError() + { + NewDtbdctTestbed().RunTest(Testsuite.ImportReceiverAnswerError); + } + + [TestMethod] + public void ImportReceiverAnswerCanceled() + { + NewDtbdctTestbed().RunTest(Testsuite.ImportReceiverCanceled); + } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs similarity index 50% rename from Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs rename to Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs index 8bd35b2..b399f0a 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcErrorHandling.cs +++ b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs @@ -16,7 +16,7 @@ namespace Capnp.Net.Runtime.Tests { [TestClass] [TestCategory("Coverage")] - public class TcpRpcErrorHandling: TestBase + public class EdgeCaseHandling: TestBase { class MemStreamEndpoint : IEndpoint { @@ -255,6 +255,74 @@ namespace Capnp.Net.Runtime.Tests tester.ExpectAbort(); } + [TestMethod] + public void UnimplementedReturnAcceptFromThirdParty() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.AcceptFromThirdParty; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + } + + [TestMethod] + public void UnimplementedReturnUnknown() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = (Return.WHICH)33; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + } + + [TestMethod] + public void InvalidReturnTakeFromOtherQuestion() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.TakeFromOtherQuestion; + _.Return.TakeFromOtherQuestion = 1u; + }); + tester.ExpectAbort(); + } + [TestMethod] public void InvalidReceiverHosted() { @@ -309,7 +377,92 @@ namespace Capnp.Net.Runtime.Tests } [TestMethod] - public void DuplicateResolve() + public void InvalidCallTargetImportedCap() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + uint bootCapId = 0; + + tester.Send(_ => { _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 0; }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => { + _.which = Message.WHICH.Call; + _.Call.QuestionId = 1; + _.Call.Target.which = MessageTarget.WHICH.ImportedCap; + _.Call.Target.ImportedCap = bootCapId + 1; + _.Call.InterfaceId = ((TypeIdAttribute)typeof(ITestInterface).GetCustomAttributes(typeof(TypeIdAttribute), false)[0]).Id; + _.Call.MethodId = 0; + _.Call.Params.Content.Rewrap(); + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void InvalidCallTargetPromisedAnswer() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + uint bootCapId = 0; + + tester.Send(_ => { _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 0; }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => { + _.which = Message.WHICH.Call; + _.Call.QuestionId = 1; + _.Call.Target.which = MessageTarget.WHICH.PromisedAnswer; + _.Call.Target.PromisedAnswer.QuestionId = 1; + _.Call.Target.PromisedAnswer.Transform.Init(1); + _.Call.Target.PromisedAnswer.Transform[0].which = PromisedAnswer.Op.WHICH.GetPointerField; + _.Call.InterfaceId = ((TypeIdAttribute)typeof(ITestInterface).GetCustomAttributes(typeof(TypeIdAttribute), false)[0]).Id; + _.Call.MethodId = 0; + _.Call.Params.Content.Rewrap(); + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void UnimplementedCallTargetUnknown() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + uint bootCapId = 0; + + tester.Send(_ => { _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 0; }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => { + _.which = Message.WHICH.Call; + _.Call.QuestionId = 1; + _.Call.Target.which = (MessageTarget.WHICH)77; + _.Call.InterfaceId = ((TypeIdAttribute)typeof(ITestInterface).GetCustomAttributes(typeof(TypeIdAttribute), false)[0]).Id; + _.Call.MethodId = 0; + _.Call.Params.Content.Rewrap(); + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + Assert.IsFalse(tester.IsDismissed); + } + + [TestMethod] + public void DuplicateResolve1() { var tester = new RpcEngineTester(); @@ -346,6 +499,125 @@ namespace Capnp.Net.Runtime.Tests tester.Recv(_ => { Assert.AreEqual(Message.WHICH.Release, _.which); }); + + // tester.ExpectAbort(); + + // Duplicate resolve is only a protocol error if the Rpc engine can prove misbehavior. + // In this case that proof is not possible because the preliminary cap is release (thus, removed from import table) + // immediately after the first resolution. Now we get the situation that the 2nd resolution refers to a non-existing + // cap. This is not considered a protocol error because it might be due to an expected race condition + // between receiver-side Release and sender-side Resolve. + } + + [TestMethod] + public void DuplicateResolve2() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.Results; + _.Return.Results.CapTable.Init(1); + _.Return.Results.CapTable[0].which = CapDescriptor.WHICH.SenderPromise; + _.Return.Results.CapTable[0].SenderPromise = 0; + _.Return.Results.Content.SetCapability(0); + }); + proxy.Call(0, 0, DynamicSerializerState.CreateForRpc()); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Finish, _.which); + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Call, _.which); + }); + tester.Send(_ => { + _.which = Message.WHICH.Resolve; + _.Resolve.which = Resolve.WHICH.Cap; + _.Resolve.Cap.which = CapDescriptor.WHICH.SenderHosted; + _.Resolve.Cap.SenderHosted = 1; + }); + tester.Send(_ => { + _.which = Message.WHICH.Resolve; + _.Resolve.which = Resolve.WHICH.Exception; + _.Resolve.Exception.Reason = "problem"; + }); + + tester.ExpectAbort(); + } + + [TestMethod] + public void UnimplementedResolveCategory() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.Results; + _.Return.Results.CapTable.Init(1); + _.Return.Results.CapTable[0].which = CapDescriptor.WHICH.SenderPromise; + _.Return.Results.CapTable[0].SenderPromise = 0; + }); + tester.Send(_ => { + _.which = Message.WHICH.Resolve; + _.Resolve.which = (Resolve.WHICH)7; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Finish, _.which); + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + } + + [TestMethod] + public void InvalidResolve() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.Results; + _.Return.Results.CapTable.Init(1); + _.Return.Results.CapTable[0].which = CapDescriptor.WHICH.SenderHosted; + _.Return.Results.CapTable[0].SenderHosted = 7; + }); + tester.Send(_ => { + _.which = Message.WHICH.Resolve; + _.Resolve.which = Resolve.WHICH.Cap; + _.Resolve.PromiseId = 7; + _.Resolve.Cap.which = CapDescriptor.WHICH.SenderHosted; + _.Resolve.Cap.SenderHosted = 1; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Finish, _.which); + }); + tester.ExpectAbort(); } @@ -506,6 +778,73 @@ namespace Capnp.Net.Runtime.Tests Assert.IsFalse(tester.IsDismissed); } + [TestMethod] + public void UnimplementedSendResultsToThirdParty() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + uint bootCapId = 0; + + tester.Send(_ => { + _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 0; }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => { + _.which = Message.WHICH.Call; + _.Call.QuestionId = 42; + _.Call.Target.which = MessageTarget.WHICH.ImportedCap; + _.Call.Target.ImportedCap = bootCapId; + _.Call.InterfaceId = new TestInterface_Skeleton().InterfaceId; + _.Call.MethodId = 0; + var wr = _.Call.Params.Content.Rewrap(); + _.Call.Params.CapTable.Init(0); + _.Call.SendResultsTo.which = Call.sendResultsTo.WHICH.ThirdParty; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + Assert.IsFalse(tester.IsDismissed); + } + + [TestMethod] + public void UnimplementedSendResultsToUnknown() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + uint bootCapId = 0; + + tester.Send(_ => { + _.which = Message.WHICH.Bootstrap; _.Bootstrap.QuestionId = 0; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(1, _.Return.Results.CapTable.Count); + bootCapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => { + _.which = Message.WHICH.Call; + _.Call.QuestionId = 42; + _.Call.Target.which = MessageTarget.WHICH.ImportedCap; + _.Call.Target.ImportedCap = bootCapId; + _.Call.InterfaceId = new TestInterface_Skeleton().InterfaceId; + _.Call.MethodId = 0; + var wr = _.Call.Params.Content.Rewrap(); + _.Call.Params.CapTable.Init(0); + _.Call.SendResultsTo.which = (Call.sendResultsTo.WHICH)13; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + Assert.IsFalse(tester.IsDismissed); + } + class TestPipelineImpl3 : ITestPipeline { readonly TestPipelineImpl2 _impl; @@ -605,5 +944,242 @@ namespace Capnp.Net.Runtime.Tests }); Assert.IsFalse(tester.IsDismissed); } + + [TestMethod] + public void SenderLoopbackOnInvalidCap() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + tester.Send(_ => { + _.which = Message.WHICH.Disembargo; + _.Disembargo.Target.which = MessageTarget.WHICH.ImportedCap; + _.Disembargo.Target.ImportedCap = 0; + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void SenderLoopbackOnInvalidPromisedAnswer() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + tester.Send(_ => { + _.which = Message.WHICH.Disembargo; + _.Disembargo.Context.which = Disembargo.context.WHICH.SenderLoopback; + _.Disembargo.Context.SenderLoopback = 0; + _.Disembargo.Target.which = MessageTarget.WHICH.PromisedAnswer; + _.Disembargo.Target.PromisedAnswer.QuestionId = 9; + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void SenderLoopbackOnUnknownTarget() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + tester.Send(_ => { + _.which = Message.WHICH.Disembargo; + _.Disembargo.Context.which = Disembargo.context.WHICH.SenderLoopback; + _.Disembargo.Context.SenderLoopback = 0; + _.Disembargo.Target.which = (MessageTarget.WHICH)12; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + } + + [TestMethod] + public void ReceiverLoopbackOnInvalidCap() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + tester.Send(_ => { + _.which = Message.WHICH.Disembargo; + _.Disembargo.Context.which = Disembargo.context.WHICH.ReceiverLoopback; + _.Disembargo.Context.ReceiverLoopback = 0; + _.Disembargo.Target.which = MessageTarget.WHICH.ImportedCap; + _.Disembargo.Target.ImportedCap = 0; + }); + tester.ExpectAbort(); + } + + [TestMethod] + public void UnimplementedDisembargoAccept() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + tester.Send(_ => { + _.which = Message.WHICH.Disembargo; + _.Disembargo.Context.which = Disembargo.context.WHICH.Accept; + _.Disembargo.Target.which = MessageTarget.WHICH.ImportedCap; + _.Disembargo.Target.ImportedCap = 0; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + } + + [TestMethod] + public void UnimplementedDisembargoProvide() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + tester.Send(_ => { + _.which = Message.WHICH.Disembargo; + _.Disembargo.Context.which = Disembargo.context.WHICH.Provide; + _.Disembargo.Target.which = MessageTarget.WHICH.ImportedCap; + _.Disembargo.Target.ImportedCap = 0; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + } + + [TestMethod] + public void UnimplementedDisembargoUnknown() + { + var tester = new RpcEngineTester(); + tester.Engine.Main = new TestInterfaceImpl(new Counters()); + + tester.Send(_ => { + _.which = Message.WHICH.Disembargo; + _.Disembargo.Context.which = (Disembargo.context.WHICH)50; + _.Disembargo.Target.which = MessageTarget.WHICH.ImportedCap; + _.Disembargo.Target.ImportedCap = 0; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + } + + [TestMethod] + public void UnimplementedCall() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.Results; + _.Return.Results.CapTable.Init(1); + _.Return.Results.CapTable[0].which = CapDescriptor.WHICH.SenderHosted; + _.Return.Results.CapTable[0].SenderHosted = 1; + _.Return.Results.Content.SetCapability(0); + }); + Assert.IsTrue(proxy.WhenResolved.IsCompleted); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Finish, _.which); + }); + var args = DynamicSerializerState.CreateForRpc(); + var ti = new TestInterfaceImpl(new Counters()); + args.ProvideCapability(ti); + proxy.Call(1, 2, args); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Call, _.which); + Assert.AreEqual(1ul, _.Call.InterfaceId); + Assert.AreEqual((ushort)2, _.Call.MethodId); + + Assert.IsFalse(ti.IsDisposed); + + tester.Send(_1 => + { + _1.which = Message.WHICH.Unimplemented; + _1.Unimplemented.which = Message.WHICH.Call; + Reserializing.DeepCopy(_.Call, _1.Unimplemented.Call); + }); + + Assert.IsTrue(ti.IsDisposed); + }); + } + + [TestMethod] + public void UnimplementedBootstrap() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + + tester.Send(_1 => + { + _1.which = Message.WHICH.Unimplemented; + _1.Unimplemented.which = Message.WHICH.Bootstrap; + Reserializing.DeepCopy(_.Bootstrap, _1.Unimplemented.Bootstrap); + }); + }); + + tester.ExpectAbort(); + } + + [TestMethod] + public void Abort() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + }); + + tester.Send(_ => { + _.which = Message.WHICH.Abort; + }); + } + + [TestMethod] + public void ThirdPartyHostedBootstrap() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + + tester.Send(_1 => + { + _1.which = Message.WHICH.Return; + _1.Return.AnswerId = _.Bootstrap.QuestionId; + _1.Return.which = Return.WHICH.Results; + _1.Return.Results.CapTable.Init(1); + _1.Return.Results.CapTable[0].which = CapDescriptor.WHICH.ThirdPartyHosted; + _1.Return.Results.CapTable[0].ThirdPartyHosted.VineId = 27; + _1.Return.Results.Content.SetCapability(0); + }); + }); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Finish, _.which); + }); + + proxy.Call(1, 2, DynamicSerializerState.CreateForRpc()); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Call, _.which); + Assert.AreEqual(MessageTarget.WHICH.ImportedCap, _.Call.Target.which); + Assert.AreEqual(27u, _.Call.Target.ImportedCap); + }); + } } } diff --git a/Capnp.Net.Runtime.Tests/LocalRpc.cs b/Capnp.Net.Runtime.Tests/LocalRpc.cs index 2100293..7adc180 100644 --- a/Capnp.Net.Runtime.Tests/LocalRpc.cs +++ b/Capnp.Net.Runtime.Tests/LocalRpc.cs @@ -34,7 +34,7 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void Embargo() { - NewLocalTestbed().RunTest(Testsuite.Embargo); + NewLocalTestbed().RunTest(Testsuite.EmbargoOnPromisedAnswer); } [TestMethod] @@ -132,5 +132,11 @@ namespace Capnp.Net.Runtime.Tests { NewLocalTestbed().RunTest(Testsuite.Ownership3); } + + [TestMethod] + public void ImportReceiverAnswer() + { + NewLocalTestbed().RunTest(Testsuite.Ownership3); + } } } diff --git a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs index 6f65819..dbd91c5 100644 --- a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs @@ -827,6 +827,115 @@ namespace Capnp.Net.Runtime.Tests.GenImpls } } + class TestMoreStuffImpl2 : ITestMoreStuff + { + readonly TaskCompletionSource _echo = new TaskCompletionSource(); + readonly TaskCompletionSource _held = new TaskCompletionSource(); + ITestCallOrder _cap; + int _callCount; + + public TestMoreStuffImpl2() + { + } + + public async Task CallFoo(ITestInterface cap, CancellationToken cancellationToken_) + { + using (cap) + { + string s = await cap.Foo(123, true, cancellationToken_); + Assert.AreEqual("foo", s); + } + return "bar"; + } + + public Task CallFooWhenResolved(ITestInterface cap, CancellationToken cancellationToken_) + { + throw new NotImplementedException(); + } + + public Task CallHeld(CancellationToken cancellationToken_) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + } + + public Task Echo(ITestCallOrder cap, CancellationToken cancellationToken_) + { + _cap = cap; + return Task.FromResult(_echo.Task.Eager(true)); + } + + public void EnableEcho() + { + _echo.SetResult(_cap); + } + + public Task ExpectCancel(ITestInterface cap, CancellationToken cancellationToken_) + { + throw new NotImplementedException(); + } + + public Task GetCallSequence(uint expected, CancellationToken cancellationToken_) + { + return Task.FromResult((uint)(Interlocked.Increment(ref _callCount) - 1)); + } + + public Task GetEnormousString(CancellationToken cancellationToken_) + { + return Task.FromResult(new string(new char[100000000])); + } + + public Task GetHandle(CancellationToken cancellationToken_) + { + throw new NotImplementedException(); + } + + public Task GetHeld(CancellationToken cancellationToken_) + { + return _held.Task; + } + + public Task GetNull(CancellationToken cancellationToken_) + { + return Task.FromResult(default(ITestMoreStuff)); + } + + public async Task Hold(ITestInterface cap, CancellationToken cancellationToken_) + { + try + { + var unwrapped = await cap.Unwrap(); + _held.SetResult(unwrapped); + } + catch (System.Exception exception) when (exception.Message == new TaskCanceledException().Message) + { + _held.SetCanceled(); + } + catch (System.Exception exception) + { + _held.SetException(exception); + } + } + + public Task<(string, string)> MethodWithDefaults(string a, uint b, string c, CancellationToken cancellationToken_) + { + throw new NotImplementedException(); + } + + public Task MethodWithNullDefault(string a, ITestInterface b, CancellationToken cancellationToken_) + { + throw new NotImplementedException(); + } + + public Task NeverReturn(ITestInterface cap, CancellationToken cancellationToken_) + { + throw new NotImplementedException(); + } + } + #endregion TestMoreStuff #region TestHandle diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index 56d8229..b122da4 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -44,7 +44,7 @@ namespace Capnp.Net.Runtime.Tests int MediumTimeout => Debugger.IsAttached ? Timeout.Infinite : 2000; - [TestMethod, Timeout(10000)] + [TestMethod] public void CreateAndDispose() { (var server, var client) = SetupClientServerPair(); @@ -55,7 +55,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void ConnectAndDispose() { (var server, var client) = SetupClientServerPair(); @@ -77,7 +77,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void ConnectNoServer() { using (var client = new TcpRpcClient("localhost", TcpPort)) @@ -86,7 +86,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void ConnectAndBootstrap() { (var server, var client) = SetupClientServerPair(); @@ -105,7 +105,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void ConnectNoBootstrap() { (var server, var client) = SetupClientServerPair(); @@ -123,7 +123,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void CallReturn() { (var server, var client) = SetupClientServerPair(); @@ -164,7 +164,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void CallCancelOnServer() { (var server, var client) = SetupClientServerPair(); @@ -199,7 +199,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void CallCancelOnClient() { ExpectingLogOutput = false; @@ -244,7 +244,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void CallReturnAfterClientSideCancel() { ExpectingLogOutput = false; @@ -306,7 +306,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void CallServerSideException() { (var server, var client) = SetupClientServerPair(); @@ -343,7 +343,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void PipelineBeforeReturn() { (var server, var client) = SetupClientServerPair(); @@ -416,7 +416,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void PipelineAfterReturn() { (var server, var client) = SetupClientServerPair(); @@ -492,7 +492,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void PipelineMultiple() { (var server, var client) = SetupClientServerPair(); @@ -609,7 +609,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void PipelineCallAfterDisposal() { (var server, var client) = SetupClientServerPair(); @@ -656,7 +656,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void PipelineCallDuringDisposal() { (var server, var client) = SetupClientServerPair(); diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index e029d0a..ecd5d8d 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -13,7 +13,7 @@ namespace Capnp.Net.Runtime.Tests [TestCategory("Coverage")] public class TcpRpcAdvancedStuff : TestBase { - [TestMethod, Timeout(10000)] + [TestMethod] public void MultiConnect() { using (var server = SetupServer()) @@ -51,7 +51,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void TwoClients() { using (var server = SetupServer()) @@ -90,7 +90,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void ClosingServerWhileRequestingBootstrap() { for (int i = 0; i < 100; i++) diff --git a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs index 97228ca..e093a27 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs @@ -128,7 +128,7 @@ namespace Capnp.Net.Runtime.Tests IncrementTcpPort(); } - [TestMethod, Timeout(10000)] + [TestMethod] public void BasicClient() { LaunchCompatTestProcess("server:Interface", stdout => @@ -159,7 +159,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void BasicServer() { using (var server = SetupServer()) @@ -176,7 +176,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void PipelineClient() { LaunchCompatTestProcess("server:Pipeline", stdout => @@ -213,7 +213,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void PipelineServer() { using (var server = SetupServer()) @@ -232,7 +232,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void ReleaseClient() { LaunchCompatTestProcess("server:MoreStuff", stdout => @@ -265,7 +265,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void ReleaseServer() { using (var server = SetupServer()) @@ -377,7 +377,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void ReleaseOnCancelServer() { using (var server = SetupServer()) @@ -464,7 +464,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void CancelationServer() { LaunchCompatTestProcess("server:MoreStuff", stdout => @@ -494,7 +494,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void CancelationClient() { using (var server = SetupServer()) @@ -511,7 +511,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void PromiseResolveServer() { LaunchCompatTestProcess("server:MoreStuff", stdout => @@ -553,7 +553,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void PromiseResolveClient() { using (var server = SetupServer()) @@ -573,7 +573,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void RetainAndReleaseServer() { var destructionPromise = new TaskCompletionSource(); @@ -671,7 +671,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void CancelServer() { LaunchCompatTestProcess("server:MoreStuff", stdout => @@ -712,7 +712,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void CancelClient() { using (var server = SetupServer()) @@ -729,7 +729,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void SendTwiceServer() { LaunchCompatTestProcess("server:MoreStuff", stdout => @@ -773,7 +773,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void SendTwiceClient() { using (var server = SetupServer()) @@ -793,7 +793,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void EmbargoServer() { LaunchCompatTestProcess("server:MoreStuff", stdout => @@ -878,7 +878,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void EmbargoServer2() { LaunchCompatTestProcess("server:MoreStuff", stdout => @@ -961,7 +961,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void EmbargoClient() { using (var server = SetupServer()) @@ -1031,7 +1031,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void EmbargoErrorServer() { LaunchCompatTestProcess("server:MoreStuff", EmbargoErrorImpl); @@ -1049,7 +1049,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void EmbargoErrorClient() { using (var server = SetupServer()) @@ -1065,7 +1065,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void EmbargoNullServer() { LaunchCompatTestProcess("server:MoreStuff", stdout => @@ -1125,7 +1125,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void EmbargoNullClient() { using (var server = SetupServer()) @@ -1141,7 +1141,7 @@ namespace Capnp.Net.Runtime.Tests } } - [TestMethod, Timeout(10000)] + [TestMethod] public void CallBrokenPromiseServer() { LaunchCompatTestProcess("server:MoreStuff", stdout => @@ -1178,7 +1178,7 @@ namespace Capnp.Net.Runtime.Tests }); } - [TestMethod, Timeout(10000)] + [TestMethod] public void CallBrokenPromiseClient() { using (var server = SetupServer()) diff --git a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs index e878920..9e7cd2a 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs @@ -119,7 +119,7 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void Embargo() { - NewLocalhostTcpTestbed().RunTest(Testsuite.Embargo); + NewLocalhostTcpTestbed().RunTest(Testsuite.EmbargoOnPromisedAnswer); } [TestMethod] diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs index 1b3486d..90b4675 100644 --- a/Capnp.Net.Runtime.Tests/Testsuite.cs +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -53,7 +53,7 @@ namespace Capnp.Net.Runtime.Tests ftask.GetAwaiter().GetResult(); // re-throw exception } - public static void Embargo(ITestbed testbed) + public static void EmbargoOnPromisedAnswer(ITestbed testbed) { var counters = new Counters(); var impl = new TestMoreStuffImpl(counters); @@ -113,7 +113,64 @@ namespace Capnp.Net.Runtime.Tests } } } - + + public static void EmbargoOnImportedCap(ITestbed testbed) + { + var impl = new TestMoreStuffImpl2(); + + using (var main = testbed.ConnectMain(impl)) + { + var cap = new TestCallOrderImpl(); + cap.CountToDispose = 6; + + var earlyCall = main.GetCallSequence(0, default); + + var echo = main.Echo(cap, default); + testbed.MustComplete(echo); + using (var pipeline = echo.Result) + { + var call0 = pipeline.GetCallSequence(0, default); + var call1 = pipeline.GetCallSequence(1, default); + + testbed.MustComplete(earlyCall); + + impl.EnableEcho(); + + var call2 = pipeline.GetCallSequence(2, default); + + testbed.MustComplete(echo); + using (var resolved = echo.Result) + { + var call3 = pipeline.GetCallSequence(3, default); + var call4 = pipeline.GetCallSequence(4, default); + var call5 = pipeline.GetCallSequence(5, default); + + try + { + testbed.MustComplete(call0); + testbed.MustComplete(call1); + testbed.MustComplete(call2); + testbed.MustComplete(call3); + testbed.MustComplete(call4); + testbed.MustComplete(call5); + } + catch (System.Exception) + { + cap.CountToDispose = null; + throw; + } + + Assert.AreEqual(0u, call0.Result); + Assert.AreEqual(1u, call1.Result); + Assert.AreEqual(2u, call2.Result); + Assert.AreEqual(3u, call3.Result); + Assert.AreEqual(4u, call4.Result); + Assert.AreEqual(5u, call5.Result); + } + } + } + } + public static void EmbargoError(ITestbed testbed) { var counters = new Counters(); @@ -404,6 +461,55 @@ namespace Capnp.Net.Runtime.Tests } } + public static void PromiseResolveLate(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var tcs = new TaskCompletionSource(); + var disposed = new TaskCompletionSource(); + using (var eager = tcs.Task.Eager(true)) + { + var request = main.NeverReturn(Proxy.Share(eager), new CancellationToken(true)); + + testbed.MustComplete(request); + + var tiimpl = new TestInterfaceImpl(new Counters(), disposed); + tcs.SetResult(tiimpl); + + Assert.IsFalse(tiimpl.IsDisposed); + } + testbed.MustComplete(disposed.Task); + } + } + + public static void PromiseResolveError(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + using (var main = testbed.ConnectMain(impl)) + { + var tcs = new TaskCompletionSource(); + using (var eager = tcs.Task.Eager(true)) + { + var request = main.CallFoo(Proxy.Share(eager), default); + var request2 = main.CallFooWhenResolved(eager, default); + + var gcs = main.GetCallSequence(0, default); + testbed.MustComplete(gcs); + Assert.AreEqual(2u, gcs.Result); + Assert.AreEqual(3, counters.CallCount); + + tcs.SetException(new System.Exception("too bad")); + + testbed.MustComplete(request, request2); + Assert.IsTrue(request.IsFaulted); + Assert.IsTrue(request2.IsFaulted); + } + } + } + public static void Cancelation(ITestbed testbed) { var counters = new Counters(); @@ -570,5 +676,78 @@ namespace Capnp.Net.Runtime.Tests testbed.MustComplete(tcs.Task); } } + + class ThrowingSkeleton : Skeleton + { + public bool WasCalled { get; private set; } + + public override Task Invoke(ulong interfaceId, ushort methodId, DeserializerState args, CancellationToken cancellationToken = default) + { + WasCalled = true; + throw new NotImplementedException(); + } + } + + public static void SillySkeleton(ITestbed testbed) + { + var impl = new ThrowingSkeleton(); + using (var main = testbed.ConnectMain(impl)) + { + var tcs = new TaskCompletionSource(); + var ti = new TestInterfaceImpl(new Counters(), tcs); + testbed.ExpectPromiseThrows(main.CallFoo(ti)); + Assert.IsTrue(impl.WasCalled); + testbed.MustComplete(tcs.Task); + } + } + + public static void ImportReceiverAnswer(ITestbed testbed) + { + var impl = new TestMoreStuffImpl2(); + using (var main = testbed.ConnectMain(impl)) + { + var held = main.GetHeld().Eager(); + var foo = main.CallFoo(held); + testbed.MustNotComplete(foo); + var tcs = new TaskCompletionSource(); + testbed.MustComplete( + main.Hold(new TestInterfaceImpl(new Counters(), tcs)), + foo, + tcs.Task); + } + } + + public static void ImportReceiverAnswerError(ITestbed testbed) + { + var impl = new TestMoreStuffImpl2(); + using (var main = testbed.ConnectMain(impl)) + using (var held = main.GetHeld().Eager()) + { + var foo = main.CallFoo(held); + testbed.MustNotComplete(foo); + var faulted = Task.FromException( + new InvalidOperationException("I faulted")).Eager(true); + testbed.MustComplete( + main.Hold(faulted), + foo); + Assert.IsTrue(foo.IsFaulted); + } + } + + public static void ImportReceiverCanceled(ITestbed testbed) + { + var impl = new TestMoreStuffImpl2(); + using (var main = testbed.ConnectMain(impl)) + using (var held = main.GetHeld().Eager()) + { + var foo = main.CallFoo(held); + testbed.MustNotComplete(foo); + var canceled = Task.FromCanceled(new CancellationToken(true)).Eager(true); + testbed.MustComplete( + main.Hold(canceled), + foo); + Assert.IsTrue(foo.IsCanceled); + } + } } } diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 2edffbc..6352051 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -15,7 +15,7 @@ namespace Capnp.Net.Runtime.Tests { public interface ITestbed { - T ConnectMain(T main) where T : class; + T ConnectMain(object main) where T : class; void MustComplete(params Task[] tasks); void MustNotComplete(params Task[] tasks); void FlushCommunication(); @@ -52,8 +52,11 @@ namespace Capnp.Net.Runtime.Tests public void Dismiss() { - OtherEndpoint.Dismiss(); - _dismissed = true; + if (!_dismissed) + { + _dismissed = true; + OtherEndpoint.Dismiss(); + } } public void Forward(WireFrame frame) @@ -156,9 +159,9 @@ namespace Capnp.Net.Runtime.Tests action(this); } - T ITestbed.ConnectMain(T main) + T ITestbed.ConnectMain(object main) { - return main; + return (T)main; } void ITestbed.FlushCommunication() @@ -199,7 +202,7 @@ namespace Capnp.Net.Runtime.Tests }); } - T ITestbed.ConnectMain(T main) + T ITestbed.ConnectMain(object main) { return SetupEnginePair(main, _decisionTree, out _enginePair); } @@ -242,7 +245,7 @@ namespace Capnp.Net.Runtime.Tests } } - T ITestbed.ConnectMain(T main) + T ITestbed.ConnectMain(object main) { _server.Main = main; return _client.GetMain(); @@ -330,7 +333,7 @@ namespace Capnp.Net.Runtime.Tests return (server, client); } - protected static T SetupEnginePair(T main, DecisionTree decisionTree, out EnginePair pair) where T: class + protected static T SetupEnginePair(object main, DecisionTree decisionTree, out EnginePair pair) where T: class { pair = new EnginePair(decisionTree); pair.Engine1.Main = main; diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index 7b2c7b3..4b73082 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -158,8 +158,16 @@ namespace Capnp.Rpc throw new ArgumentException("The task was not returned from a remote method invocation. See documentation for details."); } - var lazyCap = new LazyCapability(task.AsProxyTask()); - return (CapabilityReflection.CreateProxy(lazyCap) as TInterface)!; + var proxyTask = task.AsProxyTask(); + if (proxyTask.ReplacementTaskIsCompletedSuccessfully()) + { + return proxyTask.Result.Cast(true); + } + else + { + var lazyCap = new LazyCapability(proxyTask); + return (CapabilityReflection.CreateProxy(lazyCap) as TInterface)!; + } } else { @@ -172,6 +180,17 @@ namespace Capnp.Rpc } } + public static async Task Unwrap(this TInterface cap) where TInterface: class, IDisposable + { + using var proxy = cap as Proxy; + + if (proxy == null) + return cap; + + var unwrapped = await proxy.ConsumedCap.Unwrap(); + return ((CapabilityReflection.CreateProxy(unwrapped)) as TInterface)!; + } + internal static IRpcEndpoint? AskingEndpoint { get => _askingEndpoint.Value; diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index ae1eef4..6b11347 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -64,8 +64,7 @@ namespace Capnp.Rpc if (WhenResolved.ReplacementTaskIsCompletedSuccessfully()) { using var proxy = new Proxy(WhenResolved.Result); - proxy.Export(endpoint, writer); - return null; + return proxy.Export(endpoint, writer); } else { diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index b660d6d..394f4f2 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; @@ -89,6 +90,7 @@ namespace Capnp.Rpc internal object ReentrancyBlocker { get; } = new object(); internal uint QuestionId => _questionId; internal State StateFlags { get; private set; } + internal IReadOnlyList? CapTable { get; set; } ///

/// Eventually returns the server answer @@ -323,6 +325,7 @@ namespace Capnp.Rpc try { RpcEndpoint.SendQuestion(inParams, call.Params); + CapTable = call.Params.CapTable; } catch (System.Exception exception) { diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index 22957a9..65616b0 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -131,18 +131,17 @@ namespace Capnp.Rpc #endif } - internal Skeleton? GetProvider() + internal async Task GetProvider() { - switch (ConsumedCap) + var unwrapped = await ConsumedCap.Unwrap(); + + switch (unwrapped) { case LocalCapability lcap: return lcap.ProvidedCap; - case null: - return null; - default: - return Vine.Create(ConsumedCap); + return Vine.Create(unwrapped); } } @@ -214,15 +213,20 @@ namespace Capnp.Rpc } } - internal void Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) + internal Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { if (_disposedValue) throw new ObjectDisposedException(nameof(Proxy)); if (ConsumedCap == null) + { writer.which = CapDescriptor.WHICH.None; + return null; + } else - ConsumedCap.Export(endpoint, writer); + { + return ConsumedCap.Export(endpoint, writer); + } } internal void Freeze(out IRpcEndpoint? boundEndpoint) diff --git a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs index 0461d75..86c5fa8 100644 --- a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs @@ -5,6 +5,18 @@ namespace Capnp.Rpc { static class ResolvingCapabilityExtensions { + public static async Task Unwrap(this ConsumedCapability? cap) + { + cap ??= LazyCapability.Null; + + while (cap is IResolvingCapability resolving) + { + cap = await resolving.WhenResolved ?? LazyCapability.Null; + } + + return cap; + } + public static Action? ExportAsSenderPromise(this T cap, IRpcEndpoint endpoint, CapDescriptor.WRITER writer) where T: ConsumedCapability, IResolvingCapability { @@ -20,7 +32,7 @@ namespace Capnp.Rpc try { - var resolvedCap = await cap.WhenResolved; + var resolvedCap = await Unwrap(await cap.WhenResolved); endpoint.Resolve(preliminaryId, vine, () => resolvedCap!); } catch (System.Exception exception) diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 11c99b5..c59c3d8 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -30,16 +30,9 @@ namespace Capnp.Rpc ++RefCount; } - public void Release() - { - --RefCount; - CheckDispose(); - } - public void ReleaseAll() { RefCount = 0; - CheckDispose(); } public void Release(int count) @@ -48,15 +41,6 @@ namespace Capnp.Rpc throw new ArgumentOutOfRangeException(nameof(count)); RefCount -= count; - CheckDispose(); - } - - void CheckDispose() - { - if (RefCount == 0 && Cap is IDisposable disposable) - { - disposable.Dispose(); - } } } @@ -90,7 +74,7 @@ namespace Capnp.Rpc readonly RpcEngine _host; readonly IEndpoint _tx; - readonly Dictionary>> _importTable = new Dictionary>>(); + readonly Dictionary> _importTable = new Dictionary>(); readonly Dictionary> _exportTable = new Dictionary>(); readonly Dictionary _revExportTable = new Dictionary(); readonly Dictionary _questionTable = new Dictionary(); @@ -207,11 +191,17 @@ namespace Capnp.Rpc void SendAbort(string reason) { - var mb = MessageBuilder.Create(); - var msg = mb.BuildRoot(); - msg.which = Message.WHICH.Abort; - msg.Abort!.Reason = reason; - Tx(mb.Frame); + try + { + var mb = MessageBuilder.Create(); + var msg = mb.BuildRoot(); + msg.which = Message.WHICH.Abort; + msg.Abort!.Reason = reason; + Tx(mb.Frame); + } + catch // Take care that an exception does not prevent shutdown. + { + } } void IRpcEndpoint.Resolve(uint preliminaryId, Skeleton preliminaryCap, Func resolvedCapGetter) @@ -305,40 +295,16 @@ namespace Capnp.Rpc lock (_reentrancyBlocker) { uint questionId = NextId(); - var question = new PendingQuestion(this, questionId, target, inParams); - - while (!_questionTable.ReplacementTryAdd(questionId, question)) - { + while (_questionTable.ContainsKey(questionId)) questionId = NextId(); - var oldQuestion = question; - question = new PendingQuestion(this, questionId, target, inParams); - oldQuestion.Dispose(); - } + + var question = new PendingQuestion(this, questionId, target, inParams); + _questionTable.Add(questionId, question); return question; } } - void DeleteQuestion(uint id, PendingQuestion question) - { - lock (_reentrancyBlocker) - { - if (!_questionTable.TryGetValue(id, out var existingQuestion)) - { - Logger.LogError("Attempting to delete unknown question ID. Race condition?"); - return; - } - - if (question != existingQuestion) - { - Logger.LogError("Found different question under given ID. WTF???"); - return; - } - - _questionTable.Remove(id); - } - } - (TaskCompletionSource, uint) AllocateDisembargo() { var tcs = new TaskCompletionSource(); @@ -444,9 +410,9 @@ namespace Capnp.Rpc } } - Skeleton? callTargetCap; + Skeleton callTargetCap; PendingAnswer pendingAnswer; - bool releaseParamCaps = false; + bool releaseParamCaps = true; void AwaitAnswerAndReply() { @@ -564,32 +530,27 @@ namespace Capnp.Rpc { var inParams = req.Params.Content; inParams.Caps = ImportCapTable(req.Params); + releaseParamCaps = false; - if (callTargetCap == null) + try { - releaseParamCaps = true; - pendingAnswer = new PendingAnswer( - Task.FromException( - new RpcException("Call target resolved to null")), null); + var cts = new CancellationTokenSource(); + var callTask = callTargetCap.Invoke(req.InterfaceId, req.MethodId, inParams, cts.Token); + pendingAnswer = new PendingAnswer(callTask, cts); } - else + catch (System.Exception exception) { - try + foreach (var cap in inParams.Caps) { - var cts = new CancellationTokenSource(); - var callTask = callTargetCap.Invoke(req.InterfaceId, req.MethodId, inParams, cts.Token); - pendingAnswer = new PendingAnswer(callTask, cts); - } - catch (System.Exception exception) - { - releaseParamCaps = true; - pendingAnswer = new PendingAnswer( - Task.FromException(exception), null); - } - finally - { - callTargetCap.Relinquish(); + cap?.Release(); } + + pendingAnswer = new PendingAnswer( + Task.FromException(exception), null); + } + finally + { + callTargetCap.Relinquish(); } AwaitAnswerAndReply(); @@ -657,8 +618,8 @@ namespace Capnp.Rpc try { using var proxy = await t; - callTargetCap = proxy?.GetProvider(); - callTargetCap?.Claim(); + callTargetCap = await proxy.GetProvider(); + callTargetCap.Claim(); CreateAnswerAwaitItAndReply(); } catch (TaskCanceledException) @@ -715,6 +676,11 @@ namespace Capnp.Rpc } } + if (req.ReleaseParamCaps) + { + ReleaseExports(question.CapTable); + } + switch (req.which) { case Return.WHICH.Results: @@ -782,6 +748,7 @@ namespace Capnp.Rpc else { Logger.LogWarning("Incoming RPC return: Peer requested to take results from other question, but specified ID is unknown (already released?)"); + throw new RpcProtocolErrorException("Invalid ID"); } } break; @@ -793,48 +760,53 @@ namespace Capnp.Rpc void ProcessResolve(Resolve.READER resolve) { - if (!_importTable.TryGetValue(resolve.PromiseId, out var rcw)) + lock (_reentrancyBlocker) { - Logger.LogWarning("Received a resolve message with invalid ID"); - throw new RpcProtocolErrorException($"Invalid ID {resolve.PromiseId}"); - } - - if (!rcw.Cap.TryGetTarget(out var cap)) - { - // Silently discard - return; - } - - if (!(cap is PromisedCapability resolvableCap)) - { - Logger.LogWarning("Received a resolve message for a capability which is not a promise"); - throw new RpcProtocolErrorException($"Not a promise {resolve.PromiseId}"); - } - - try - { - switch (resolve.which) + if (!_importTable.TryGetValue(resolve.PromiseId, out var rcc)) { - case Resolve.WHICH.Cap: - lock (_reentrancyBlocker) - { + // May happen if Resolve arrives late. Not an actual error. + + if (resolve.which == Resolve.WHICH.Cap) + { + // Import and release immediately + var imp = ImportCap(resolve.Cap); + imp.AddRef(); + imp.Release(); + } + + return; + } + + var cap = rcc.Cap; + + if (!(cap is PromisedCapability resolvableCap)) + { + Logger.LogWarning("Received a resolve message for a capability which is not a promise"); + throw new RpcProtocolErrorException($"Not a promise {resolve.PromiseId}"); + } + + try + { + switch (resolve.which) + { + case Resolve.WHICH.Cap: var resolvedCap = ImportCap(resolve.Cap); resolvableCap.ResolveTo(resolvedCap); - } - break; + break; - case Resolve.WHICH.Exception: - resolvableCap.Break(resolve.Exception.Reason ?? "unknown reason"); - break; + case Resolve.WHICH.Exception: + resolvableCap.Break(resolve.Exception.Reason ?? "unknown reason"); + break; - default: - Logger.LogWarning("Received a resolve message with unknown category."); - throw new RpcUnimplementedException(); + default: + Logger.LogWarning("Received a resolve message with unknown category."); + throw new RpcUnimplementedException(); + } + } + catch (InvalidOperationException) + { + throw new RpcProtocolErrorException($"Capability {resolve.PromiseId} was already resolved"); } - } - catch (InvalidOperationException) - { - throw new RpcProtocolErrorException($"Capability {resolve.PromiseId} was already resolved"); } } @@ -958,14 +930,12 @@ namespace Capnp.Rpc Logger.LogDebug($"Receiver loopback disembargo, Thread = {Thread.CurrentThread.Name}"); #endif - if (!tcs.TrySetResult(0)) - { - Logger.LogError("Attempting to grant disembargo failed. Looks like an internal error / race condition."); - } + tcs.SetResult(0); } else { Logger.LogWarning("Peer sent receiver loopback with unknown ID"); + throw new RpcProtocolErrorException("Invalid ID"); } } @@ -988,6 +958,26 @@ namespace Capnp.Rpc } } + void ReleaseExports(IReadOnlyList? caps) + { + if (caps != null) + { + foreach (var capDesc in caps) + { + switch (capDesc.which) + { + case CapDescriptor.WHICH.SenderHosted: + ReleaseExport(capDesc.SenderHosted, 1); + break; + + case CapDescriptor.WHICH.SenderPromise: + ReleaseExport(capDesc.SenderPromise, 1); + break; + } + } + } + } + void ReleaseResultCaps(PendingAnswer answer) { answer.Chain(async t => @@ -995,24 +985,7 @@ namespace Capnp.Rpc try { var aorcq = await t; - var caps = answer.CapTable; - - if (caps != null) - { - foreach (var capDesc in caps) - { - switch (capDesc.which) - { - case CapDescriptor.WHICH.SenderHosted: - ReleaseExport(capDesc.SenderHosted, 1); - break; - - case CapDescriptor.WHICH.SenderPromise: - ReleaseExport(capDesc.SenderPromise, 1); - break; - } - } - } + ReleaseExports(answer.CapTable); } catch { @@ -1103,6 +1076,7 @@ namespace Capnp.Rpc break; case CapDescriptor.WHICH.SenderPromise: + // Not really expected that a promise gets resolved to another promise. ReleaseExport(resolve.Cap.SenderPromise, 1); break; @@ -1114,7 +1088,19 @@ namespace Capnp.Rpc void ProcessUnimplementedCall(Call.READER call) { - Finish(call.QuestionId); + PendingQuestion? question; + + lock (_reentrancyBlocker) + { + if (!_questionTable.TryGetValue(call.QuestionId, out question)) + { + Logger.LogWarning("Unimplemented call: Unknown question ID."); + + throw new RpcProtocolErrorException("Unknown question ID"); + } + } + + ReleaseExports(question.CapTable); } void ProcessUnimplemented(Message.READER unimplemented) @@ -1265,54 +1251,34 @@ namespace Capnp.Rpc switch (capDesc.which) { case CapDescriptor.WHICH.SenderHosted: - if (_importTable.TryGetValue(capDesc.SenderHosted, out var rcw)) + if (_importTable.TryGetValue(capDesc.SenderHosted, out var rcc)) { - if (rcw.Cap.TryGetTarget(out var impCap)) - { - impCap.Validate(); - rcw.AddRef(); - return impCap; - } - else - { - impCap = new ImportedCapability(this, capDesc.SenderHosted); - rcw.Cap.SetTarget(impCap); - } - - return impCap!; + var impCap = rcc.Cap; + impCap.Validate(); + rcc.AddRef(); + return impCap; } else { var newCap = new ImportedCapability(this, capDesc.SenderHosted); - rcw = new RefCounted>( - new WeakReference(newCap)); - _importTable.Add(capDesc.SenderHosted, rcw); + rcc = new RefCounted(newCap); + _importTable.Add(capDesc.SenderHosted, rcc); return newCap; } case CapDescriptor.WHICH.SenderPromise: - if (_importTable.TryGetValue(capDesc.SenderPromise, out var rcwp)) + if (_importTable.TryGetValue(capDesc.SenderPromise, out var rccp)) { - if (rcwp.Cap.TryGetTarget(out var impCap)) - { - impCap.Validate(); - rcwp.AddRef(); - return impCap; - } - else - { - impCap = new PromisedCapability(this, capDesc.SenderPromise); - rcwp.Cap.SetTarget(impCap); - } - + var impCap = rccp.Cap; + impCap.Validate(); + rccp.AddRef(); return impCap; } else { var newCap = new PromisedCapability(this, capDesc.SenderPromise); - rcw = new RefCounted>( - new WeakReference(newCap)); - _importTable.Add(capDesc.SenderPromise, rcw); + rccp = new RefCounted(newCap); + _importTable.Add(capDesc.SenderPromise, rccp); return newCap; } @@ -1362,25 +1328,15 @@ namespace Capnp.Rpc case CapDescriptor.WHICH.ThirdPartyHosted: if (_importTable.TryGetValue(capDesc.ThirdPartyHosted.VineId, out var rcv)) { - if (rcv.Cap.TryGetTarget(out var impCap)) - { - rcv.AddRef(); - impCap.Validate(); - return impCap; - } - else - { - impCap = new ImportedCapability(this, capDesc.ThirdPartyHosted.VineId); - rcv.Cap.SetTarget(impCap); - } - + var impCap = rcv.Cap; + rcv.AddRef(); + impCap.Validate(); return impCap; } else { var newCap = new ImportedCapability(this, capDesc.ThirdPartyHosted.VineId); - rcv = new RefCounted>( - new WeakReference(newCap)); + rcv = new RefCounted(newCap); return newCap; } @@ -1552,7 +1508,13 @@ namespace Capnp.Rpc void IRpcEndpoint.DeleteQuestion(PendingQuestion question) { - DeleteQuestion(question.QuestionId, question); + lock (_reentrancyBlocker) + { + if (!_questionTable.Remove(question.QuestionId)) + { + Logger.LogError("Attempting to delete unknown question ID."); + } + } } } diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index 8a19bba..42c5522 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -511,7 +511,7 @@ namespace Capnp } } - internal void SetCapability(uint capabilityIndex) + public void SetCapability(uint capabilityIndex) { if (Kind == ObjectKind.Nil) { @@ -1259,10 +1259,10 @@ namespace Capnp /// Adds an entry to the capability table if the provided capability does not yet exist. /// /// The capability, in one of the following forms: - /// Low-level capability object (Rpc.ConsumedCapability) - /// Proxy object (Rpc.Proxy). Note that the provision has "move semantics": SerializerState + /// Low-level capability () + /// Proxy object (). Note that the provision has "move semantics": SerializerState /// takes ownership, so the Proxy object will be disposed. - /// Skeleton object (Rpc.Skeleton) + /// instance /// Capability interface implementation /// /// Index of the given capability in the capability table From 20c8523aae5d3910d25cc0b4e08f8f9aaff05132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 31 Mar 2020 22:01:43 +0200 Subject: [PATCH 23/76] more fixes, more coverage --- Capnp.Net.Runtime.Tests/RpcSchemaTests.cs | 4 + Capnp.Net.Runtime.Tests/SerializationTests.cs | 182 +++++++++++++++++- Capnp.Net.Runtime.Tests/Testsuite.cs | 4 +- Capnp.Net.Runtime/DeserializerState.cs | 2 +- Capnp.Net.Runtime/DynamicSerializerState.cs | 4 +- Capnp.Net.Runtime/MessageBuilder.cs | 6 +- Capnp.Net.Runtime/Rpc/Impatient.cs | 5 +- Capnp.Net.Runtime/Rpc/LazyCapability.cs | 2 - Capnp.Net.Runtime/Rpc/PendingAnswer.cs | 2 +- Capnp.Net.Runtime/Rpc/Proxy.cs | 5 +- .../Rpc/ResolvingCapabilityExtensions.cs | 8 +- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 16 +- Capnp.Net.Runtime/Rpc/Vine.cs | 6 +- Capnp.Net.Runtime/SerializerState.cs | 126 ++++++------ Capnp.Net.Runtime/WirePointer.cs | 9 +- 15 files changed, 279 insertions(+), 102 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs b/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs index 82ab2d0..0a95dc6 100644 --- a/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs +++ b/Capnp.Net.Runtime.Tests/RpcSchemaTests.cs @@ -378,6 +378,10 @@ namespace Capnp.Net.Runtime.Tests var mb = MessageBuilder.Create(); var root = mb.BuildRoot(); obj.Serialize(root); + using (var tr = new FrameTracing.RpcFrameTracer(Console.Out)) + { + tr.TraceFrame(FrameTracing.FrameDirection.Tx, mb.Frame); + } var d = (DeserializerState)root; var obj2 = new TD(); obj2.Deserialize(d); diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs index 153feb8..67ae5bc 100644 --- a/Capnp.Net.Runtime.Tests/SerializationTests.cs +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -1,4 +1,5 @@ using Capnp.Net.Runtime.Tests.GenImpls; +using Capnp.Rpc; using Capnproto_test.Capnp.Test; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; @@ -229,7 +230,7 @@ namespace Capnp.Net.Runtime.Tests } [TestMethod] - public void ListOfStructs() + public void ListOfStructs1() { var b = MessageBuilder.Create(); var list = b.CreateObject>(); @@ -259,6 +260,19 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual("3", list3[3].SomeText); } + [TestMethod] + public void ListOfStructs2() + { + var b = MessageBuilder.Create(); + var list = b.CreateObject(); + list.SetListOfStructs(3, 4, 5); + list.SetListOfStructs(3, 4, 5); + Assert.ThrowsException(() => list.SetListOfStructs(1, 4, 5)); + Assert.ThrowsException(() => list.SetListOfStructs(3, 1, 5)); + Assert.ThrowsException(() => list.SetListOfStructs(3, 4, 1)); + Assert.ThrowsException(() => list.StructWriteData(0, 1, 1)); + } + [TestMethod] public void ListOfText() { @@ -741,5 +755,171 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => { var _ = list[0]; }); 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(() => dss.Rewrap()); + } + + [TestMethod] + public void SerializerStateInvalidRewrap2() + { + var dss = new DynamicSerializerState(); + dss.SetStruct(1, 0); + Assert.ThrowsException(() => dss.Rewrap()); + } + + [TestMethod] + public void SerializerStateInvalidRewrap3() + { + var dss = new DynamicSerializerState(); + dss.SetStruct(0, 1); + Assert.ThrowsException(() => dss.Rewrap()); + } + + [TestMethod] + public void SerializerStateInvalidRewrap4() + { + var dss = new DynamicSerializerState(); + dss.SetStruct(1, 0); + Assert.ThrowsException(() => dss.Rewrap()); + } + + [TestMethod] + public void UnboundSerializerState() + { + var dss = new DynamicSerializerState(); + dss.SetStruct(1, 0); + Assert.ThrowsException(() => dss.WriteData(0, 0)); + } + + [TestMethod] + public void LinkBadUsage1() + { + var mb = MessageBuilder.Create(); + var dss = mb.CreateObject(); + dss.SetStruct(0, 1); + Assert.ThrowsException(() => dss.Link(0, null)); + Assert.ThrowsException(() => dss.Link(-1, dss)); + Assert.ThrowsException(() => dss.Link(1, dss)); + dss.Link(0, dss); + Assert.ThrowsException(() => dss.Link(0, mb.CreateObject())); + } + + [TestMethod] + public void LinkBadUsage2() + { + var dss = new DynamicSerializerState(MessageBuilder.Create()); + dss.SetListOfPointers(1); + Assert.ThrowsException(() => dss.Link(0, null)); + Assert.ThrowsException(() => dss.Link(-1, dss)); + Assert.ThrowsException(() => dss.Link(1, dss)); + } + + [TestMethod] + public void StructReadCapNoCapTable() + { + var dss = new DynamicSerializerState(MessageBuilder.Create()); + dss.SetStruct(0, 1); + Assert.ThrowsException(() => dss.ReadCap(0)); + } + + [TestMethod] + public void StructReadCap() + { + var dss = DynamicSerializerState.CreateForRpc(); + dss.SetStruct(0, 3); + Assert.ThrowsException(() => dss.ReadCap(-1)); + Assert.ThrowsException(() => 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(0) is Proxy proxy && proxy.IsNull); + Assert.ThrowsException(() => dss.ReadCap(1)); + Assert.ThrowsException(() => dss.ReadCap(2)); + } + + [TestMethod] + public void Rewrap() + { + var mb = MessageBuilder.Create(); + var list1 = mb.CreateObject>(); + list1.Init(3); + var list2 = list1.Rewrap>(); + list2[0].WriteData(0, 0); + Assert.ThrowsException(() => list2.Rewrap()); + var obj = mb.CreateObject(); + var obj2 = obj.Rewrap(); + Assert.ThrowsException(() => obj2.Rewrap()); + } + + [TestMethod] + public void AllocatedNil() + { + var mb = MessageBuilder.Create(); + mb.InitCapTable(); + var dss = mb.CreateObject(); + dss.Allocate(); + Assert.ThrowsException(() => dss.SetCapability(0)); + dss.SetCapability(null); + Assert.ThrowsException(() => dss.SetListOfPointers(1)); + Assert.ThrowsException(() => dss.SetListOfStructs(1, 1, 1)); + Assert.ThrowsException(() => dss.SetListOfValues(8, 1)); + Assert.ThrowsException(() => dss.SetObject(mb.CreateObject())); + dss.SetObject(null); + Assert.ThrowsException(() => dss.SetStruct(1, 1)); + } + + [TestMethod] + public void SetCapability1() + { + var mb = MessageBuilder.Create(); + mb.InitCapTable(); + var dss = mb.CreateObject(); + dss.SetStruct(1, 1); + Assert.ThrowsException(() => dss.SetCapability(null)); + Assert.ThrowsException(() => dss.SetCapability(0)); + } + + [TestMethod] + public void SetCapability2() + { + var mb = MessageBuilder.Create(); + mb.InitCapTable(); + var dss = mb.CreateObject(); + dss.SetCapability(7); + dss.SetCapability(7); + Assert.ThrowsException(() => dss.SetCapability(8)); + Assert.ThrowsException(() => dss.SetCapability(null)); + } } } diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs index 90b4675..443beea 100644 --- a/Capnp.Net.Runtime.Tests/Testsuite.cs +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -571,12 +571,12 @@ namespace Capnp.Net.Runtime.Tests task1.Result.Dispose(); testbed.FlushCommunication(); - Assert.AreEqual(1, counters.HandleCount); + Assert.IsTrue(SpinWait.SpinUntil(() => counters.HandleCount == 1, TestBase.ShortTimeout)); task2.Result.Dispose(); testbed.FlushCommunication(); - Assert.AreEqual(0, counters.HandleCount); + Assert.IsTrue(SpinWait.SpinUntil(() => counters.HandleCount == 0, TestBase.ShortTimeout)); } } diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs index 735ae7e..6fbb996 100644 --- a/Capnp.Net.Runtime/DeserializerState.cs +++ b/Capnp.Net.Runtime/DeserializerState.cs @@ -49,7 +49,7 @@ namespace Capnp /// /// The capabilities imported from the capability table. Only valid in RPC context. /// - public IList? Caps { get; set; } + public IList? Caps { get; set; } /// /// Current segment (essentially Segments[CurrentSegmentIndex]) /// diff --git a/Capnp.Net.Runtime/DynamicSerializerState.cs b/Capnp.Net.Runtime/DynamicSerializerState.cs index fe750d9..d6092c6 100644 --- a/Capnp.Net.Runtime/DynamicSerializerState.cs +++ b/Capnp.Net.Runtime/DynamicSerializerState.cs @@ -79,7 +79,7 @@ namespace Capnp /// This state does neither describe a struct, nor a list of pointers /// Another state is already linked to the specified position (sorry, no overwrite allowed) /// - public new void LinkToCapability(int slot, uint capabilityIndex) => base.LinkToCapability(slot, capabilityIndex); + public new void LinkToCapability(int slot, uint? capabilityIndex) => base.LinkToCapability(slot, capabilityIndex); /// /// Determines the underlying object to be a struct. @@ -89,6 +89,8 @@ namespace Capnp /// The object type was already set to something different public new void SetStruct(ushort dataCount, ushort ptrCount) => base.SetStruct(dataCount, ptrCount); + public new void SetCapability(uint? capabilityIndex) => base.SetCapability(capabilityIndex); + /// /// Determines the underlying object to be a list of (primitive) values. /// diff --git a/Capnp.Net.Runtime/MessageBuilder.cs b/Capnp.Net.Runtime/MessageBuilder.cs index 6afb40e..ba2f556 100644 --- a/Capnp.Net.Runtime/MessageBuilder.cs +++ b/Capnp.Net.Runtime/MessageBuilder.cs @@ -10,7 +10,7 @@ namespace Capnp { readonly ISegmentAllocator _allocator; readonly DynamicSerializerState _rootPtrBuilder; - List? _capTable; + List? _capTable; MessageBuilder(ISegmentAllocator allocator) { @@ -92,13 +92,13 @@ namespace Capnp if (_capTable != null) throw new InvalidOperationException("Capability table was already initialized"); - _capTable = new List(); + _capTable = new List(); } /// /// Returns this message builder's segment allocator. /// public ISegmentAllocator Allocator => _allocator; - internal List? Caps => _capTable; + internal List? Caps => _capTable; } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index 4b73082..bddc2be 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -180,7 +180,7 @@ namespace Capnp.Rpc } } - public static async Task Unwrap(this TInterface cap) where TInterface: class, IDisposable + public static async Task Unwrap(this TInterface cap) where TInterface: class, IDisposable { using var proxy = cap as Proxy; @@ -188,6 +188,9 @@ namespace Capnp.Rpc return cap; var unwrapped = await proxy.ConsumedCap.Unwrap(); + if (unwrapped == null) + return null; + return ((CapabilityReflection.CreateProxy(unwrapped)) as TInterface)!; } diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index 6b11347..880b837 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -16,8 +16,6 @@ namespace Capnp.Rpc return new LazyCapability(Task.FromCanceled(token)); } - public static LazyCapability Null => CreateBrokenCap("Null capability"); - readonly Task? _proxyTask; public LazyCapability(Task capabilityTask) diff --git a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs index 4bc0f89..a195b0c 100644 --- a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs @@ -108,7 +108,7 @@ namespace Capnp.Rpc try { var cap = aorcq.Answer.Caps![(int)cur.CapabilityIndex]; - proxy = new Proxy(cap ?? LazyCapability.Null); + proxy = new Proxy(cap); } catch (ArgumentOutOfRangeException) { diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index 65616b0..53ec1af 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -197,16 +197,13 @@ namespace Capnp.Rpc /// Whether to Dispose() this Proxy instance /// Proxy for desired capability interface /// did not qualify as capability interface. - /// This capability is broken, or mismatch between generic type arguments (if capability interface is generic). + /// Mismatch between generic type arguments (if capability interface is generic). /// Mismatch between generic type arguments (if capability interface is generic). /// Problem with instatiating the Proxy (constructor threw exception). /// Caller does not have permission to invoke the Proxy constructor. /// Problem with building the Proxy type, or problem with loading some dependent class. public T Cast(bool disposeThis) where T: class { - if (IsNull) - throw new InvalidOperationException("Capability is broken"); - using (disposeThis ? this : null) { return (CapabilityReflection.CreateProxy(ConsumedCap) as T)!; diff --git a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs index 86c5fa8..23b3fab 100644 --- a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs @@ -5,13 +5,11 @@ namespace Capnp.Rpc { static class ResolvingCapabilityExtensions { - public static async Task Unwrap(this ConsumedCapability? cap) + public static async Task Unwrap(this ConsumedCapability? cap) { - cap ??= LazyCapability.Null; - while (cap is IResolvingCapability resolving) { - cap = await resolving.WhenResolved ?? LazyCapability.Null; + cap = await resolving.WhenResolved; } return cap; @@ -66,7 +64,7 @@ namespace Capnp.Rpc switch (obj) { case Proxy proxy: return proxy; - case null: return new Proxy(LazyCapability.Null); + case null: return new Proxy(null); default: return BareProxy.FromImpl(obj); } } diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index c59c3d8..e7e0df1 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -1347,9 +1347,9 @@ namespace Capnp.Rpc } } - internal IList ImportCapTable(Payload.READER payload) + internal IList ImportCapTable(Payload.READER payload) { - var list = new List(); + var list = new List(); if (payload.CapTable != null) { @@ -1378,16 +1378,8 @@ namespace Capnp.Rpc foreach (var cap in state.MsgBuilder.Caps) { var capDesc = payload.CapTable[i++]; - - if (cap == null) - { - LazyCapability.Null.Export(this, capDesc); - } - else - { - postAction += cap.Export(this, capDesc); - cap.Release(); - } + postAction += cap.Export(this, capDesc); + cap.Release(); } Tx(state.MsgBuilder.Frame); diff --git a/Capnp.Net.Runtime/Rpc/Vine.cs b/Capnp.Net.Runtime/Rpc/Vine.cs index 1542681..3572f6c 100644 --- a/Capnp.Net.Runtime/Rpc/Vine.cs +++ b/Capnp.Net.Runtime/Rpc/Vine.cs @@ -7,7 +7,7 @@ namespace Capnp.Rpc { class Vine : Skeleton { - public static Skeleton Create(ConsumedCapability cap) + public static Skeleton Create(ConsumedCapability? cap) { if (cap is LocalCapability lcap) return lcap.ProvidedCap; @@ -15,9 +15,9 @@ namespace Capnp.Rpc 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 CreatorStackTrace = Environment.StackTrace; diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index 42c5522..c89ca61 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -30,7 +30,7 @@ namespace Capnp internal MessageBuilder? MsgBuilder { get; set; } internal ISegmentAllocator? Allocator => MsgBuilder?.Allocator; - internal List? Caps => MsgBuilder?.Caps; + internal List? Caps => MsgBuilder?.Caps; internal SerializerState? Owner { get; set; } internal int OwnerSlot { 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 /// non-symmetric to DeserializerState.RawData. Never mind: You should not use it directly, anyway. /// - public Span RawData => SegmentSpan.Slice(Offset, (int)WordsAllocated); + public Span RawData => IsAllocated ? SegmentSpan.Slice(Offset, (int)WordsAllocated) : Span.Empty; /// /// The kind of object this state currently represents. @@ -170,12 +170,6 @@ namespace Capnp SegmentIndex = 0; Offset = 0; } - else if (Owner?.Kind == ObjectKind.ListOfStructs) - { - Owner.Allocate(); - SegmentIndex = Owner.SegmentIndex; - Offset = Owner.Offset + OwnerSlot + 1; - } else { 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) - throw new ArgumentNullException(nameof(target)); + if (Caps == null) + throw new InvalidOperationException("Capbility table not set"); - if (!target.IsAllocated) - throw new InvalidOperationException("Target must be allocated before a pointer can be built"); - - if (MsgBuilder == null) - throw Unbound(); - - try + if (!IsAllocated) { - if (SegmentSpan[offset] != 0) - throw new InvalidOperationException("Won't replace an already allocated pointer to prevent memory leaks and security flaws"); + return null; } - catch (IndexOutOfRangeException) + + WirePointer pointer = RawData[offset]; + + if (pointer.IsNull) { - throw new ArgumentOutOfRangeException(nameof(offset)); + 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) + { + throw new InvalidOperationException("Won't replace an already allocated pointer to prevent memory leaks and security flaws"); } 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]; - } - /// /// 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). @@ -471,7 +458,7 @@ namespace Capnp /// This state does neither describe a struct, nor a list of pointers /// Another state is already linked to the specified position (sorry, no overwrite allowed) /// - protected void LinkToCapability(int slot, uint capabilityIndex) + protected void LinkToCapability(int slot, uint? capabilityIndex) { var cstate = new SerializerState(); cstate.SetCapability(capabilityIndex); @@ -511,19 +498,29 @@ namespace Capnp } } - public void SetCapability(uint capabilityIndex) + protected void SetCapability(uint? capabilityIndex) { - if (Kind == ObjectKind.Nil) + if (capabilityIndex.HasValue) { - VerifyNotYetAllocated(); + if (Kind == ObjectKind.Nil) + { + VerifyNotYetAllocated(); - Kind = ObjectKind.Capability; - CapabilityIndex = capabilityIndex; - Allocate(); + Kind = ObjectKind.Capability; + CapabilityIndex = capabilityIndex.Value; + Allocate(); + } + else if (Kind != ObjectKind.Capability || CapabilityIndex != capabilityIndex) + { + throw AlreadySet(); + } } - else if (Kind != ObjectKind.Capability || CapabilityIndex != capabilityIndex) + else { - throw AlreadySet(); + if (Kind != ObjectKind.Nil) + { + throw AlreadySet(); + } } } @@ -1225,10 +1222,13 @@ namespace Capnp /// Adds an entry to the capability table if the provided capability does not yet exist. /// /// The low-level capability object to provide. - /// Index of the given capability in the capability table + /// Index of the given capability in the capability table, null if capability is null /// The underlying message builder was not configured for capability table support. - public uint ProvideCapability(Rpc.ConsumedCapability? capability) + public uint? ProvideCapability(Rpc.ConsumedCapability? capability) { + if (capability == null) + return null; + if (Caps == null) throw new InvalidOperationException("Underlying MessageBuilder was not enabled to support capabilities"); @@ -1252,7 +1252,7 @@ namespace Capnp /// The underlying message builder was not configured for capability table support. public uint ProvideCapability(Rpc.Skeleton capability) { - return ProvideCapability(Rpc.LocalCapability.Create(capability)); + return ProvideCapability(Rpc.LocalCapability.Create(capability))!.Value; } /// @@ -1267,12 +1267,12 @@ namespace Capnp /// /// Index of the given capability in the capability table /// The underlying message builder was not configured for capability table support. - public uint ProvideCapability(object? obj) + public uint? ProvideCapability(object? obj) { switch (obj) { case null: - return ProvideCapability(default(Rpc.ConsumedCapability)); + return null; case Rpc.Proxy proxy: using (proxy) return ProvideCapability(proxy.ConsumedCap); case Rpc.ConsumedCapability consumedCapability: @@ -1348,8 +1348,8 @@ namespace Capnp if (Kind != ObjectKind.Struct && Kind != ObjectKind.Nil) throw new InvalidOperationException("Allowed on structs only"); - if (index >= StructPtrCount) - return null; + if (index < 0 || index >= StructPtrCount) + throw new ArgumentOutOfRangeException(nameof(index)); return DecodeCapPointer(index + StructDataCount); } diff --git a/Capnp.Net.Runtime/WirePointer.cs b/Capnp.Net.Runtime/WirePointer.cs index 197886e..5f17dca 100644 --- a/Capnp.Net.Runtime/WirePointer.cs +++ b/Capnp.Net.Runtime/WirePointer.cs @@ -219,10 +219,13 @@ namespace Capnp /// /// Encodes a capability pointer. /// - /// capability index - public void SetCapability(uint index) + /// capability index, 'null' means 'null pointer' + public void SetCapability(uint? index) { - _ptrData = ((ulong)index << 32) | (ulong)PointerKind.Other; + if (index.HasValue) + _ptrData = ((ulong)index << 32) | (ulong)PointerKind.Other; + else + _ptrData = 0; } } } \ No newline at end of file From 955bab45e167ed0f91677bb4df17fe78b9adf6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Wed, 1 Apr 2020 22:15:46 +0200 Subject: [PATCH 24/76] generate GeneratedCodeAttribute --- Capnp.Net.Runtime/Rpc/rpc.cs | 45 +-- Capnp.Net.Runtime/SerializerState.cs | 2 +- .../Embedded Resources/test.cs | 375 +++++++++--------- .../Util/InlineAssemblyCompiler.cs | 1 + .../CodeGen/CodeGenerator.cs | 6 +- .../CodeGen/CommonSnippetGen.cs | 36 +- CapnpC.CSharp.Generator/CodeGen/GenNames.cs | 48 +++ .../CodeGen/GeneratorOptions.cs | 2 + .../CodeGen/InterfaceSnippetGen.cs | 3 +- 9 files changed, 268 insertions(+), 250 deletions(-) diff --git a/Capnp.Net.Runtime/Rpc/rpc.cs b/Capnp.Net.Runtime/Rpc/rpc.cs index 632c62e..d2d8c5f 100644 --- a/Capnp.Net.Runtime/Rpc/rpc.cs +++ b/Capnp.Net.Runtime/Rpc/rpc.cs @@ -1,8 +1,7 @@ -#pragma warning disable CS1591 - using Capnp; using Capnp.Rpc; using System; +using System.CodeDom.Compiler; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading; @@ -10,7 +9,7 @@ using System.Threading.Tasks; namespace Capnp.Rpc { - [TypeId(0x91b79f1f808db032UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x91b79f1f808db032UL)] public class Message : ICapnpSerializable { public const UInt64 typeId = 0x91b79f1f808db032UL; @@ -483,7 +482,7 @@ namespace Capnp.Rpc } } - [TypeId(0xe94ccf8031176ec4UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe94ccf8031176ec4UL)] public class Bootstrap : ICapnpSerializable { public const UInt64 typeId = 0xe94ccf8031176ec4UL; @@ -558,7 +557,7 @@ namespace Capnp.Rpc } } - [TypeId(0x836a53ce789d4cd4UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x836a53ce789d4cd4UL)] public class Call : ICapnpSerializable { public const UInt64 typeId = 0x836a53ce789d4cd4UL; @@ -707,7 +706,7 @@ namespace Capnp.Rpc } } - [TypeId(0xdae8b0f61aab5f99UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdae8b0f61aab5f99UL)] public class sendResultsTo : ICapnpSerializable { public const UInt64 typeId = 0xdae8b0f61aab5f99UL; @@ -832,7 +831,7 @@ namespace Capnp.Rpc } } - [TypeId(0x9e19b28d3db3573aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9e19b28d3db3573aUL)] public class Return : ICapnpSerializable { public const UInt64 typeId = 0x9e19b28d3db3573aUL; @@ -1072,7 +1071,7 @@ namespace Capnp.Rpc } } - [TypeId(0xd37d2eb2c2f80e63UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd37d2eb2c2f80e63UL)] public class Finish : ICapnpSerializable { public const UInt64 typeId = 0xd37d2eb2c2f80e63UL; @@ -1148,7 +1147,7 @@ namespace Capnp.Rpc } } - [TypeId(0xbbc29655fa89086eUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbbc29655fa89086eUL)] public class Resolve : ICapnpSerializable { public const UInt64 typeId = 0xbbc29655fa89086eUL; @@ -1301,7 +1300,7 @@ namespace Capnp.Rpc } } - [TypeId(0xad1a6c0d7dd07497UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xad1a6c0d7dd07497UL)] public class Release : ICapnpSerializable { public const UInt64 typeId = 0xad1a6c0d7dd07497UL; @@ -1376,7 +1375,7 @@ namespace Capnp.Rpc } } - [TypeId(0xf964368b0fbd3711UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf964368b0fbd3711UL)] public class Disembargo : ICapnpSerializable { public const UInt64 typeId = 0xf964368b0fbd3711UL; @@ -1449,7 +1448,7 @@ namespace Capnp.Rpc } } - [TypeId(0xd562b4df655bdd4dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd562b4df655bdd4dUL)] public class context : ICapnpSerializable { public const UInt64 typeId = 0xd562b4df655bdd4dUL; @@ -1619,7 +1618,7 @@ namespace Capnp.Rpc } } - [TypeId(0x9c6a046bfbc1ac5aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9c6a046bfbc1ac5aUL)] public class Provide : ICapnpSerializable { public const UInt64 typeId = 0x9c6a046bfbc1ac5aUL; @@ -1709,7 +1708,7 @@ namespace Capnp.Rpc } } - [TypeId(0xd4c9b56290554016UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd4c9b56290554016UL)] public class Accept : ICapnpSerializable { public const UInt64 typeId = 0xd4c9b56290554016UL; @@ -1799,7 +1798,7 @@ namespace Capnp.Rpc } } - [TypeId(0xfbe1980490e001afUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfbe1980490e001afUL)] public class Join : ICapnpSerializable { public const UInt64 typeId = 0xfbe1980490e001afUL; @@ -1889,7 +1888,7 @@ namespace Capnp.Rpc } } - [TypeId(0x95bc14545813fbc1UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x95bc14545813fbc1UL)] public class MessageTarget : ICapnpSerializable { public const UInt64 typeId = 0x95bc14545813fbc1UL; @@ -2025,7 +2024,7 @@ namespace Capnp.Rpc } } - [TypeId(0x9a0e61223d96743bUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9a0e61223d96743bUL)] public class Payload : ICapnpSerializable { public const UInt64 typeId = 0x9a0e61223d96743bUL; @@ -2100,7 +2099,7 @@ namespace Capnp.Rpc } } - [TypeId(0x8523ddc40b86b8b0UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8523ddc40b86b8b0UL)] public class CapDescriptor : ICapnpSerializable { public const UInt64 typeId = 0x8523ddc40b86b8b0UL; @@ -2326,7 +2325,7 @@ namespace Capnp.Rpc } } - [TypeId(0xd800b1d6cd6f1ca0UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd800b1d6cd6f1ca0UL)] public class PromisedAnswer : ICapnpSerializable { public const UInt64 typeId = 0xd800b1d6cd6f1ca0UL; @@ -2400,7 +2399,7 @@ namespace Capnp.Rpc } } - [TypeId(0xf316944415569081UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf316944415569081UL)] public class Op : ICapnpSerializable { public const UInt64 typeId = 0xf316944415569081UL; @@ -2517,7 +2516,7 @@ namespace Capnp.Rpc } } - [TypeId(0xd37007fde1f0027dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd37007fde1f0027dUL)] public class ThirdPartyCapDescriptor : ICapnpSerializable { public const UInt64 typeId = 0xd37007fde1f0027dUL; @@ -2592,7 +2591,7 @@ namespace Capnp.Rpc } } - [TypeId(0xd625b7063acf691aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd625b7063acf691aUL)] public class Exception : ICapnpSerializable { public const UInt64 typeId = 0xd625b7063acf691aUL; @@ -2696,7 +2695,7 @@ namespace Capnp.Rpc } } - [TypeId(0xb28c96e23f4cbd58UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb28c96e23f4cbd58UL)] public enum Type : ushort { failed, diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index c89ca61..b5323ee 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -282,7 +282,7 @@ namespace Capnp { Allocate(); - var targetCopy = new DynamicSerializerState(MsgBuilder); + var targetCopy = new DynamicSerializerState(MsgBuilder!); Reserializing.DeepCopy(target, targetCopy); target = targetCopy; } diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs index 2f482e4..919dabb 100644 --- a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs +++ b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs @@ -1,13 +1,14 @@ using Capnp; using Capnp.Rpc; using System; +using System.CodeDom.Compiler; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Capnproto_test.Capnp.Test { - [TypeId(0x9c8e9318b29d9cd3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9c8e9318b29d9cd3UL)] public enum TestEnum : ushort { foo, @@ -20,7 +21,7 @@ namespace Capnproto_test.Capnp.Test garply } - [TypeId(0xa0a8f314b80b63fdUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa0a8f314b80b63fdUL)] public class TestAllTypes : ICapnpSerializable { public const UInt64 typeId = 0xa0a8f314b80b63fdUL; @@ -545,7 +546,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xeb3f9ebe98c73cb6UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xeb3f9ebe98c73cb6UL)] public class TestDefaults : ICapnpSerializable { public const UInt64 typeId = 0xeb3f9ebe98c73cb6UL; @@ -1117,7 +1118,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe3da5a2ccd28c0d8UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe3da5a2ccd28c0d8UL)] public class TestAnyPointer : ICapnpSerializable { public const UInt64 typeId = 0xe3da5a2ccd28c0d8UL; @@ -1177,7 +1178,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf49850f63c2bfa59UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf49850f63c2bfa59UL)] public class TestAnyOthers : ICapnpSerializable { public const UInt64 typeId = 0xf49850f63c2bfa59UL; @@ -1267,7 +1268,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa9d5f8efe770022bUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa9d5f8efe770022bUL)] public class TestOutOfOrder : ICapnpSerializable { public const UInt64 typeId = 0xa9d5f8efe770022bUL; @@ -1447,7 +1448,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf47697362233ce52UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf47697362233ce52UL)] public class TestUnion : ICapnpSerializable { public const UInt64 typeId = 0xf47697362233ce52UL; @@ -1667,7 +1668,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfc76a82eecb7a718UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfc76a82eecb7a718UL)] public class union0 : ICapnpSerializable { public const UInt64 typeId = 0xfc76a82eecb7a718UL; @@ -2087,7 +2088,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xee0a6b99b7dc7ab2UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xee0a6b99b7dc7ab2UL)] public class union1 : ICapnpSerializable { public const UInt64 typeId = 0xee0a6b99b7dc7ab2UL; @@ -2669,7 +2670,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xafc5fd419f0d66d4UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xafc5fd419f0d66d4UL)] public class union2 : ICapnpSerializable { public const UInt64 typeId = 0xafc5fd419f0d66d4UL; @@ -2884,7 +2885,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa2fb022ec7f30053UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa2fb022ec7f30053UL)] public class union3 : ICapnpSerializable { public const UInt64 typeId = 0xa2fb022ec7f30053UL; @@ -3100,7 +3101,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9e2e784c915329b6UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9e2e784c915329b6UL)] public class TestUnnamedUnion : ICapnpSerializable { public const UInt64 typeId = 0x9e2e784c915329b6UL; @@ -3281,7 +3282,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x89a9494f1b900f22UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x89a9494f1b900f22UL)] public class TestUnionInUnion : ICapnpSerializable { public const UInt64 typeId = 0x89a9494f1b900f22UL; @@ -3339,7 +3340,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd005f6c63707670cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd005f6c63707670cUL)] public class outer : ICapnpSerializable { public const UInt64 typeId = 0xd005f6c63707670cUL; @@ -3471,7 +3472,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xff9ce111c6f8e5dbUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xff9ce111c6f8e5dbUL)] public class inner : ICapnpSerializable { public const UInt64 typeId = 0xff9ce111c6f8e5dbUL; @@ -3607,7 +3608,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdc841556134c3103UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdc841556134c3103UL)] public class TestGroups : ICapnpSerializable { public const UInt64 typeId = 0xdc841556134c3103UL; @@ -3665,7 +3666,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe22ae74ff9113268UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe22ae74ff9113268UL)] public class groups : ICapnpSerializable { public const UInt64 typeId = 0xe22ae74ff9113268UL; @@ -3822,7 +3823,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf5fcba89c0c1196fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf5fcba89c0c1196fUL)] public class foo : ICapnpSerializable { public const UInt64 typeId = 0xf5fcba89c0c1196fUL; @@ -3911,7 +3912,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf0fa30304066a4b3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf0fa30304066a4b3UL)] public class baz : ICapnpSerializable { public const UInt64 typeId = 0xf0fa30304066a4b3UL; @@ -4000,7 +4001,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb727c0d0091a001dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb727c0d0091a001dUL)] public class bar : ICapnpSerializable { public const UInt64 typeId = 0xb727c0d0091a001dUL; @@ -4091,7 +4092,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf77ed6f7454eec40UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf77ed6f7454eec40UL)] public class TestInterleavedGroups : ICapnpSerializable { public const UInt64 typeId = 0xf77ed6f7454eec40UL; @@ -4163,7 +4164,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc7485a3516c7d3c8UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc7485a3516c7d3c8UL)] public class group1 : ICapnpSerializable { public const UInt64 typeId = 0xc7485a3516c7d3c8UL; @@ -4368,7 +4369,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdb0afd413f4a313aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdb0afd413f4a313aUL)] public class corge : ICapnpSerializable { public const UInt64 typeId = 0xdb0afd413f4a313aUL; @@ -4473,7 +4474,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xcc85a335569990e9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xcc85a335569990e9UL)] public class group2 : ICapnpSerializable { public const UInt64 typeId = 0xcc85a335569990e9UL; @@ -4678,7 +4679,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa017f0366827ee37UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa017f0366827ee37UL)] public class corge : ICapnpSerializable { public const UInt64 typeId = 0xa017f0366827ee37UL; @@ -4784,7 +4785,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x94f7e0b103b4b718UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x94f7e0b103b4b718UL)] public class TestUnionDefaults : ICapnpSerializable { public const UInt64 typeId = 0x94f7e0b103b4b718UL; @@ -4905,7 +4906,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd9f2b5941a343bcdUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd9f2b5941a343bcdUL)] public class TestNestedTypes : ICapnpSerializable { public const UInt64 typeId = 0xd9f2b5941a343bcdUL; @@ -4996,14 +4997,14 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb651d2fba42056d4UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb651d2fba42056d4UL)] public enum NestedEnum : ushort { foo, bar } - [TypeId(0x82cd03a53b29d76bUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x82cd03a53b29d76bUL)] public class NestedStruct : ICapnpSerializable { public const UInt64 typeId = 0x82cd03a53b29d76bUL; @@ -5079,7 +5080,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xcfa0d546993a3df3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xcfa0d546993a3df3UL)] public enum NestedEnum : ushort { baz, @@ -5089,7 +5090,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe78aac389e77b065UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe78aac389e77b065UL)] public class TestUsing : ICapnpSerializable { public const UInt64 typeId = 0xe78aac389e77b065UL; @@ -5166,7 +5167,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe41885c94393277eUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe41885c94393277eUL)] public class TestLists : ICapnpSerializable { public const UInt64 typeId = 0xe41885c94393277eUL; @@ -5360,7 +5361,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8412c03b75b2cfeeUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8412c03b75b2cfeeUL)] public class Struct0 : ICapnpSerializable { public const UInt64 typeId = 0x8412c03b75b2cfeeUL; @@ -5405,7 +5406,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe0fe5870b141ad69UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe0fe5870b141ad69UL)] public class Struct1 : ICapnpSerializable { public const UInt64 typeId = 0xe0fe5870b141ad69UL; @@ -5465,7 +5466,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa6411a353090145bUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa6411a353090145bUL)] public class Struct8 : ICapnpSerializable { public const UInt64 typeId = 0xa6411a353090145bUL; @@ -5525,7 +5526,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa8abf7a82928986cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa8abf7a82928986cUL)] public class Struct16 : ICapnpSerializable { public const UInt64 typeId = 0xa8abf7a82928986cUL; @@ -5585,7 +5586,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xad7beedc4ed30742UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xad7beedc4ed30742UL)] public class Struct32 : ICapnpSerializable { public const UInt64 typeId = 0xad7beedc4ed30742UL; @@ -5645,7 +5646,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xef9a34f2ff7cc646UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xef9a34f2ff7cc646UL)] public class Struct64 : ICapnpSerializable { public const UInt64 typeId = 0xef9a34f2ff7cc646UL; @@ -5705,7 +5706,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc6abf1b0329e6227UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc6abf1b0329e6227UL)] public class StructP : ICapnpSerializable { public const UInt64 typeId = 0xc6abf1b0329e6227UL; @@ -5765,7 +5766,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x943a234ca336b16aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x943a234ca336b16aUL)] public class Struct0c : ICapnpSerializable { public const UInt64 typeId = 0x943a234ca336b16aUL; @@ -5825,7 +5826,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8991bc0e74a594cdUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8991bc0e74a594cdUL)] public class Struct1c : ICapnpSerializable { public const UInt64 typeId = 0x8991bc0e74a594cdUL; @@ -5900,7 +5901,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xed267416528c7a24UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xed267416528c7a24UL)] public class Struct8c : ICapnpSerializable { public const UInt64 typeId = 0xed267416528c7a24UL; @@ -5975,7 +5976,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9978837b037d58e6UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9978837b037d58e6UL)] public class Struct16c : ICapnpSerializable { public const UInt64 typeId = 0x9978837b037d58e6UL; @@ -6050,7 +6051,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xed5fa940f54a7904UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xed5fa940f54a7904UL)] public class Struct32c : ICapnpSerializable { public const UInt64 typeId = 0xed5fa940f54a7904UL; @@ -6125,7 +6126,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xbc743778f2597c7dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbc743778f2597c7dUL)] public class Struct64c : ICapnpSerializable { public const UInt64 typeId = 0xbc743778f2597c7dUL; @@ -6200,7 +6201,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc2e364a40182013dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc2e364a40182013dUL)] public class StructPc : ICapnpSerializable { public const UInt64 typeId = 0xc2e364a40182013dUL; @@ -6276,7 +6277,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x92fc29a80f3ddd5cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x92fc29a80f3ddd5cUL)] public class TestFieldZeroIsBit : ICapnpSerializable { public const UInt64 typeId = 0x92fc29a80f3ddd5cUL; @@ -6368,7 +6369,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa851ad32cbc2ffeaUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa851ad32cbc2ffeaUL)] public class TestListDefaults : ICapnpSerializable { public const UInt64 typeId = 0xa851ad32cbc2ffeaUL; @@ -6452,7 +6453,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa76e3c9bb7fd56d3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa76e3c9bb7fd56d3UL)] public class TestLateUnion : ICapnpSerializable { public const UInt64 typeId = 0xa76e3c9bb7fd56d3UL; @@ -6569,7 +6570,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x807280a2901aa079UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x807280a2901aa079UL)] public class theUnion : ICapnpSerializable { public const UInt64 typeId = 0x807280a2901aa079UL; @@ -6730,7 +6731,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc1973984dee98e3aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc1973984dee98e3aUL)] public class anotherUnion : ICapnpSerializable { public const UInt64 typeId = 0xc1973984dee98e3aUL; @@ -6892,7 +6893,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x95b30dd14e01dda8UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x95b30dd14e01dda8UL)] public class TestOldVersion : ICapnpSerializable { public const UInt64 typeId = 0x95b30dd14e01dda8UL; @@ -6982,7 +6983,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8ed75a7469f04ce3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8ed75a7469f04ce3UL)] public class TestNewVersion : ICapnpSerializable { public const UInt64 typeId = 0x8ed75a7469f04ce3UL; @@ -7104,7 +7105,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xbd5fe16e5170c492UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbd5fe16e5170c492UL)] public class TestOldUnionVersion : ICapnpSerializable { public const UInt64 typeId = 0xbd5fe16e5170c492UL; @@ -7220,7 +7221,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc7e4c513a975492bUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc7e4c513a975492bUL)] public class TestNewUnionVersion : ICapnpSerializable { public const UInt64 typeId = 0xc7e4c513a975492bUL; @@ -7353,7 +7354,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x86232c1de4513e84UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x86232c1de4513e84UL)] public class a : ICapnpSerializable { public const UInt64 typeId = 0x86232c1de4513e84UL; @@ -7469,7 +7470,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfaf781ef89a00e39UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfaf781ef89a00e39UL)] public class TestStructUnion : ICapnpSerializable { public const UInt64 typeId = 0xfaf781ef89a00e39UL; @@ -7527,7 +7528,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x992edc677bef5a3cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x992edc677bef5a3cUL)] public class un : ICapnpSerializable { public const UInt64 typeId = 0x992edc677bef5a3cUL; @@ -7661,7 +7662,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9daec9823f171085UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9daec9823f171085UL)] public class SomeStruct : ICapnpSerializable { public const UInt64 typeId = 0x9daec9823f171085UL; @@ -7737,7 +7738,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdec497819d097c3cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdec497819d097c3cUL)] public class TestPrintInlineStructs : ICapnpSerializable { public const UInt64 typeId = 0xdec497819d097c3cUL; @@ -7811,7 +7812,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8e4936003708dac2UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8e4936003708dac2UL)] public class InlineStruct : ICapnpSerializable { public const UInt64 typeId = 0x8e4936003708dac2UL; @@ -7887,7 +7888,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x91afd4a864dbb030UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x91afd4a864dbb030UL)] public class TestWholeFloatDefault : ICapnpSerializable { public const UInt64 typeId = 0x91afd4a864dbb030UL; @@ -7964,7 +7965,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9d5b8cd8de9922ebUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9d5b8cd8de9922ebUL)] public class TestGenerics : ICapnpSerializable where TFoo : class where TBar : class { public const UInt64 typeId = 0x9d5b8cd8de9922ebUL; @@ -8124,7 +8125,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb46a779beaf3384eUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb46a779beaf3384eUL)] public class ug : ICapnpSerializable { public const UInt64 typeId = 0xb46a779beaf3384eUL; @@ -8183,7 +8184,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf6a841117e19ac73UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf6a841117e19ac73UL)] public class Inner : ICapnpSerializable { public const UInt64 typeId = 0xf6a841117e19ac73UL; @@ -8258,7 +8259,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa9ab42b118d6d435UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa9ab42b118d6d435UL)] public class Inner2 : ICapnpSerializable where TBaz : class { public const UInt64 typeId = 0xa9ab42b118d6d435UL; @@ -8362,7 +8363,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb6a0829c762b06f3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb6a0829c762b06f3UL)] public class DeepNest : ICapnpSerializable where TQux : class { public const UInt64 typeId = 0xb6a0829c762b06f3UL; @@ -8466,7 +8467,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8839ed86c9794287UL), Proxy(typeof(DeepNestInterface_Proxy<>)), Skeleton(typeof(DeepNestInterface_Skeleton<>))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8839ed86c9794287UL), Proxy(typeof(DeepNestInterface_Proxy<>)), Skeleton(typeof(DeepNestInterface_Skeleton<>))] public interface IDeepNestInterface : IDisposable where TQuux : class { Task Call(CancellationToken cancellationToken_ = default); @@ -8510,7 +8511,7 @@ namespace Capnproto_test.Capnp.Test public static class DeepNestInterface where TQuux : class { - [TypeId(0xb84eecc799437049UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb84eecc799437049UL)] public class Params_Call : ICapnpSerializable { public const UInt64 typeId = 0xb84eecc799437049UL; @@ -8555,7 +8556,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe080f0fc54614f6fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe080f0fc54614f6fUL)] public class Result_Call : ICapnpSerializable { public const UInt64 typeId = 0xe080f0fc54614f6fUL; @@ -8603,7 +8604,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc9e749e8dd54da5cUL), Proxy(typeof(Interface_Proxy<>)), Skeleton(typeof(Interface_Skeleton<>))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc9e749e8dd54da5cUL), Proxy(typeof(Interface_Proxy<>)), Skeleton(typeof(Interface_Skeleton<>))] public interface IInterface : IDisposable where TQux : class { Task<(TQux, Capnproto_test.Capnp.Test.TestGenerics)> Call(Capnproto_test.Capnp.Test.TestGenerics.Inner2 arg_, CancellationToken cancellationToken_ = default); @@ -8656,7 +8657,7 @@ namespace Capnproto_test.Capnp.Test public static class Interface where TQux : class { - [TypeId(0xa5b46224e33581adUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa5b46224e33581adUL)] public class Result_Call : ICapnpSerializable { public const UInt64 typeId = 0xa5b46224e33581adUL; @@ -8732,7 +8733,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8e656edfb45ba6cfUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8e656edfb45ba6cfUL)] public class UseAliases : ICapnpSerializable { public const UInt64 typeId = 0x8e656edfb45ba6cfUL; @@ -8868,7 +8869,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa9b2b1f52dde845dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa9b2b1f52dde845dUL)] public class TestGenericsWrapper : ICapnpSerializable where TFoo : class where TBar : class { public const UInt64 typeId = 0xa9b2b1f52dde845dUL; @@ -8928,7 +8929,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf28f83667a557a04UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf28f83667a557a04UL)] public class TestGenericsWrapper2 : ICapnpSerializable { public const UInt64 typeId = 0xf28f83667a557a04UL; @@ -8988,7 +8989,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8b9717a3f8d85a9aUL), Proxy(typeof(TestImplicitMethodParams_Proxy)), Skeleton(typeof(TestImplicitMethodParams_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8b9717a3f8d85a9aUL), Proxy(typeof(TestImplicitMethodParams_Proxy)), Skeleton(typeof(TestImplicitMethodParams_Skeleton))] public interface ITestImplicitMethodParams : IDisposable { Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) @@ -9045,7 +9046,7 @@ namespace Capnproto_test.Capnp.Test public static class TestImplicitMethodParams { - [TypeId(0xf83f8caf54bdc486UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf83f8caf54bdc486UL)] public class Params_Call : ICapnpSerializable where TT : class where TU : class { public const UInt64 typeId = 0xf83f8caf54bdc486UL; @@ -9121,7 +9122,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdf9ccdeb81a704c9UL), Proxy(typeof(TestImplicitMethodParamsInGeneric_Proxy<>)), Skeleton(typeof(TestImplicitMethodParamsInGeneric_Skeleton<>))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdf9ccdeb81a704c9UL), Proxy(typeof(TestImplicitMethodParamsInGeneric_Proxy<>)), Skeleton(typeof(TestImplicitMethodParamsInGeneric_Skeleton<>))] public interface ITestImplicitMethodParamsInGeneric : IDisposable where TV : class { Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) @@ -9179,7 +9180,7 @@ namespace Capnproto_test.Capnp.Test public static class TestImplicitMethodParamsInGeneric where TV : class { - [TypeId(0x9aab8e25c808d71eUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9aab8e25c808d71eUL)] public class Params_Call : ICapnpSerializable where TT : class where TU : class { public const UInt64 typeId = 0x9aab8e25c808d71eUL; @@ -9255,7 +9256,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa54870440e919063UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa54870440e919063UL)] public class TestGenericsUnion : ICapnpSerializable where TFoo : class where TBar : class { public const UInt64 typeId = 0xa54870440e919063UL; @@ -9390,7 +9391,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9427b2a71030338fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9427b2a71030338fUL)] public class TestUseGenerics : ICapnpSerializable { public const UInt64 typeId = 0x9427b2a71030338fUL; @@ -9841,7 +9842,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc5598844441096dcUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc5598844441096dcUL)] public class TestEmptyStruct : ICapnpSerializable { public const UInt64 typeId = 0xc5598844441096dcUL; @@ -9886,7 +9887,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xabed745cd8c92095UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xabed745cd8c92095UL)] public class TestConstants : ICapnpSerializable { public const UInt64 typeId = 0xabed745cd8c92095UL; @@ -9931,7 +9932,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xddc280dbee9c99b3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddc280dbee9c99b3UL)] public class TestAnyPointerConstants : ICapnpSerializable { public const UInt64 typeId = 0xddc280dbee9c99b3UL; @@ -10036,7 +10037,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x88eb12a0e0af92b2UL), Proxy(typeof(TestInterface_Proxy)), Skeleton(typeof(TestInterface_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x88eb12a0e0af92b2UL), Proxy(typeof(TestInterface_Proxy)), Skeleton(typeof(TestInterface_Skeleton))] public interface ITestInterface : IDisposable { Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default); @@ -10135,7 +10136,7 @@ namespace Capnproto_test.Capnp.Test public static class TestInterface { - [TypeId(0xb874edc0d559b391UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb874edc0d559b391UL)] public class Params_Foo : ICapnpSerializable { public const UInt64 typeId = 0xb874edc0d559b391UL; @@ -10210,7 +10211,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb04fcaddab714ba4UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb04fcaddab714ba4UL)] public class Result_Foo : ICapnpSerializable { public const UInt64 typeId = 0xb04fcaddab714ba4UL; @@ -10270,7 +10271,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd044893357b42568UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd044893357b42568UL)] public class Params_Bar : ICapnpSerializable { public const UInt64 typeId = 0xd044893357b42568UL; @@ -10315,7 +10316,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9bf141df4247d52fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9bf141df4247d52fUL)] public class Result_Bar : ICapnpSerializable { public const UInt64 typeId = 0x9bf141df4247d52fUL; @@ -10360,7 +10361,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd9ac8abb2a91cfbcUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd9ac8abb2a91cfbcUL)] public class Params_Baz : ICapnpSerializable { public const UInt64 typeId = 0xd9ac8abb2a91cfbcUL; @@ -10420,7 +10421,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9b99d14f2f375b2dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9b99d14f2f375b2dUL)] public class Result_Baz : ICapnpSerializable { public const UInt64 typeId = 0x9b99d14f2f375b2dUL; @@ -10466,7 +10467,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe4e9bac98670b748UL), Proxy(typeof(TestExtends_Proxy)), Skeleton(typeof(TestExtends_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe4e9bac98670b748UL), Proxy(typeof(TestExtends_Proxy)), Skeleton(typeof(TestExtends_Skeleton))] public interface ITestExtends : Capnproto_test.Capnp.Test.ITestInterface { Task Qux(CancellationToken cancellationToken_ = default); @@ -10599,7 +10600,7 @@ namespace Capnproto_test.Capnp.Test public static class TestExtends { - [TypeId(0x83a4bc5471363f17UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x83a4bc5471363f17UL)] public class Params_Qux : ICapnpSerializable { public const UInt64 typeId = 0x83a4bc5471363f17UL; @@ -10644,7 +10645,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8e4b3d1a3e2753ddUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8e4b3d1a3e2753ddUL)] public class Result_Qux : ICapnpSerializable { public const UInt64 typeId = 0x8e4b3d1a3e2753ddUL; @@ -10689,7 +10690,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xacf67532a7e7bad9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xacf67532a7e7bad9UL)] public class Result_Corge : ICapnpSerializable { public const UInt64 typeId = 0xacf67532a7e7bad9UL; @@ -10734,7 +10735,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf3b834e851ea8af6UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf3b834e851ea8af6UL)] public class Params_Grault : ICapnpSerializable { public const UInt64 typeId = 0xf3b834e851ea8af6UL; @@ -10780,7 +10781,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x98d7e0ef61488783UL), Proxy(typeof(TestExtends2_Proxy)), Skeleton(typeof(TestExtends2_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x98d7e0ef61488783UL), Proxy(typeof(TestExtends2_Proxy)), Skeleton(typeof(TestExtends2_Skeleton))] public interface ITestExtends2 : Capnproto_test.Capnp.Test.ITestExtends { } @@ -10874,7 +10875,7 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 11013518732491786115UL; } - [TypeId(0xa5a404caa61d4cd0UL), Proxy(typeof(TestPipeline_Proxy)), Skeleton(typeof(TestPipeline_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa5a404caa61d4cd0UL), Proxy(typeof(TestPipeline_Proxy)), Skeleton(typeof(TestPipeline_Skeleton))] public interface ITestPipeline : IDisposable { Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint N, Capnproto_test.Capnp.Test.ITestInterface InCap, CancellationToken cancellationToken_ = default); @@ -10990,7 +10991,7 @@ namespace Capnproto_test.Capnp.Test public static class TestPipeline { - [TypeId(0xb0b29e51db0e26b1UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb0b29e51db0e26b1UL)] public class Box : ICapnpSerializable { public const UInt64 typeId = 0xb0b29e51db0e26b1UL; @@ -11050,7 +11051,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9442ad5a1d2c8acbUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9442ad5a1d2c8acbUL)] public class AnyBox : ICapnpSerializable { public const UInt64 typeId = 0x9442ad5a1d2c8acbUL; @@ -11110,7 +11111,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc7e8df5096257034UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc7e8df5096257034UL)] public class Params_GetCap : ICapnpSerializable { public const UInt64 typeId = 0xc7e8df5096257034UL; @@ -11185,7 +11186,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb2442a9e0ba28fdfUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb2442a9e0ba28fdfUL)] public class Result_GetCap : ICapnpSerializable { public const UInt64 typeId = 0xb2442a9e0ba28fdfUL; @@ -11260,7 +11261,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa604ee63cf37819fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa604ee63cf37819fUL)] public class Params_TestPointers : ICapnpSerializable { public const UInt64 typeId = 0xa604ee63cf37819fUL; @@ -11350,7 +11351,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8eda54756c6070d6UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8eda54756c6070d6UL)] public class Result_TestPointers : ICapnpSerializable { public const UInt64 typeId = 0x8eda54756c6070d6UL; @@ -11395,7 +11396,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf8e36b53ab093d4eUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf8e36b53ab093d4eUL)] public class Params_GetAnyCap : ICapnpSerializable { public const UInt64 typeId = 0xf8e36b53ab093d4eUL; @@ -11470,7 +11471,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xbf44b4c94c26ef79UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbf44b4c94c26ef79UL)] public class Result_GetAnyCap : ICapnpSerializable { public const UInt64 typeId = 0xbf44b4c94c26ef79UL; @@ -11546,7 +11547,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa0e77035bdff0051UL), Proxy(typeof(TestCallOrder_Proxy)), Skeleton(typeof(TestCallOrder_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa0e77035bdff0051UL), Proxy(typeof(TestCallOrder_Proxy)), Skeleton(typeof(TestCallOrder_Skeleton))] public interface ITestCallOrder : IDisposable { Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default); @@ -11596,7 +11597,7 @@ namespace Capnproto_test.Capnp.Test public static class TestCallOrder { - [TypeId(0x8f1e8cd56ceb74dcUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8f1e8cd56ceb74dcUL)] public class Params_GetCallSequence : ICapnpSerializable { public const UInt64 typeId = 0x8f1e8cd56ceb74dcUL; @@ -11656,7 +11657,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdedbb6bf3810eab7UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdedbb6bf3810eab7UL)] public class Result_GetCallSequence : ICapnpSerializable { public const UInt64 typeId = 0xdedbb6bf3810eab7UL; @@ -11717,7 +11718,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xddd699207eb8e23bUL), Proxy(typeof(TestTailCallee_Proxy)), Skeleton(typeof(TestTailCallee_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddd699207eb8e23bUL), Proxy(typeof(TestTailCallee_Proxy)), Skeleton(typeof(TestTailCallee_Skeleton))] public interface ITestTailCallee : IDisposable { Task Foo(int I, string T, CancellationToken cancellationToken_ = default); @@ -11771,7 +11772,7 @@ namespace Capnproto_test.Capnp.Test public static class TestTailCallee { - [TypeId(0xa9ed2e5a9fd53d19UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa9ed2e5a9fd53d19UL)] public class TailResult : ICapnpSerializable { public const UInt64 typeId = 0xa9ed2e5a9fd53d19UL; @@ -11861,7 +11862,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc5e1efc325614957UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc5e1efc325614957UL)] public class Params_Foo : ICapnpSerializable { public const UInt64 typeId = 0xc5e1efc325614957UL; @@ -11937,7 +11938,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x870bf40110ce3035UL), Proxy(typeof(TestTailCaller_Proxy)), Skeleton(typeof(TestTailCaller_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x870bf40110ce3035UL), Proxy(typeof(TestTailCaller_Proxy)), Skeleton(typeof(TestTailCaller_Skeleton))] public interface ITestTailCaller : IDisposable { Task Foo(int I, Capnproto_test.Capnp.Test.ITestTailCallee Callee, CancellationToken cancellationToken_ = default); @@ -11991,7 +11992,7 @@ namespace Capnproto_test.Capnp.Test public static class TestTailCaller { - [TypeId(0xb07a279515dc8ac5UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb07a279515dc8ac5UL)] public class Params_Foo : ICapnpSerializable { public const UInt64 typeId = 0xb07a279515dc8ac5UL; @@ -12067,7 +12068,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa38e5efe41e53a15UL), Proxy(typeof(TestHandle_Proxy)), Skeleton(typeof(TestHandle_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa38e5efe41e53a15UL), Proxy(typeof(TestHandle_Proxy)), Skeleton(typeof(TestHandle_Skeleton))] public interface ITestHandle : IDisposable { } @@ -12086,7 +12087,7 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 11785461720995412501UL; } - [TypeId(0xddc70bf9784133cfUL), Proxy(typeof(TestMoreStuff_Proxy)), Skeleton(typeof(TestMoreStuff_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddc70bf9784133cfUL), Proxy(typeof(TestMoreStuff_Proxy)), Skeleton(typeof(TestMoreStuff_Skeleton))] public interface ITestMoreStuff : Capnproto_test.Capnp.Test.ITestCallOrder { Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); @@ -12523,7 +12524,7 @@ namespace Capnproto_test.Capnp.Test public static class TestMoreStuff { - [TypeId(0x931ba418da60f6e4UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x931ba418da60f6e4UL)] public class Params_CallFoo : ICapnpSerializable { public const UInt64 typeId = 0x931ba418da60f6e4UL; @@ -12583,7 +12584,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9a28970beccecdd0UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9a28970beccecdd0UL)] public class Result_CallFoo : ICapnpSerializable { public const UInt64 typeId = 0x9a28970beccecdd0UL; @@ -12643,7 +12644,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfabc700c2ebe6378UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfabc700c2ebe6378UL)] public class Params_CallFooWhenResolved : ICapnpSerializable { public const UInt64 typeId = 0xfabc700c2ebe6378UL; @@ -12703,7 +12704,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa54ce1e9aa822f90UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa54ce1e9aa822f90UL)] public class Result_CallFooWhenResolved : ICapnpSerializable { public const UInt64 typeId = 0xa54ce1e9aa822f90UL; @@ -12763,7 +12764,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x94fe60465c95182bUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x94fe60465c95182bUL)] public class Params_NeverReturn : ICapnpSerializable { public const UInt64 typeId = 0x94fe60465c95182bUL; @@ -12823,7 +12824,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdef4e5fa6999c5dcUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdef4e5fa6999c5dcUL)] public class Result_NeverReturn : ICapnpSerializable { public const UInt64 typeId = 0xdef4e5fa6999c5dcUL; @@ -12883,7 +12884,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfe7c8fbb769d8e58UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfe7c8fbb769d8e58UL)] public class Params_Hold : ICapnpSerializable { public const UInt64 typeId = 0xfe7c8fbb769d8e58UL; @@ -12943,7 +12944,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf839fb1374d003c9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf839fb1374d003c9UL)] public class Result_Hold : ICapnpSerializable { public const UInt64 typeId = 0xf839fb1374d003c9UL; @@ -12988,7 +12989,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf8c5e5ef1edf83beUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf8c5e5ef1edf83beUL)] public class Params_CallHeld : ICapnpSerializable { public const UInt64 typeId = 0xf8c5e5ef1edf83beUL; @@ -13033,7 +13034,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe59935f160ac7578UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe59935f160ac7578UL)] public class Result_CallHeld : ICapnpSerializable { public const UInt64 typeId = 0xe59935f160ac7578UL; @@ -13093,7 +13094,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfeffc025fce317e3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfeffc025fce317e3UL)] public class Params_GetHeld : ICapnpSerializable { public const UInt64 typeId = 0xfeffc025fce317e3UL; @@ -13138,7 +13139,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xef4e146185af67ceUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xef4e146185af67ceUL)] public class Result_GetHeld : ICapnpSerializable { public const UInt64 typeId = 0xef4e146185af67ceUL; @@ -13198,7 +13199,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc07526f7e2e533b9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc07526f7e2e533b9UL)] public class Params_Echo : ICapnpSerializable { public const UInt64 typeId = 0xc07526f7e2e533b9UL; @@ -13258,7 +13259,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa6224536593d5b92UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa6224536593d5b92UL)] public class Result_Echo : ICapnpSerializable { public const UInt64 typeId = 0xa6224536593d5b92UL; @@ -13318,7 +13319,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa1cc32d87f3edeb1UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa1cc32d87f3edeb1UL)] public class Params_ExpectCancel : ICapnpSerializable { public const UInt64 typeId = 0xa1cc32d87f3edeb1UL; @@ -13378,7 +13379,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8a3eba1758c0916eUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8a3eba1758c0916eUL)] public class Result_ExpectCancel : ICapnpSerializable { public const UInt64 typeId = 0x8a3eba1758c0916eUL; @@ -13423,7 +13424,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x99160a25fa50fbf1UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x99160a25fa50fbf1UL)] public class Params_MethodWithDefaults : ICapnpSerializable { public const UInt64 typeId = 0x99160a25fa50fbf1UL; @@ -13515,7 +13516,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9c7e066f845a6c56UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9c7e066f845a6c56UL)] public class Result_MethodWithDefaults : ICapnpSerializable { public const UInt64 typeId = 0x9c7e066f845a6c56UL; @@ -13591,7 +13592,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xead024a301a092a1UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xead024a301a092a1UL)] public class Params_GetHandle : ICapnpSerializable { public const UInt64 typeId = 0xead024a301a092a1UL; @@ -13636,7 +13637,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc3490d75420a1fe8UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc3490d75420a1fe8UL)] public class Result_GetHandle : ICapnpSerializable { public const UInt64 typeId = 0xc3490d75420a1fe8UL; @@ -13696,7 +13697,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd8493f0e175d61f2UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd8493f0e175d61f2UL)] public class Params_GetNull : ICapnpSerializable { public const UInt64 typeId = 0xd8493f0e175d61f2UL; @@ -13741,7 +13742,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe6955d8ef1023671UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe6955d8ef1023671UL)] public class Result_GetNull : ICapnpSerializable { public const UInt64 typeId = 0xe6955d8ef1023671UL; @@ -13801,7 +13802,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x805df436f55dd07aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x805df436f55dd07aUL)] public class Params_GetEnormousString : ICapnpSerializable { public const UInt64 typeId = 0x805df436f55dd07aUL; @@ -13846,7 +13847,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x860e7512dc3925b0UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x860e7512dc3925b0UL)] public class Result_GetEnormousString : ICapnpSerializable { public const UInt64 typeId = 0x860e7512dc3925b0UL; @@ -13906,7 +13907,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfb92899aeb0ee74fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfb92899aeb0ee74fUL)] public class Params_MethodWithNullDefault : ICapnpSerializable { public const UInt64 typeId = 0xfb92899aeb0ee74fUL; @@ -13981,7 +13982,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8467348247305cf7UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8467348247305cf7UL)] public class Result_MethodWithNullDefault : ICapnpSerializable { public const UInt64 typeId = 0x8467348247305cf7UL; @@ -14027,7 +14028,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc07d8dcd80a69c0cUL), Proxy(typeof(TestMembrane_Proxy)), Skeleton(typeof(TestMembrane_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc07d8dcd80a69c0cUL), Proxy(typeof(TestMembrane_Proxy)), Skeleton(typeof(TestMembrane_Skeleton))] public interface ITestMembrane : IDisposable { Task MakeThing(CancellationToken cancellationToken_ = default); @@ -14201,7 +14202,7 @@ namespace Capnproto_test.Capnp.Test public static class TestMembrane { - [TypeId(0x9352e4e41f173917UL), Proxy(typeof(Thing_Proxy)), Skeleton(typeof(Thing_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9352e4e41f173917UL), Proxy(typeof(Thing_Proxy)), Skeleton(typeof(Thing_Skeleton))] public interface IThing : IDisposable { Task PassThrough(CancellationToken cancellationToken_ = default); @@ -14278,7 +14279,7 @@ namespace Capnproto_test.Capnp.Test public static class Thing { - [TypeId(0xff9bdcd05085d786UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xff9bdcd05085d786UL)] public class Params_PassThrough : ICapnpSerializable { public const UInt64 typeId = 0xff9bdcd05085d786UL; @@ -14323,7 +14324,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xee94bed3615ee745UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xee94bed3615ee745UL)] public class Params_Intercept : ICapnpSerializable { public const UInt64 typeId = 0xee94bed3615ee745UL; @@ -14369,7 +14370,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb0c6163faf291965UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb0c6163faf291965UL)] public class Result : ICapnpSerializable { public const UInt64 typeId = 0xb0c6163faf291965UL; @@ -14429,7 +14430,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd8ac2acc3ece6556UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd8ac2acc3ece6556UL)] public class Params_MakeThing : ICapnpSerializable { public const UInt64 typeId = 0xd8ac2acc3ece6556UL; @@ -14474,7 +14475,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe5d4904814ccbf29UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe5d4904814ccbf29UL)] public class Result_MakeThing : ICapnpSerializable { public const UInt64 typeId = 0xe5d4904814ccbf29UL; @@ -14534,7 +14535,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x945d9f634a6a29daUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x945d9f634a6a29daUL)] public class Params_CallPassThrough : ICapnpSerializable { public const UInt64 typeId = 0x945d9f634a6a29daUL; @@ -14609,7 +14610,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8749aac3375c5c71UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8749aac3375c5c71UL)] public class Params_CallIntercept : ICapnpSerializable { public const UInt64 typeId = 0x8749aac3375c5c71UL; @@ -14684,7 +14685,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x869a1b7ab34b42c9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x869a1b7ab34b42c9UL)] public class Params_Loopback : ICapnpSerializable { public const UInt64 typeId = 0x869a1b7ab34b42c9UL; @@ -14744,7 +14745,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xecd19398fd88ab5cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xecd19398fd88ab5cUL)] public class Result_Loopback : ICapnpSerializable { public const UInt64 typeId = 0xecd19398fd88ab5cUL; @@ -14804,7 +14805,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8f6bb30cc62917ffUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8f6bb30cc62917ffUL)] public class Params_WaitForever : ICapnpSerializable { public const UInt64 typeId = 0x8f6bb30cc62917ffUL; @@ -14849,7 +14850,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc343a4907280be01UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc343a4907280be01UL)] public class Result_WaitForever : ICapnpSerializable { public const UInt64 typeId = 0xc343a4907280be01UL; @@ -14895,7 +14896,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x949449ad7c11fa5cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x949449ad7c11fa5cUL)] public class TestContainMembrane : ICapnpSerializable { public const UInt64 typeId = 0x949449ad7c11fa5cUL; @@ -14970,7 +14971,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdd2b66a791a279f0UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdd2b66a791a279f0UL)] public class TestTransferCap : ICapnpSerializable { public const UInt64 typeId = 0xdd2b66a791a279f0UL; @@ -15029,7 +15030,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc7263e8f88844abcUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc7263e8f88844abcUL)] public class Element : ICapnpSerializable { public const UInt64 typeId = 0xc7263e8f88844abcUL; @@ -15105,7 +15106,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9ae342d394247cfcUL), Proxy(typeof(TestKeywordMethods_Proxy)), Skeleton(typeof(TestKeywordMethods_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9ae342d394247cfcUL), Proxy(typeof(TestKeywordMethods_Proxy)), Skeleton(typeof(TestKeywordMethods_Skeleton))] public interface ITestKeywordMethods : IDisposable { Task Delete(CancellationToken cancellationToken_ = default); @@ -15220,7 +15221,7 @@ namespace Capnproto_test.Capnp.Test public static class TestKeywordMethods { - [TypeId(0xca3a89cdeb6bd6b7UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xca3a89cdeb6bd6b7UL)] public class Params_Delete : ICapnpSerializable { public const UInt64 typeId = 0xca3a89cdeb6bd6b7UL; @@ -15265,7 +15266,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xeeb5843598307592UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xeeb5843598307592UL)] public class Result_Delete : ICapnpSerializable { public const UInt64 typeId = 0xeeb5843598307592UL; @@ -15310,7 +15311,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9cf5a8313c5db036UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9cf5a8313c5db036UL)] public class Params_Class : ICapnpSerializable { public const UInt64 typeId = 0x9cf5a8313c5db036UL; @@ -15355,7 +15356,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc0253868ac12e7d8UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc0253868ac12e7d8UL)] public class Result_Class : ICapnpSerializable { public const UInt64 typeId = 0xc0253868ac12e7d8UL; @@ -15400,7 +15401,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa4a08763833c7757UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa4a08763833c7757UL)] public class Params_Void : ICapnpSerializable { public const UInt64 typeId = 0xa4a08763833c7757UL; @@ -15445,7 +15446,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xde82773089c0aeabUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xde82773089c0aeabUL)] public class Result_Void : ICapnpSerializable { public const UInt64 typeId = 0xde82773089c0aeabUL; @@ -15490,7 +15491,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x99817360625e8ca3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x99817360625e8ca3UL)] public class Params_Return : ICapnpSerializable { public const UInt64 typeId = 0x99817360625e8ca3UL; @@ -15535,7 +15536,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb70872e07eaa992fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb70872e07eaa992fUL)] public class Result_Return : ICapnpSerializable { public const UInt64 typeId = 0xb70872e07eaa992fUL; @@ -15581,7 +15582,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xea72cc77253798cdUL), Proxy(typeof(TestAuthenticatedBootstrap_Proxy<>)), Skeleton(typeof(TestAuthenticatedBootstrap_Skeleton<>))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xea72cc77253798cdUL), Proxy(typeof(TestAuthenticatedBootstrap_Proxy<>)), Skeleton(typeof(TestAuthenticatedBootstrap_Skeleton<>))] public interface ITestAuthenticatedBootstrap : IDisposable where TVatId : class { Task GetCallerId(CancellationToken cancellationToken_ = default); @@ -15636,7 +15637,7 @@ namespace Capnproto_test.Capnp.Test public static class TestAuthenticatedBootstrap where TVatId : class { - [TypeId(0x8ec30e2451f1cffeUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8ec30e2451f1cffeUL)] public class Params_GetCallerId : ICapnpSerializable { public const UInt64 typeId = 0x8ec30e2451f1cffeUL; @@ -15681,7 +15682,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc71cf776034a3e67UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc71cf776034a3e67UL)] public class Result_GetCallerId : ICapnpSerializable { public const UInt64 typeId = 0xc71cf776034a3e67UL; @@ -15742,7 +15743,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xceba982cb629f6c2UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xceba982cb629f6c2UL)] public class TestSturdyRef : ICapnpSerializable { public const UInt64 typeId = 0xceba982cb629f6c2UL; @@ -15817,7 +15818,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe02d3bbe1010e342UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe02d3bbe1010e342UL)] public class TestSturdyRefHostId : ICapnpSerializable { public const UInt64 typeId = 0xe02d3bbe1010e342UL; @@ -15877,7 +15878,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xaeb2ad168e2f5697UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xaeb2ad168e2f5697UL)] public class TestSturdyRefObjectId : ICapnpSerializable { public const UInt64 typeId = 0xaeb2ad168e2f5697UL; @@ -15936,7 +15937,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xef428f2f67c4d439UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xef428f2f67c4d439UL)] public enum Tag : ushort { testInterface, @@ -15948,7 +15949,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9e5c574772b1d462UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9e5c574772b1d462UL)] public class TestProvisionId : ICapnpSerializable { public const UInt64 typeId = 0x9e5c574772b1d462UL; @@ -15993,7 +15994,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xea2fb7dca9cdbdeaUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xea2fb7dca9cdbdeaUL)] public class TestRecipientId : ICapnpSerializable { public const UInt64 typeId = 0xea2fb7dca9cdbdeaUL; @@ -16038,7 +16039,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa805157b98b65469UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa805157b98b65469UL)] public class TestThirdPartyCapId : ICapnpSerializable { public const UInt64 typeId = 0xa805157b98b65469UL; @@ -16083,7 +16084,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf4c58a8ebcd0f600UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf4c58a8ebcd0f600UL)] public class TestJoinResult : ICapnpSerializable { public const UInt64 typeId = 0xf4c58a8ebcd0f600UL; @@ -16128,7 +16129,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd1fd8e9caf2a5d58UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd1fd8e9caf2a5d58UL)] public class TestNameAnnotation : ICapnpSerializable { public const UInt64 typeId = 0xd1fd8e9caf2a5d58UL; @@ -16292,7 +16293,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x89d9d1626b34017cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x89d9d1626b34017cUL)] public class badlyNamedUnion : ICapnpSerializable { public const UInt64 typeId = 0x89d9d1626b34017cUL; @@ -16424,7 +16425,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc3594bce5b24b722UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc3594bce5b24b722UL)] public class badlyNamedGroup : ICapnpSerializable { public const UInt64 typeId = 0xc3594bce5b24b722UL; @@ -16469,7 +16470,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf610d1deb4c9e84aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf610d1deb4c9e84aUL)] public enum BadlyNamedEnum : ushort { foo, @@ -16477,7 +16478,7 @@ namespace Capnproto_test.Capnp.Test baz } - [TypeId(0xbe406b6341d52284UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbe406b6341d52284UL)] public class NestedStruct : ICapnpSerializable { public const UInt64 typeId = 0xbe406b6341d52284UL; @@ -16551,7 +16552,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf6cb3f9c7a4322e0UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf6cb3f9c7a4322e0UL)] public enum DeeplyNestedEnum : ushort { quux, @@ -16561,7 +16562,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd112a69d31ed918bUL), Proxy(typeof(TestNameAnnotationInterface_Proxy)), Skeleton(typeof(TestNameAnnotationInterface_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd112a69d31ed918bUL), Proxy(typeof(TestNameAnnotationInterface_Proxy)), Skeleton(typeof(TestNameAnnotationInterface_Skeleton))] public interface ITestNameAnnotationInterface : IDisposable { Task BadlyNamedMethod(byte BadlyNamedParam, CancellationToken cancellationToken_ = default); @@ -16605,7 +16606,7 @@ namespace Capnproto_test.Capnp.Test public static class TestNameAnnotationInterface { - [TypeId(0xc12efc3b075adfe9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc12efc3b075adfe9UL)] public class Params_BadlyNamedMethod : ICapnpSerializable { public const UInt64 typeId = 0xc12efc3b075adfe9UL; @@ -16665,7 +16666,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdcc3cdb4b28f6c86UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdcc3cdb4b28f6c86UL)] public class Result_BadlyNamedMethod : ICapnpSerializable { public const UInt64 typeId = 0xdcc3cdb4b28f6c86UL; diff --git a/CapnpC.CSharp.Generator.Tests/Util/InlineAssemblyCompiler.cs b/CapnpC.CSharp.Generator.Tests/Util/InlineAssemblyCompiler.cs index 2ab94cb..372b3d0 100644 --- a/CapnpC.CSharp.Generator.Tests/Util/InlineAssemblyCompiler.cs +++ b/CapnpC.CSharp.Generator.Tests/Util/InlineAssemblyCompiler.cs @@ -45,6 +45,7 @@ namespace CapnpC.CSharp.Generator.Tests.Util MetadataReference.CreateFromFile(Path.Combine(assemblyRoot, "mscorlib.dll")), MetadataReference.CreateFromFile(Path.Combine(assemblyRoot, "System.dll")), MetadataReference.CreateFromFile(Path.Combine(assemblyRoot, "System.Core.dll")), + MetadataReference.CreateFromFile(Path.Combine(assemblyRoot, "System.Diagnostics.Tools.dll")), MetadataReference.CreateFromFile(Path.Combine(assemblyRoot, "System.Runtime.dll")), MetadataReference.CreateFromFile(Path.Combine(assemblyRoot, "System.Private.CoreLib.dll")), MetadataReference.CreateFromFile(capnpRuntimePath) }, diff --git a/CapnpC.CSharp.Generator/CodeGen/CodeGenerator.cs b/CapnpC.CSharp.Generator/CodeGen/CodeGenerator.cs index a0ec9fc..c57b20b 100644 --- a/CapnpC.CSharp.Generator/CodeGen/CodeGenerator.cs +++ b/CapnpC.CSharp.Generator/CodeGen/CodeGenerator.cs @@ -81,8 +81,9 @@ .AddConstraintClauses(MakeTypeParameterConstraints(def).ToArray()); } - topDecl = topDecl.AddMembers(CommonSnippetGen.MakeTypeIdConst(def.Id, _names)); - topDecl = topDecl.WithAttributeLists(CommonSnippetGen.MakeTypeIdAttributeLists(def.Id)); + topDecl = topDecl + .AddMembers(_names.MakeTypeIdConst(def.Id)) + .AddAttributeLists(_names.MakeTypeDecorationAttributes(def.Id)); if (def.UnionInfo != null) { @@ -244,6 +245,7 @@ UsingDirective(ParseName("Capnp")), UsingDirective(ParseName("Capnp.Rpc")), UsingDirective(ParseName("System")), + UsingDirective(ParseName("System.CodeDom.Compiler")), UsingDirective(ParseName("System.Collections.Generic"))); if (_names.NullableEnable) diff --git a/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs b/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs index 549a272..2c6a172 100644 --- a/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs +++ b/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs @@ -50,7 +50,7 @@ namespace CapnpC.CSharp.Generator.CodeGen public EnumDeclarationSyntax MakeEnum(TypeDefinition def) { var decl = EnumDeclaration(_names.GetCodeIdentifier(def)) - .WithAttributeLists(MakeTypeIdAttributeLists(def.Id)) + .AddAttributeLists(_names.MakeTypeDecorationAttributes(def.Id)) .AddModifiers(_names.TypeVisibilityModifier) .AddBaseListTypes(SimpleBaseType(_names.Type(Nullability.NonNullable))); @@ -87,39 +87,5 @@ namespace CapnpC.CSharp.Generator.CodeGen yield return expr; } } - - static LiteralExpressionSyntax HexLiteral(ulong id) => - LiteralExpression( - SyntaxKind.NumericLiteralExpression, - Literal($"0x{id:x}UL", id)); - - public static FieldDeclarationSyntax MakeTypeIdConst(ulong id, GenNames names) => - FieldDeclaration( - VariableDeclaration( - IdentifierName("UInt64")) - .WithVariables( - SingletonSeparatedList( - VariableDeclarator(names.TypeIdField.Identifier) - .WithInitializer( - EqualsValueClause(HexLiteral(id)))))) - .WithModifiers( - TokenList( - new[]{ - Token(SyntaxKind.PublicKeyword), - Token(SyntaxKind.ConstKeyword)})); - - public static AttributeSyntax MakeTypeIdAttribute(ulong id) => - Attribute( - IdentifierName("TypeId")) - .WithArgumentList( - AttributeArgumentList( - SingletonSeparatedList( - AttributeArgument(HexLiteral(id))))); - - public static SyntaxList MakeTypeIdAttributeLists(ulong id) => - SingletonList( - AttributeList( - SingletonSeparatedList( - CommonSnippetGen.MakeTypeIdAttribute(id)))); } } diff --git a/CapnpC.CSharp.Generator/CodeGen/GenNames.cs b/CapnpC.CSharp.Generator/CodeGen/GenNames.cs index 688f49a..1c3ac6b 100644 --- a/CapnpC.CSharp.Generator/CodeGen/GenNames.cs +++ b/CapnpC.CSharp.Generator/CodeGen/GenNames.cs @@ -77,6 +77,9 @@ namespace CapnpC.CSharp.Generator.CodeGen public bool NullableEnable { get; set; } public bool EmitDomainClassesAndInterfaces { get; set; } public SupportedAnnotations.TypeVisibility TypeVisibility { get; set; } + public string GeneratorToolName { get; } + public string GeneratorToolVersion { get; } + public GenNames(GeneratorOptions options) { TopNamespace = new Name(options.TopNamespaceName).IdentifierName; @@ -115,6 +118,8 @@ namespace CapnpC.CSharp.Generator.CodeGen ProxyClassFormat = options.ProxyClassFormat; SkeletonClassFormat = options.SkeletonClassFormat; AwaitProxy = new Name(options.AwaitProxyName); + GeneratorToolName = options.GeneratorToolName; + GeneratorToolVersion = options.GeneratorToolVersion; } public Name MakeTypeName(TypeDefinition def, NameUsage usage = NameUsage.Default) @@ -729,5 +734,48 @@ namespace CapnpC.CSharp.Generator.CodeGen } } } + + static LiteralExpressionSyntax HexLiteral(ulong id) => + LiteralExpression( + SyntaxKind.NumericLiteralExpression, + Literal($"0x{id:x}UL", id)); + + static LiteralExpressionSyntax StringLiteral(string text) => + LiteralExpression( + SyntaxKind.StringLiteralExpression, + Literal(text)); + + public FieldDeclarationSyntax MakeTypeIdConst(ulong id) => + FieldDeclaration( + VariableDeclaration( + IdentifierName("UInt64")) + .WithVariables( + SingletonSeparatedList( + VariableDeclarator(TypeIdField.Identifier) + .WithInitializer( + EqualsValueClause(HexLiteral(id)))))) + .WithModifiers( + TokenList( + new[]{ + Token(SyntaxKind.PublicKeyword), + Token(SyntaxKind.ConstKeyword)})); + + static AttributeSyntax MakeTypeIdAttribute(ulong id) => + Attribute( + IdentifierName("TypeId")) + .WithArgumentList( + AttributeArgumentList( + SingletonSeparatedList( + AttributeArgument(HexLiteral(id))))); + + public AttributeSyntax MakeGeneratedCodeAttribute() => + Attribute( + IdentifierName("System.CodeDom.Compiler.GeneratedCode")) + .AddArgumentListArguments( + AttributeArgument(StringLiteral(GeneratorToolName)), + AttributeArgument(StringLiteral(GeneratorToolVersion))); + + public AttributeListSyntax MakeTypeDecorationAttributes(ulong typeId) => + AttributeList().AddAttributes(MakeGeneratedCodeAttribute(), MakeTypeIdAttribute(typeId)); } } diff --git a/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs b/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs index 178d41b..cd6061f 100644 --- a/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs +++ b/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs @@ -39,5 +39,7 @@ public string TypeIdFieldName { get; set; } = "typeId"; public string AwaitProxyName { get; set; } = "AwaitProxy"; public bool NullableEnableDefault { get; set; } = false; + public string GeneratorToolName { get; set; } = "capnpc-csharp"; + public string GeneratorToolVersion = ThisAssembly.AssemblyVersion; } } diff --git a/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs b/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs index 676a09d..d3f2076 100644 --- a/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs +++ b/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs @@ -99,9 +99,8 @@ namespace CapnpC.CSharp.Generator.CodeGen var ifaceDecl = InterfaceDeclaration(_names.MakeTypeName(type, NameUsage.Interface).Identifier) .AddModifiers(Public) .AddAttributeLists( - AttributeList() + _names.MakeTypeDecorationAttributes(type.Id) .AddAttributes( - CommonSnippetGen.MakeTypeIdAttribute(type.Id), Attribute(IdentifierName("Proxy")) .AddArgumentListArguments( AttributeArgument( From 2bfa620a2d3d080b6d1d29ebe77681215346c633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Thu, 2 Apr 2020 22:14:16 +0200 Subject: [PATCH 25/76] coverage + fixes --- Capnp.Net.Runtime.Tests/SerializationTests.cs | 161 +++++++++++++++++- Capnp.Net.Runtime/SerializerState.cs | 15 +- 2 files changed, 173 insertions(+), 3 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs index 67ae5bc..35983ca 100644 --- a/Capnp.Net.Runtime.Tests/SerializationTests.cs +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -16,7 +16,7 @@ namespace Capnp.Net.Runtime.Tests public class SerializationTests { [TestMethod] - public void ListOfBits() + public void ListOfBits1() { void CheckList(IEnumerable items) { @@ -69,6 +69,34 @@ namespace Capnp.Net.Runtime.Tests CheckList(list3); } + [TestMethod] + public void ListOfBits2() + { + var b = MessageBuilder.Create(); + var wrong = b.CreateObject(); + wrong.SetListOfValues(8, 7); + wrong.Allocate(); + Assert.ThrowsException(() => wrong.ListWriteValue(0, true)); + Assert.ThrowsException(() => wrong.ListWriteValues(new bool[7])); + var list = b.CreateObject(); + list.SetListOfValues(1, 70); + list.ListWriteValue(0, true); + Assert.ThrowsException(() => list.ListWriteValue(-1, true)); + Assert.ThrowsException(() => list.ListWriteValue(70, true)); + var values = new bool[70]; + values[63] = true; + values[65] = true; + list.ListWriteValues(values, true); + var los = list.Rewrap(); + Assert.IsTrue(!los[63]); + Assert.IsFalse(!los[64]); + Assert.IsTrue(!los[65]); + Assert.IsFalse(!los[66]); + Assert.ThrowsException(() => list.ListWriteValues(null)); + Assert.ThrowsException(() => list.ListWriteValues(new bool[1])); + Assert.ThrowsException(() => list.ListWriteValues(new bool[71])); + } + [TestMethod] public void ListOfCaps() { @@ -229,11 +257,72 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(3.0f, list3[3]); } + [TestMethod] + public void ListOfBytes() + { + var b = MessageBuilder.Create(); + var wrong = b.CreateObject(); + wrong.SetListOfValues(1, 64); + wrong.Allocate(); + Assert.ThrowsException(() => wrong.ListWriteValue(0, (byte)1)); + Assert.ThrowsException(() => wrong.ListGetBytes()); + var list = b.CreateObject(); + list.SetListOfValues(8, 3); + Assert.ThrowsException(() => list.ListWriteValue(-1, (byte)1)); + Assert.ThrowsException(() => list.ListWriteValue(64, (byte)1)); + list.ListWriteValue(1, (byte)1); + list.ListWriteValue(2, (byte)2); + CollectionAssert.AreEqual(new byte[] { 0, 1, 2 }, list.ListGetBytes().ToArray()); + } + + [TestMethod] + public void ListOfUShorts() + { + var b = MessageBuilder.Create(); + var wrong = b.CreateObject(); + wrong.SetListOfValues(1, 64); + wrong.Allocate(); + Assert.ThrowsException(() => wrong.ListWriteValue(0, (ushort)1)); + var list = b.CreateObject(); + list.SetListOfValues(16, 3); + Assert.ThrowsException(() => list.ListWriteValue(-1, (ushort)1)); + Assert.ThrowsException(() => list.ListWriteValue(64, (ushort)1)); + } + + [TestMethod] + public void ListOfUInts() + { + var b = MessageBuilder.Create(); + var wrong = b.CreateObject(); + wrong.SetListOfValues(1, 64); + wrong.Allocate(); + Assert.ThrowsException(() => wrong.ListWriteValue(0, 1u)); + var list = b.CreateObject(); + list.SetListOfValues(32, 3); + Assert.ThrowsException(() => list.ListWriteValue(-1, 1u)); + Assert.ThrowsException(() => list.ListWriteValue(64, 1u)); + } + + [TestMethod] + public void ListOfULongs() + { + var b = MessageBuilder.Create(); + var wrong = b.CreateObject(); + wrong.SetListOfValues(1, 64); + wrong.Allocate(); + Assert.ThrowsException(() => wrong.ListWriteValue(0, 1ul)); + var list = b.CreateObject(); + list.SetListOfValues(64, 3); + Assert.ThrowsException(() => list.ListWriteValue(-1, 1ul)); + Assert.ThrowsException(() => list.ListWriteValue(64, 1ul)); + } + [TestMethod] public void ListOfStructs1() { var b = MessageBuilder.Create(); var list = b.CreateObject>(); + Assert.ThrowsException(() => list.Init(-1)); Assert.ThrowsException(() => { var _ = list[0]; }); list.Init(4); @@ -273,6 +362,25 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => list.StructWriteData(0, 1, 1)); } + [TestMethod] + public void ListOfStructs3() + { + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + Assert.ThrowsException(() => list.Any()); + list.Init(3); + int i = 0; + foreach (var item in list) + { + item.SomeText = i.ToString(); + Assert.AreEqual(item, list[i]); + ++i; + } + Assert.AreEqual("0", list[0].SomeText); + Assert.AreEqual("1", list[1].SomeText); + Assert.AreEqual("2", list[2].SomeText); + } + [TestMethod] public void ListOfText() { @@ -844,11 +952,13 @@ namespace Capnp.Net.Runtime.Tests } [TestMethod] - public void StructReadCapNoCapTable() + public void NoCapTable() { var dss = new DynamicSerializerState(MessageBuilder.Create()); dss.SetStruct(0, 1); Assert.ThrowsException(() => dss.ReadCap(0)); + Assert.ThrowsException(() => dss.ProvideCapability(new TestInterfaceImpl2())); + Assert.ThrowsException(() => dss.ProvideCapability(new TestInterface_Skeleton())); } [TestMethod] @@ -921,5 +1031,52 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => dss.SetCapability(8)); Assert.ThrowsException(() => dss.SetCapability(null)); } + + [TestMethod] + public void StructReadData() + { + var mb = MessageBuilder.Create(); + var dss = mb.CreateObject(); + Assert.ThrowsException(() => dss.StructReadData(0, 1)); + dss.SetStruct(2, 0); + Assert.AreEqual(0ul, dss.StructReadData(0, 64)); + dss.Allocate(); + Assert.AreEqual(0ul, dss.StructReadData(0, 64)); + Assert.AreEqual(0ul, dss.StructReadData(256, 64)); + Assert.ThrowsException(() => dss.StructReadData(0, -1)); + Assert.ThrowsException(() => dss.StructReadData(1, 64)); + Assert.ThrowsException(() => dss.StructReadData(0, 65)); + Assert.ThrowsException(() => dss.StructReadData(ulong.MaxValue, 2)); + } + + [TestMethod] + public void TryGetPointer() + { + var mb = MessageBuilder.Create(); + var dss = mb.CreateObject(); + Assert.ThrowsException(() => dss.TryGetPointer(0)); + dss.SetStruct(0, 1); + Assert.IsNull(dss.TryGetPointer(0)); + Assert.ThrowsException(() => dss.TryGetPointer(1)); + } + + [TestMethod] + public void ListBuildStruct() + { + var mb = MessageBuilder.Create(); + var dss1 = mb.CreateObject(); + dss1.SetStruct(1, 1); + Assert.ThrowsException(() => dss1.ListBuildStruct(0)); + var dss2 = mb.CreateObject(); + dss2.SetListOfStructs(2, 1, 1); + var s0 = dss2.ListBuildStruct(0); + Assert.AreEqual(s0, dss2.ListBuildStruct(0)); + Assert.ThrowsException(() => dss2.ListBuildStruct(-1)); + Assert.ThrowsException(() => dss2.ListBuildStruct(2)); + var s1 = dss2.ListBuildStruct(1); + Assert.AreEqual(s1, dss2.ListBuildStruct(1)); + Assert.ThrowsException(() => dss2.ListBuildStruct(-1)); + Assert.ThrowsException(() => dss2.ListBuildStruct(2)); + } } } diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index b5323ee..b18ce3c 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -80,6 +80,7 @@ namespace Capnp { SegmentIndex = other.SegmentIndex; Offset = other.Offset; + WordsAllocated = other.WordsAllocated; ListElementCount = other.ListElementCount; StructDataCount = other.StructDataCount; StructPtrCount = other.StructPtrCount; @@ -712,6 +713,9 @@ namespace Capnp if (index >= data.Length) return 0; // Assume backwards-compatible change + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count)); + if (relBitOffset + count > 64) throw new ArgumentOutOfRangeException(nameof(count)); @@ -773,6 +777,9 @@ namespace Capnp if (Kind != ObjectKind.Struct && Kind != ObjectKind.ListOfPointers) throw new InvalidOperationException("This is not a struct or list of pointers"); + if (index < 0 || index >= _linkedStates!.Length) + throw new ArgumentOutOfRangeException(nameof(index)); + var state = _linkedStates![index]; if (state == null) return null; @@ -870,6 +877,9 @@ namespace Capnp if (Kind != ObjectKind.ListOfStructs) throw new InvalidOperationException("This is not a list of structs"); + if (index < 0 || index >= _linkedStates!.Length) + throw new ArgumentOutOfRangeException(nameof(index)); + ref var state = ref _linkedStates![index]; if (state == null) @@ -897,6 +907,9 @@ namespace Capnp if (Kind != ObjectKind.ListOfStructs) throw new InvalidOperationException("This is not a list of structs"); + if (index < 0 || index >= _linkedStates!.Length) + throw new ArgumentOutOfRangeException(nameof(index)); + ref var state = ref _linkedStates![index]; if (state == null) @@ -1045,7 +1058,7 @@ namespace Capnp /// /// The list bytes /// The underlying object was not set to a list of bytes. - Span ListGetBytes() + public Span ListGetBytes() { if (Kind != ObjectKind.ListOfBytes) throw new InvalidOperationException("This is not a list of bytes"); From 4bf0e970c2f25b4c1e33ba63f6e219bb0e702d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Fri, 3 Apr 2020 21:34:21 +0200 Subject: [PATCH 26/76] more tests --- .../Mock/TestCapImplementations.cs | 1 + Capnp.Net.Runtime.Tests/SerializationTests.cs | 62 ++++++++++++++++++- Capnp.Net.Runtime/SerializerState.cs | 2 +- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs index dbd91c5..bb93eef 100644 --- a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs @@ -449,6 +449,7 @@ namespace Capnp.Net.Runtime.Tests.GenImpls public void Dispose() { + Assert.IsFalse(IsDisposed); IsDisposed = true; } diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs index 35983ca..64a2835 100644 --- a/Capnp.Net.Runtime.Tests/SerializationTests.cs +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -962,7 +962,7 @@ namespace Capnp.Net.Runtime.Tests } [TestMethod] - public void StructReadCap() + public void StructReadCap1() { var dss = DynamicSerializerState.CreateForRpc(); dss.SetStruct(0, 3); @@ -978,6 +978,15 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => dss.ReadCap(2)); } + [TestMethod] + public void StructReadCap2() + { + var dss = DynamicSerializerState.CreateForRpc(); + dss.SetListOfStructs(1, 1, 1); + dss.Allocate(); + Assert.ThrowsException(() => dss.ReadCap(0)); + } + [TestMethod] public void Rewrap() { @@ -1078,5 +1087,56 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => dss2.ListBuildStruct(-1)); Assert.ThrowsException(() => dss2.ListBuildStruct(2)); } + + [TestMethod] + public void LinkObject() + { + var mb = MessageBuilder.Create(); + var dss = mb.CreateObject(); + dss.SetStruct(0, 4); + var s1 = mb.CreateObject(); + s1.SomeText = "foo"; + s1.MoreText = "bar"; + dss.LinkObject(0, s1); + var s2 = mb.CreateObject(); + s2.SomeText = "baz"; + s2.MoreText = "foobar"; + var d = (DeserializerState)s2; + dss.LinkObject(1, d); + var s3 = mb.CreateObject(); + s3.SomeText = "0"; + var s4 = mb.CreateObject(); + s4.SomeText = "1"; + var arr = new SomeStruct.WRITER[] { s3, s4 }; + dss.LinkObject(2, arr); + Assert.ThrowsException(() => dss.LinkObject(3, new object())); + + var t1 = dss.BuildPointer(0).Rewrap(); + Assert.AreEqual("foo", t1.SomeText); + Assert.AreEqual("bar", t1.MoreText); + var t2 = dss.BuildPointer(1).Rewrap(); + Assert.AreEqual("baz", t2.SomeText); + Assert.AreEqual("foobar", t2.MoreText); + var l = dss.BuildPointer(2).Rewrap>(); + Assert.AreEqual(2, l.Count); + Assert.AreEqual("0", l[0].SomeText); + Assert.AreEqual("1", l[1].SomeText); + Assert.AreEqual(ObjectKind.Nil, dss.BuildPointer(3).Kind); + } + + [TestMethod] + public void Disposing() + { + var mb = MessageBuilder.Create(); + var dss = mb.CreateObject(); + dss.Dispose(); + dss.Dispose(); + var dss2 = DynamicSerializerState.CreateForRpc(); + var cap = new TestInterfaceImpl2(); + dss2.ProvideCapability(cap); + dss2.Dispose(); + Assert.IsTrue(cap.IsDisposed); + dss2.Dispose(); + } } } diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index b18ce3c..c717f15 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -1404,7 +1404,7 @@ namespace Capnp { foreach (var cap in Caps) { - cap?.Release(); + cap.Release(); } Caps.Clear(); From d7f937a9c013c6cdb2ef8dde96d65348a2b61d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Fri, 3 Apr 2020 22:10:40 +0200 Subject: [PATCH 27/76] refactored IResolvingCapability to hide ConsumedCapability --- Capnp.Net.Runtime/Rpc/IResolvingCapability.cs | 11 +++++-- Capnp.Net.Runtime/Rpc/LazyCapability.cs | 32 +++++++++++++++---- .../Rpc/LocalAnswerCapability.cs | 7 ++-- Capnp.Net.Runtime/Rpc/PromisedCapability.cs | 5 +-- Capnp.Net.Runtime/Rpc/Proxy.cs | 24 ++++++++++---- .../Rpc/RemoteAnswerCapability.cs | 18 +++-------- .../Rpc/RemoteResolvingCapability.cs | 3 +- .../Rpc/ResolvingCapabilityExtensions.cs | 27 ++++++++++++++-- 8 files changed, 90 insertions(+), 37 deletions(-) diff --git a/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs b/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs index cc26602..b3dc986 100644 --- a/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs @@ -8,8 +8,15 @@ namespace Capnp.Rpc public interface IResolvingCapability { /// - /// Will eventually give the resolved capability. + /// Completes when the capability gets resolved. /// - Task WhenResolved { get; } + Task WhenResolved { get; } + + /// + /// Returns the resolved capability + /// + /// Capability interface or + /// the resolved capability, or null if it did not resolve yet + T? GetResolvedCapability() where T: class; } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index 880b837..3e11953 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -17,10 +17,11 @@ namespace Capnp.Rpc } readonly Task? _proxyTask; + readonly Task _capTask; public LazyCapability(Task capabilityTask) { - WhenResolved = capabilityTask; + _capTask = capabilityTask; } public LazyCapability(Task proxyTask) @@ -29,7 +30,7 @@ namespace Capnp.Rpc async Task AwaitCap() => (await _proxyTask!).ConsumedCap; - WhenResolved = AwaitCap(); + _capTask = AwaitCap(); } internal override void Freeze(out IRpcEndpoint? boundEndpoint) @@ -40,7 +41,7 @@ namespace Capnp.Rpc try { - WhenResolved.Result?.Freeze(out boundEndpoint); + _capTask.Result?.Freeze(out boundEndpoint); } catch (AggregateException exception) { @@ -61,7 +62,7 @@ namespace Capnp.Rpc { if (WhenResolved.ReplacementTaskIsCompletedSuccessfully()) { - using var proxy = new Proxy(WhenResolved.Result); + using var proxy = GetResolvedCapability()!; return proxy.Export(endpoint, writer); } else @@ -84,14 +85,33 @@ namespace Capnp.Rpc } } - public Task WhenResolved { get; } + public Task WhenResolved => _capTask; + + public T? GetResolvedCapability() where T: class + { + if (_capTask.IsCompleted) + { + try + { + return CapabilityReflection.CreateProxy(_capTask.Result) as T; + } + catch (AggregateException exception) + { + throw exception.InnerException!; + } + } + else + { + return null; + } + } async Task CallImpl(ulong interfaceId, ushort methodId, DynamicSerializerState args, CancellationToken cancellationToken) { ConsumedCapability? cap; try { - cap = await WhenResolved; + cap = await _capTask; } catch { diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs index 08a5437..e29a1b3 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs @@ -21,9 +21,6 @@ namespace Capnp.Rpc public LocalAnswerCapability(Task proxyTask) { _whenResolvedProxy = proxyTask; - - async Task AwaitResolved() => (await _whenResolvedProxy).ConsumedCap; - WhenResolved = AwaitResolved(); } public LocalAnswerCapability(Task answer, MemberAccessPath access): @@ -42,7 +39,9 @@ namespace Capnp.Rpc } - public Task WhenResolved { get; private set; } + public Task WhenResolved => _whenResolvedProxy; + + public T? GetResolvedCapability() where T : class => _whenResolvedProxy.GetResolvedCapability(); internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { diff --git a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs index 0099383..0b5bfbf 100644 --- a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs @@ -16,11 +16,12 @@ namespace Capnp.Rpc { _remoteId = remoteId; - async Task AwaitProxy() => new Proxy(await WhenResolved); + async Task AwaitProxy() => new Proxy(await _resolvedCap.Task); _whenResolvedProxy = AwaitProxy(); } - public override Task WhenResolved => _resolvedCap.Task; + public override Task WhenResolved => _resolvedCap.Task; + public override T? GetResolvedCapability() where T: class => _whenResolvedProxy.GetResolvedCapability(); internal override void Freeze(out IRpcEndpoint? boundEndpoint) { diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index 53ec1af..34f09c1 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -17,7 +17,7 @@ namespace Capnp.Rpc /// Capability interface /// instance to share /// - public static T Share(T obj) where T: class + public static T Share(T obj) where T : class { if (obj is Proxy proxy) return proxy.Cast(false); @@ -32,18 +32,30 @@ namespace Capnp.Rpc bool _disposedValue = false; /// - /// Will eventually give the resolved capability, if this is a promised capability. + /// Completes when the capability gets resolved. /// - public Task WhenResolved + public Task WhenResolved { get { - return ConsumedCap is IResolvingCapability resolving ? - resolving.WhenResolved : - Task.FromResult(ConsumedCap); + return ConsumedCap is IResolvingCapability resolving ? + resolving.WhenResolved : Task.CompletedTask; } } + /// + /// Returns the resolved capability + /// + /// Capability interface or + /// the resolved capability, or null if it did not resolve yet + public T? GetResolvedCapability() where T : class + { + if (ConsumedCap is IResolvingCapability resolving) + return resolving.GetResolvedCapability(); + else + return CapabilityReflection.CreateProxy(ConsumedCap) as T; + } + /// /// Underlying low-level capability /// diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index fd47935..734899b 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -23,18 +23,6 @@ namespace Capnp.Rpc _question = question ?? throw new ArgumentNullException(nameof(question)); _access = access ?? throw new ArgumentNullException(nameof(access)); _whenResolvedProxy = proxyTask ?? throw new ArgumentNullException(nameof(proxyTask)); - - async Task AwaitWhenResolved() - { - var proxy = await _whenResolvedProxy; - - if (_question.IsTailCall) - throw new InvalidOperationException("Question is a tail call, so won't resolve back."); - - return proxy.ConsumedCap; - } - - WhenResolved = AwaitWhenResolved(); } static async Task TransferOwnershipToDummyProxy(PendingQuestion question, MemberAccessPath access) @@ -81,7 +69,7 @@ namespace Capnp.Rpc { try { - return WhenResolved.Result; + return _whenResolvedProxy.Result.ConsumedCap; } catch (AggregateException exception) { @@ -96,7 +84,9 @@ namespace Capnp.Rpc } } - public override Task WhenResolved { get; } + public override Task WhenResolved => _whenResolvedProxy; + + public override T? GetResolvedCapability() where T: class => _whenResolvedProxy.GetResolvedCapability(); protected override void GetMessageTarget(MessageTarget.WRITER wr) { diff --git a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs index b6a9cf8..6f3ba0b 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs @@ -16,7 +16,8 @@ namespace Capnp.Rpc ILogger Logger { get; } = Logging.CreateLogger(); #endif - public abstract Task WhenResolved { get; } + public abstract Task WhenResolved { get; } + public abstract T? GetResolvedCapability() where T : class; protected RemoteResolvingCapability(IRpcEndpoint ep) : base(ep) { diff --git a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs index 23b3fab..7fae258 100644 --- a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs @@ -9,7 +9,9 @@ namespace Capnp.Rpc { while (cap is IResolvingCapability resolving) { - cap = await resolving.WhenResolved; + await resolving.WhenResolved; + using var proxy = resolving.GetResolvedCapability()!; + cap = proxy.ConsumedCap; } return cap; @@ -30,7 +32,9 @@ namespace Capnp.Rpc try { - var resolvedCap = await Unwrap(await cap.WhenResolved); + await cap.WhenResolved; + using var proxy = cap.GetResolvedCapability()!; + var resolvedCap = await Unwrap(proxy.ConsumedCap); endpoint.Resolve(preliminaryId, vine, () => resolvedCap!); } catch (System.Exception exception) @@ -68,5 +72,24 @@ namespace Capnp.Rpc default: return BareProxy.FromImpl(obj); } } + + public static T? GetResolvedCapability(this Task proxyTask) where T: class + { + if (proxyTask.IsCompleted) + { + try + { + return proxyTask.Result.Cast(false); + } + catch (AggregateException exception) + { + throw exception.InnerException!; + } + } + else + { + return null; + } + } } } \ No newline at end of file From fef879de9f820f414d0e694033bb2f7c5e3c927c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 4 Apr 2020 14:55:31 +0200 Subject: [PATCH 28/76] tests + fixes --- .../DeserializationTests.cs | 177 ++++++++++++++- Capnp.Net.Runtime.Tests/TcpRpc.cs | 212 +++++++++++++----- Capnp.Net.Runtime/DeserializerState.cs | 16 +- .../FrameTracing/RpcFrameTracer.cs | 16 +- 4 files changed, 356 insertions(+), 65 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/DeserializationTests.cs b/Capnp.Net.Runtime.Tests/DeserializationTests.cs index d9b2861..1f286b7 100644 --- a/Capnp.Net.Runtime.Tests/DeserializationTests.cs +++ b/Capnp.Net.Runtime.Tests/DeserializationTests.cs @@ -1,4 +1,5 @@ -using Capnproto_test.Capnp.Test; +using Capnp.Net.Runtime.Tests.GenImpls; +using Capnproto_test.Capnp.Test; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; @@ -791,5 +792,179 @@ namespace Capnp.Net.Runtime.Tests var kind = loed.Cast(_ => _.Kind).Take(1).Single(); Assert.AreEqual(ObjectKind.Nil, kind); } + + [TestMethod] + public void DeserializerStateBadConv() + { + SerializerState s = null; + Assert.ThrowsException(() => (DeserializerState)s); + s = new DynamicSerializerState(); + Assert.ThrowsException(() => (DeserializerState)s); + } + + [TestMethod] + public void BadPointers() + { + var data = new ulong[1]; + var wf = new WireFrame(new Memory[] { new Memory(data) }); + var d0 = DeserializerState.CreateRoot(wf); + Assert.AreEqual(ObjectKind.Nil, d0.Kind); + WirePointer p = default; + p.BeginStruct(1, 0); + p.Offset = 0; + data[0] = p; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + p.BeginList(ListKind.ListOfBits, 64); + data[0] = p; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + p.BeginList(ListKind.ListOfBytes, 8); + data[0] = p; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + p.BeginList(ListKind.ListOfEmpty, 6400); + data[0] = p; + var d1 = DeserializerState.CreateRoot(wf); + p.BeginList(ListKind.ListOfInts, 2); + data[0] = p; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + p.BeginList(ListKind.ListOfLongs, 1); + data[0] = p; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + p.BeginList(ListKind.ListOfPointers, 1); + data[0] = p; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + p.BeginList(ListKind.ListOfShorts, 4); + data[0] = p; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + p.BeginList(ListKind.ListOfStructs, 1); + data[0] = p; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + p.SetFarPointer(0, 0, false); + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + p.SetFarPointer(1, 0, false); + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + p.SetFarPointer(0, 1, false); + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + p.SetFarPointer(0, 0, true); + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); + + var data2 = new ulong[3]; + var wf2 = new WireFrame(new Memory[] { new Memory(data2) }); + p.BeginList(ListKind.ListOfStructs, 1); + data2[0] = p; + data2[1] = p; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf2)); + + p.SetFarPointer(0, 1, true); + data2[0] = p; + data2[1] = 0; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf2)); + + p.SetFarPointer(0, 1, false); + data2[1] = p; + data2[2] = p; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf2)); + + p.SetFarPointer(0, 2, true); + data2[0] = p; + Assert.ThrowsException(() => DeserializerState.CreateRoot(wf2)); + } + + [TestMethod] + public void ReadCap1() + { + var mb = MessageBuilder.Create(); + var dss = mb.CreateObject(); + dss.SetStruct(0, 1); + DeserializerState ds = dss; + Assert.ThrowsException(() => ds.ReadCap(-1)); + Assert.ThrowsException(() => ds.ReadCap(0)); + } + + [TestMethod] + public void ReadCap2() + { + var mb = MessageBuilder.Create(); + mb.InitCapTable(); + var dss1 = mb.CreateObject(); + var dss2 = mb.CreateObject(); + dss2.SetStruct(1, 1); + dss1.SetStruct(0, 2); + dss1.Link(0, dss2); + dss1.LinkToCapability(1, 7); + var d = (DeserializerState)dss1; + Assert.ThrowsException(() => d.ReadCap(0)); + Assert.ThrowsException(() => d.ReadCap(1)); + } + + [TestMethod] + public void Read1() + { + var mb = MessageBuilder.Create(); + var dss = mb.CreateObject(); + dss.SetStruct(1, 0); + dss.WriteData(0, ulong.MaxValue); + var d = (DeserializerState)dss; + Assert.AreEqual(ushort.MaxValue, d.ReadDataUShort(48)); + Assert.ThrowsException(() => d.ReadDataUShort(49)); + Assert.AreEqual((ushort)0, d.ReadDataUShort(64)); + Assert.IsNotNull(d.StructReadPointer(7)); + Assert.ThrowsException(() => d.RequireCapList()); + } + + [TestMethod] + public void Read2() + { + var mb = MessageBuilder.Create(); + var dss = mb.CreateObject(); + dss.Init(50); + var d = (DeserializerState)dss; + Assert.ThrowsException(() => d.ReadDataUInt(0)); + Assert.ThrowsException(() => d.StructReadPointer(0)); + } + + [TestMethod] + public void ReadCapList() + { + var mb = MessageBuilder.Create(); + mb.InitCapTable(); + var dss = mb.CreateObject(); + dss.SetStruct(0, 1); + var loc = mb.CreateObject>(); + loc.Init(1); + loc[0] = new TestInterfaceImpl2(); + dss.LinkObject(0, loc); + var d = (DeserializerState)dss; + var cl = d.ReadCapList(0); + Assert.AreEqual(1, cl.Count); + Assert.IsNotNull(cl[0]); + } + + [TestMethod] + public void ReadCap() + { + var dss = DynamicSerializerState.CreateForRpc(); + dss.SetStruct(0, 1); + dss.LinkObject(0, new TestInterfaceImpl2()); + var d = (DeserializerState)dss; + Assert.IsNotNull(d.ReadCap(0)); + Assert.IsNotNull(d.ReadCap(0)); + } + + [TestMethod] + public void RequireCap1() + { + var dss = DynamicSerializerState.CreateForRpc(); + dss.SetStruct(1, 1); + var d = (DeserializerState)dss; + Assert.ThrowsException(() => d.RequireCap()); + } + + [TestMethod] + public void RequireCap2() + { + DeserializerState d = default; + d.Kind = ObjectKind.Capability; + Assert.ThrowsException(() => d.RequireCap()); + } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index b122da4..7836f96 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -7,6 +7,9 @@ using Capnp.Rpc; using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.Extensions.Logging; using System.Diagnostics; +using System.Threading.Tasks.Dataflow; +using Capnp.Net.Runtime.Tests.GenImpls; +using Capnproto_test.Capnp.Test; namespace Capnp.Net.Runtime.Tests { @@ -42,7 +45,7 @@ namespace Capnp.Net.Runtime.Tests }); } - int MediumTimeout => Debugger.IsAttached ? Timeout.Infinite : 2000; + int MediumNonDbgTimeout => Debugger.IsAttached ? Timeout.Infinite : 2000; [TestMethod] public void CreateAndDispose() @@ -66,7 +69,7 @@ namespace Capnp.Net.Runtime.Tests try { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); } catch (System.Exception e) @@ -95,13 +98,13 @@ namespace Capnp.Net.Runtime.Tests using (client) { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); server.Main = new ProvidedCapabilityMock(); var main = client.GetMain(); var resolving = main as IResolvingCapability; - Assert.IsTrue(resolving.WhenResolved.Wait(MediumTimeout)); + Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout)); } } @@ -114,12 +117,12 @@ namespace Capnp.Net.Runtime.Tests using (client) { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); var main = client.GetMain(); var resolving = main as IResolvingCapability; - Assert.IsTrue(Assert.ThrowsExceptionAsync(() => resolving.WhenResolved).Wait(MediumTimeout)); + Assert.IsTrue(Assert.ThrowsExceptionAsync(() => resolving.WhenResolved).Wait(MediumNonDbgTimeout)); } } @@ -132,19 +135,19 @@ namespace Capnp.Net.Runtime.Tests using (client) { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); + Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); using (var answer = main.Call(0x1234567812345678, 0x3333, args)) { - Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout)); (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; Assert.AreEqual(0x1234567812345678, interfaceId); Assert.AreEqual(0x3333, methodId); @@ -156,7 +159,7 @@ namespace Capnp.Net.Runtime.Tests result.WriteData(0, 654321); mock.Return.SetResult(result); - Assert.IsTrue(answer.WhenReturned.Wait(MediumTimeout)); + Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout)); var outresult = answer.WhenReturned.Result; Assert.AreEqual(ObjectKind.Struct, outresult.Kind); Assert.AreEqual(654321, outresult.ReadDataInt(0)); @@ -173,19 +176,19 @@ namespace Capnp.Net.Runtime.Tests using (client) { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); + Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); using (var answer = main.Call(0x1234567812345678, 0x3333, args)) { - Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout)); (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; Assert.AreEqual(0x1234567812345678, interfaceId); Assert.AreEqual(0x3333, methodId); @@ -194,7 +197,7 @@ namespace Capnp.Net.Runtime.Tests mock.Return.SetCanceled(); - Assert.IsTrue(Assert.ThrowsExceptionAsync(() => answer.WhenReturned).Wait(MediumTimeout)); + Assert.IsTrue(Assert.ThrowsExceptionAsync(() => answer.WhenReturned).Wait(MediumNonDbgTimeout)); } } } @@ -212,21 +215,21 @@ namespace Capnp.Net.Runtime.Tests try { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); var resolving = main as IResolvingCapability; - Assert.IsTrue(resolving.WhenResolved.Wait(MediumTimeout)); + Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); CancellationToken ctx; using (var answer = main.Call(0x1234567812345678, 0x3333, args)) { - Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout)); (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; Assert.AreEqual(0x1234567812345678, interfaceId); Assert.AreEqual(0x3333, methodId); @@ -235,7 +238,7 @@ namespace Capnp.Net.Runtime.Tests ctx = ct; } - Assert.IsTrue(SpinWait.SpinUntil(() => ctx.IsCancellationRequested, MediumTimeout)); + Assert.IsTrue(SpinWait.SpinUntil(() => ctx.IsCancellationRequested, MediumNonDbgTimeout)); } finally { @@ -256,13 +259,13 @@ namespace Capnp.Net.Runtime.Tests try { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); + Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); @@ -270,7 +273,7 @@ namespace Capnp.Net.Runtime.Tests IPromisedAnswer answer; using (answer = main.Call(0x1234567812345678, 0x3333, args)) { - Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout)); (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; Assert.AreEqual(0x1234567812345678, interfaceId); Assert.AreEqual(0x3333, methodId); @@ -279,7 +282,7 @@ namespace Capnp.Net.Runtime.Tests ctx = ct; } - Assert.IsTrue(SpinWait.SpinUntil(() => ctx.IsCancellationRequested, MediumTimeout)); + Assert.IsTrue(SpinWait.SpinUntil(() => ctx.IsCancellationRequested, MediumNonDbgTimeout)); var mbr = MessageBuilder.Create(); mbr.InitCapTable(); @@ -290,7 +293,7 @@ namespace Capnp.Net.Runtime.Tests // Even after the client cancelled the call, the server must still send // a response. - Assert.IsTrue(answer.WhenReturned.ContinueWith(t => { }).Wait(MediumTimeout)); + Assert.IsTrue(answer.WhenReturned.ContinueWith(t => { }).Wait(MediumNonDbgTimeout)); } finally { @@ -315,19 +318,19 @@ namespace Capnp.Net.Runtime.Tests using (client) { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); + Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); using (var answer = main.Call(0x1234567812345678, 0x3333, args)) { - Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout)); (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; Assert.AreEqual(0x1234567812345678, interfaceId); Assert.AreEqual(0x3333, methodId); @@ -337,7 +340,7 @@ namespace Capnp.Net.Runtime.Tests mock.Return.SetException(new MyTestException()); var exTask = Assert.ThrowsExceptionAsync(() => answer.WhenReturned); - Assert.IsTrue(exTask.Wait(MediumTimeout)); + Assert.IsTrue(exTask.Wait(MediumNonDbgTimeout)); Assert.IsTrue(exTask.Result.Message.Contains(new MyTestException().Message)); } } @@ -352,19 +355,19 @@ namespace Capnp.Net.Runtime.Tests using (client) { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); + Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); using (var answer = main.Call(0x1234567812345678, 0x3333, args)) { - Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout)); var pipelined = (BareProxy)CapabilityReflection.CreateProxy(answer.Access( new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) }))); @@ -391,10 +394,10 @@ namespace Capnp.Net.Runtime.Tests mock.Return.SetResult(result); - Assert.IsTrue(answer.WhenReturned.Wait(MediumTimeout)); + Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout)); Assert.IsFalse(ct.IsCancellationRequested); - Assert.IsTrue(mock2.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(mock2.WhenCalled.Wait(MediumNonDbgTimeout)); (var interfaceId2, var methodId2, var inargs2, var ct2) = mock2.WhenCalled.Result; Assert.AreEqual(0x8765432187654321, interfaceId2); @@ -407,7 +410,7 @@ namespace Capnp.Net.Runtime.Tests result2.WriteData(0, 222222); mock2.Return.SetResult(result2); - Assert.IsTrue(answer2.WhenReturned.Wait(MediumTimeout)); + Assert.IsTrue(answer2.WhenReturned.Wait(MediumNonDbgTimeout)); var outresult2 = answer2.WhenReturned.Result; Assert.AreEqual(ObjectKind.Struct, outresult2.Kind); Assert.AreEqual(222222, outresult2.ReadDataInt(0)); @@ -425,19 +428,19 @@ namespace Capnp.Net.Runtime.Tests using (client) { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); + Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); using (var answer = main.Call(0x1234567812345678, 0x3333, args)) { - Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout)); (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; Assert.AreEqual(0x1234567812345678, interfaceId); @@ -467,8 +470,8 @@ namespace Capnp.Net.Runtime.Tests using (var answer2 = pipelined.Call(0x8765432187654321, 0x4444, args2)) { - Assert.IsTrue(answer.WhenReturned.Wait(MediumTimeout)); - Assert.IsTrue(mock2.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(mock2.WhenCalled.Wait(MediumNonDbgTimeout)); (var interfaceId2, var methodId2, var inargs2, var ct2) = mock2.WhenCalled.Result; Assert.AreEqual(0x8765432187654321, interfaceId2); @@ -481,7 +484,7 @@ namespace Capnp.Net.Runtime.Tests result2.WriteData(0, 222222); mock2.Return.SetResult(result2); - Assert.IsTrue(answer2.WhenReturned.Wait(MediumTimeout)); + Assert.IsTrue(answer2.WhenReturned.Wait(MediumNonDbgTimeout)); var outresult2 = answer2.WhenReturned.Result; Assert.AreEqual(ObjectKind.Struct, outresult2.Kind); Assert.AreEqual(222222, outresult2.ReadDataInt(0)); @@ -501,19 +504,19 @@ namespace Capnp.Net.Runtime.Tests using (client) { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); + Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); using (var answer = main.Call(0x1234567812345678, 0x3333, args)) { - Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout)); var pipelined = (BareProxy)CapabilityReflection.CreateProxy(answer.Access(new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) }))); @@ -545,7 +548,7 @@ namespace Capnp.Net.Runtime.Tests mock.Return.SetResult(result); - Assert.IsTrue(answer.WhenReturned.Wait(MediumTimeout)); + Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout)); Assert.IsFalse(ct.IsCancellationRequested); var args4 = DynamicSerializerState.CreateForRpc(); @@ -564,10 +567,10 @@ namespace Capnp.Net.Runtime.Tests var call4 = mock2.WhenCalled; var call5 = mock2.WhenCalled; - Assert.IsTrue(call2.Wait(MediumTimeout)); - Assert.IsTrue(call3.Wait(MediumTimeout)); - Assert.IsTrue(call4.Wait(MediumTimeout)); - Assert.IsTrue(call5.Wait(MediumTimeout)); + Assert.IsTrue(call2.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(call3.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(call4.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(call5.Wait(MediumNonDbgTimeout)); Assert.AreEqual(0x1111111111111111, call2.Result.InterfaceId); Assert.AreEqual(0x2222222222222222, call3.Result.InterfaceId); @@ -594,10 +597,10 @@ namespace Capnp.Net.Runtime.Tests ret5.WriteData(0, -4); call5.Result.Result.SetResult(ret5); - Assert.IsTrue(answer2.WhenReturned.Wait(MediumTimeout)); - Assert.IsTrue(answer3.WhenReturned.Wait(MediumTimeout)); - Assert.IsTrue(answer4.WhenReturned.Wait(MediumTimeout)); - Assert.IsTrue(answer5.WhenReturned.Wait(MediumTimeout)); + Assert.IsTrue(answer2.WhenReturned.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer3.WhenReturned.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer4.WhenReturned.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer5.WhenReturned.Wait(MediumNonDbgTimeout)); Assert.AreEqual(-1, answer2.WhenReturned.Result.ReadDataInt(0)); Assert.AreEqual(-2, answer3.WhenReturned.Result.ReadDataInt(0)); @@ -618,20 +621,20 @@ namespace Capnp.Net.Runtime.Tests using (client) { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); + Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); BareProxy pipelined; using (var answer = main.Call(0x1234567812345678, 0x3333, args)) { - Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout)); pipelined = (BareProxy)CapabilityReflection.CreateProxy( answer.Access(new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) }))); @@ -665,20 +668,20 @@ namespace Capnp.Net.Runtime.Tests using (client) { client.WhenConnected.Wait(); - SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); + SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); + Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); IPromisedAnswer answer2; using (var answer = main.Call(0x1234567812345678, 0x3333, args)) { - Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); + Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout)); var pipelined = (BareProxy)CapabilityReflection.CreateProxy(answer.Access(new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) }))); @@ -696,7 +699,7 @@ namespace Capnp.Net.Runtime.Tests var tcs = new TaskCompletionSource(); using (ct.Register(() => tcs.SetResult(0))) { - Assert.IsTrue(tcs.Task.Wait(MediumTimeout)); + Assert.IsTrue(tcs.Task.Wait(MediumNonDbgTimeout)); } var mock2 = new ProvidedCapabilityMock(); @@ -710,9 +713,100 @@ namespace Capnp.Net.Runtime.Tests mock.Return.SetResult(result); Assert.IsTrue(Assert.ThrowsExceptionAsync( - () => answer2.WhenReturned).Wait(MediumTimeout)); + () => answer2.WhenReturned).Wait(MediumNonDbgTimeout)); } } } + + [TestMethod] + public void Server() + { + var cbb = new BufferBlock(); + var server = new TcpRpcServer(); + server.Main = new TestInterfaceImpl2(); + bool init = true; + var tracer = new FrameTracing.RpcFrameTracer(Console.Out); + server.OnConnectionChanged += (s, a) => + { + var c = a.Connection; + if (init) + { + Assert.ThrowsException(() => c.AttachTracer(null)); + c.AttachTracer(tracer); + Assert.ThrowsException(() => c.InjectMidlayer(null)); + c.InjectMidlayer(_ => _); + Assert.IsFalse(c.IsComputing); + Assert.IsFalse(c.IsWaitingForData); + Assert.AreEqual(ConnectionState.Initializing, c.State); + Assert.IsNotNull(c.RemotePort); + Assert.AreEqual(TcpPort, c.LocalPort); + Assert.AreEqual(0L, c.RecvCount); + Assert.AreEqual(0L, c.SendCount); + } + else + { + Assert.ThrowsException(() => c.AttachTracer(tracer)); + Assert.ThrowsException(() => c.InjectMidlayer(_ => _)); + Assert.AreEqual(ConnectionState.Down, c.State); + } + + cbb.Post(c); + }; + + Assert.ThrowsException(() => server.StopListening()); + + server.StartAccepting(IPAddress.Any, TcpPort); + Assert.IsTrue(server.IsAlive); + Assert.ThrowsException(() => server.StartAccepting(IPAddress.Any, TcpPort)); + + var server2 = new TcpRpcServer(); + Assert.ThrowsException(() => server2.StartAccepting(IPAddress.Any, TcpPort)); + + var client1 = new TcpRpcClient("localhost", TcpPort); + var c1 = cbb.Receive(TimeSpan.FromMilliseconds(MediumNonDbgTimeout)); + Assert.IsNotNull(c1); + Assert.AreEqual(1, server.ConnectionCount); + Assert.AreEqual(c1, server.Connections[0]); + Assert.AreEqual(ConnectionState.Active, c1.State); + var proxy = client1.GetMain(); + Assert.IsTrue(proxy is IResolvingCapability r && r.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(c1.RecvCount > 0); + Assert.IsTrue(c1.SendCount > 0); + + var client2 = new TcpRpcClient("localhost", TcpPort); + var c2 = cbb.Receive(TimeSpan.FromMilliseconds(MediumNonDbgTimeout)); + Assert.IsNotNull(c2); + Assert.AreEqual(2, server.ConnectionCount); + Assert.AreEqual(c2, server.Connections[1]); + + init = false; + + client1.Dispose(); + var c1d = cbb.Receive(TimeSpan.FromMilliseconds(MediumNonDbgTimeout)); + Assert.IsNotNull(c1d); + Assert.AreEqual(1, server.ConnectionCount); + Assert.AreEqual(c2, server.Connections[0]); + Assert.IsTrue(SpinWait.SpinUntil(() => c1d.State == ConnectionState.Down, MediumNonDbgTimeout)); + + client2.Dispose(); + var c2d = cbb.Receive(TimeSpan.FromMilliseconds(MediumNonDbgTimeout)); + Assert.IsNotNull(c2d); + Assert.AreEqual(0, server.ConnectionCount); + Assert.IsTrue(SpinWait.SpinUntil(() => c2d.State == ConnectionState.Down, MediumNonDbgTimeout)); + + server.StopListening(); + Assert.IsFalse(server.IsAlive); + Assert.ThrowsException(() => server.StopListening()); + + for (int i = 0; i < 100; i++) + { + server.StartAccepting(IPAddress.Any, TcpPort); + Assert.IsTrue(server.IsAlive); + server.StopListening(); + Assert.IsFalse(server.IsAlive); + } + + server.Dispose(); + } } } diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs index 6fbb996..5773466 100644 --- a/Capnp.Net.Runtime/DeserializerState.cs +++ b/Capnp.Net.Runtime/DeserializerState.cs @@ -203,6 +203,10 @@ namespace Capnp GetRawBytes(); break; + case ObjectKind.ListOfShorts: + GetRawShorts(); + break; + case ObjectKind.ListOfInts: GetRawInts(); break; @@ -303,6 +307,8 @@ namespace Capnp case ListKind.ListOfStructs: { + if (Offset >= CurrentSegment.Length) + throw new DeserializationException("List of composites pointer exceeds segment bounds"); WirePointer tag = CurrentSegment[Offset]; if (tag.Kind != PointerKind.Struct) throw new DeserializationException("Unexpected: List of composites with non-struct type tag"); @@ -326,6 +332,10 @@ namespace Capnp if (pointer.IsDoubleFar) { CurrentSegmentIndex = pointer.TargetSegmentIndex; + + if (pointer.LandingPadOffset >= CurrentSegment.Length - 1) + throw new DeserializationException("Error decoding double-far pointer: exceeds segment bounds"); + Offset = 0; WirePointer pointer1 = CurrentSegment[pointer.LandingPadOffset]; @@ -373,14 +383,14 @@ namespace Capnp /// /// Offset relative to this.Offset within current segment /// the low-level capability object, or null if it is a null pointer - /// offset negative or out of range + /// offset negative or out of range /// capability table not set /// not a capability pointer or invalid capability index internal Rpc.ConsumedCapability? DecodeCapPointer(int offset) { if (offset < 0) { - throw new IndexOutOfRangeException(nameof(offset)); + throw new ArgumentOutOfRangeException(nameof(offset)); } if (Caps == null) @@ -677,7 +687,7 @@ namespace Capnp throw new DeserializationException("Expected a capability"); if (Caps == null) - throw new InvalidOperationException("Capability table not set. This is a bug."); + throw new InvalidOperationException("Capability table not set"); return (Rpc.CapabilityReflection.CreateProxy(Caps[(int)CapabilityIndex]) as T)!; } diff --git a/Capnp.Net.Runtime/FrameTracing/RpcFrameTracer.cs b/Capnp.Net.Runtime/FrameTracing/RpcFrameTracer.cs index fdd4ac2..62d7be9 100644 --- a/Capnp.Net.Runtime/FrameTracing/RpcFrameTracer.cs +++ b/Capnp.Net.Runtime/FrameTracing/RpcFrameTracer.cs @@ -18,15 +18,26 @@ namespace Capnp.FrameTracing readonly Stopwatch _timer = new Stopwatch(); readonly TextWriter _traceWriter; + readonly bool _disposeWriter; /// /// Constructs an instance /// /// textual logging target - public RpcFrameTracer(TextWriter traceWriter) + public RpcFrameTracer(TextWriter traceWriter): this(traceWriter, true) + { + } + + /// + /// Constructs an instance + /// + /// textual logging target + /// whether to dispose the writer when tracing is finished + public RpcFrameTracer(TextWriter traceWriter, bool dispose) { _traceWriter = traceWriter ?? throw new ArgumentNullException(nameof(traceWriter)); _traceWriter.WriteLine(Header); + _disposeWriter = dispose; } /// @@ -35,7 +46,8 @@ namespace Capnp.FrameTracing public void Dispose() { _traceWriter.WriteLine(""); - _traceWriter.Dispose(); + if (_disposeWriter) + _traceWriter.Dispose(); } void RenderMessageTarget(MessageTarget.READER target, FrameDirection dir) From ac50b7454ad330a62b6b7c8b901a63fd8bbdb550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 4 Apr 2020 22:57:07 +0200 Subject: [PATCH 29/76] fixes + coverage --- Capnp.Net.Runtime.Tests/General.cs | 51 +++++++- Capnp.Net.Runtime.Tests/Interception.cs | 75 +++++++++++ Capnp.Net.Runtime/Rpc/Impatient.cs | 39 +----- .../Rpc/Interception/CallContext.cs | 121 +++++------------- .../Rpc/Interception/Interceptor.cs | 3 +- 5 files changed, 166 insertions(+), 123 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/General.cs b/Capnp.Net.Runtime.Tests/General.cs index 662b039..c8067ef 100644 --- a/Capnp.Net.Runtime.Tests/General.cs +++ b/Capnp.Net.Runtime.Tests/General.cs @@ -1,4 +1,5 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Capnp.Rpc; +using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.Linq; @@ -67,5 +68,53 @@ namespace Capnp.Net.Runtime.Tests Task.WhenAll(tasks).Wait(); } + + class PromisedAnswerMock : IPromisedAnswer + { + readonly TaskCompletionSource _tcs = new TaskCompletionSource(); + + public Task WhenReturned => _tcs.Task; + + public void Return() + { + _tcs.SetResult(default); + } + + public void Cancel() + { + _tcs.SetCanceled(); + } + + public void Fault() + { + _tcs.SetException(new InvalidOperationException("test fault")); + } + + public ConsumedCapability Access(MemberAccessPath access) + { + throw new NotImplementedException(); + } + + public ConsumedCapability Access(MemberAccessPath access, Task proxyTask) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + } + } + + [TestMethod] + public void MakePipelineAwareOnFastPath() + { + var mock = new PromisedAnswerMock(); + mock.Return(); + for (int i = 0; i < 100; i++) + { + var t = Impatient.MakePipelineAware(mock, _ => (object)null); + Assert.IsTrue(t.IsCompleted); + }; + } } } diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index 3008723..f2f7b71 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -96,6 +96,46 @@ namespace Capnp.Net.Runtime.Tests } } + [TestMethod] + public void InterceptServerSideRedirectCall() + { + var policy = new MyPolicy("a"); + + (var server, var client) = SetupClientServerPair(); + + using (server) + using (client) + { + client.WhenConnected.Wait(); + + var counters = new Counters(); + server.Main = policy.Attach(new TestInterfaceImpl(counters)); + var redirTarget = new TestInterfaceImpl2(); + using (var main = client.GetMain()) + using (redirTarget) + { + var request1 = main.Foo(123, true, default); + var fcc = policy.Calls.ReceiveAsync(); + Assert.IsTrue(fcc.Wait(MediumNonDbgTimeout)); + var cc = fcc.Result; + + Assert.ThrowsException(() => cc.Bob = null); + cc.Bob = redirTarget; + cc.ForwardToBob(); + + Assert.IsTrue(policy.Returns.ReceiveAsync().Wait(MediumNonDbgTimeout)); + + cc.ReturnToAlice(); + + Assert.IsTrue(request1.Wait(MediumNonDbgTimeout)); + + Assert.AreEqual("bar", request1.Result); + } + Assert.IsTrue(redirTarget.IsDisposed); + Assert.AreEqual(0, counters.CallCount); + } + } + [TestMethod] public void InterceptClientSideModifyCall() { @@ -284,6 +324,41 @@ namespace Capnp.Net.Runtime.Tests } } + [TestMethod] + public void InterceptClientSideOverrideFaultedCall() + { + var policy = new MyPolicy("a"); + + (var server, var client) = SetupClientServerPair(); + + using (server) + using (client) + { + client.WhenConnected.Wait(); + + var counters = new Counters(); + server.Main = new TestInterfaceImpl(counters); + using (var main = policy.Attach(client.GetMain())) + { + var request1 = main.Bar(); + Assert.IsTrue(policy.Calls.TryReceive(out var cc)); + Assert.IsFalse(request1.IsCompleted); + + cc.ForwardToBob(); + Assert.IsTrue(policy.Returns.ReceiveAsync().Wait(MediumNonDbgTimeout)); + Assert.IsNotNull(cc.Exception); + cc.ReturnCanceled = false; + cc.Exception = null; + + cc.ReturnToAlice(); + Assert.ThrowsException(() => cc.ReturnToAlice()); + + Assert.IsTrue(request1.IsCompleted); + Assert.IsFalse(request1.IsFaulted); + } + } + } + [TestMethod] public void InterceptClientSideRedirectCall() { diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index bddc2be..4bdbc8a 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -31,40 +31,11 @@ namespace Capnp.Rpc var rtask = AwaitAnswer(); - try - { - // Really weird: We'd expect AwaitAnswer() to initialize a new Task instance upon each invocation. - // However, this does not seem to be always true (as indicated by CI test suite). An explanation might be - // that the underlying implementation recycles Task instances (um, really? doesn't make sense. But the - // observation doesn't make sense, either). - - _taskTable.Add(rtask, promise); - } - catch (ArgumentException) - { - if (rtask.IsCompleted) - { - // Force .NET to create a new Task instance - if (rtask.IsCanceled) - { - rtask = Task.FromCanceled(new CancellationToken(true)); - } - else if (rtask.IsFaulted) - { - rtask = Task.FromException(rtask.Exception!.InnerException!); - } - else - { - rtask = Task.FromResult(rtask.Result); - } - - _taskTable.Add(rtask, promise); - } - else - { - throw new InvalidOperationException("What the heck is wrong with Task?"); - } - } + // Rare situation: .NET maintains a cache of some pre-computed tasks for standard results (such as (int)0, (object)null). + // AwaitAnswer() might indeed have chosen a fast-path optimization, such that rtask is a cached object instead of a new instance. + // Once this happens the second time, and we return the same rtask for a different promise. GetAnswer()/TryGetAnswer() may return the "wrong" + // promise! Fortunately, this does not really matter, since the "wrong" promise is guaranteed to return exactly the same answer. :-) + _taskTable.GetValue(rtask, _ => promise); return rtask; } diff --git a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs index 018d865..86c4db9 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs @@ -25,50 +25,15 @@ namespace Capnp.Rpc.Interception public Task WhenReturned => _futureResult.Task; public CancellationToken CancelFromAlice => _cancelFromAlice.Token; - async Task AccessWhenReturned(MemberAccessPath access) - { - await WhenReturned; - return Access(access); - } - public ConsumedCapability? Access(MemberAccessPath access) { - if (_futureResult.Task.IsCompleted) - { - try - { - return access.Eval(WhenReturned.Result); - } - catch (AggregateException exception) - { - throw exception.InnerException!; - } - } - else - { - return new LazyCapability(AccessWhenReturned(access)); - } + return new LocalAnswerCapability(_futureResult.Task, access); } public ConsumedCapability? Access(MemberAccessPath _, Task task) { var proxyTask = task.AsProxyTask(); - - if (proxyTask.IsCompleted) - { - try - { - return proxyTask.Result?.ConsumedCap; - } - catch (AggregateException exception) - { - throw exception.InnerException!; - } - } - else - { - return new LazyCapability(proxyTask); - } + return new LocalAnswerCapability(proxyTask); } public void Dispose() @@ -122,10 +87,16 @@ namespace Capnp.Rpc.Interception /// public InterceptionState State { get; private set; } + SerializerState _inArgs; + /// /// Input arguments /// - public SerializerState? InArgs { get; set; } + public SerializerState InArgs + { + get => _inArgs; + set { _inArgs = value ?? throw new ArgumentNullException(nameof(value)); } + } /// /// Output arguments ("return value") @@ -171,45 +142,41 @@ namespace Capnp.Rpc.Interception /// A -derived object /// A -derived object /// A -derived object (low level capability) - /// null /// /// - public object? Bob + /// + /// Note that getting/setting this property does NOT transfer ownership. + /// + public object Bob { get => _bob; set { if (value != _bob) { - BobProxy?.Dispose(); - BobProxy = null; - - _bob = value; - switch (value) { + case null: + throw new ArgumentNullException(nameof(value)); + case Proxy proxy: - BobProxy = proxy; + BobProxy = proxy.Cast(false); + break; + + case ConsumedCapability cap: using (var temp = CapabilityReflection.CreateProxy(cap)) { + Bob = temp; } break; case Skeleton skeleton: - BobProxy = CapabilityReflection.CreateProxy( - LocalCapability.Create(skeleton)); - break; - - case ConsumedCapability cap: - BobProxy = CapabilityReflection.CreateProxy(cap); - break; - - case null: + Bob = LocalCapability.Create(skeleton); break; default: - BobProxy = CapabilityReflection.CreateProxy( - LocalCapability.Create( - Skeleton.GetOrCreateSkeleton(value, false))); + Bob = Skeleton.GetOrCreateSkeleton(value, false); break; } + + _bob = value; } } } @@ -218,7 +185,7 @@ namespace Capnp.Rpc.Interception readonly CensorCapability _censorCapability; PromisedAnswer _promisedAnswer; - object? _bob; + object _bob; internal IPromisedAnswer Answer => _promisedAnswer; @@ -226,13 +193,14 @@ namespace Capnp.Rpc.Interception { _censorCapability = censorCapability; _promisedAnswer = new PromisedAnswer(this); + _inArgs = inArgs; + _bob = null!; // Will beinitialized by setting Bob CancelFromAlice = _promisedAnswer.CancelFromAlice; CancelToBob = CancelFromAlice; Bob = censorCapability.InterceptedCapability; InterfaceId = interfaceId; MethodId = methodId; - InArgs = inArgs; State = InterceptionState.RequestedFromAlice; } @@ -243,12 +211,9 @@ namespace Capnp.Rpc.Interception for (int i = 0; i < state.Caps.Count; i++) { var cap = state.Caps[i]; - if (cap != null) - { - cap = policy.Attach(cap); - state.Caps[i] = cap; - cap.AddRef(); - } + cap = policy.Attach(cap); + state.Caps[i] = cap; + cap.AddRef(); } } } @@ -260,12 +225,9 @@ namespace Capnp.Rpc.Interception for (int i = 0; i < state.Caps.Count; i++) { var cap = state.Caps[i]; - if (cap != null) - { - cap = policy.Detach(cap); - state.Caps[i] = cap; - cap.AddRef(); - } + cap = policy.Detach(cap); + state.Caps[i] = cap; + cap.AddRef(); } } } @@ -274,12 +236,8 @@ namespace Capnp.Rpc.Interception /// Intercepts all capabilies inside the input arguments /// /// Policy to use, or null to further use present policy - /// InArgs not set public void InterceptInCaps(IInterceptionPolicy? policyOverride = null) { - if (InArgs == null) - throw new InvalidOperationException("InArgs not set"); - InterceptCaps(InArgs, policyOverride ?? _censorCapability.Policy); } @@ -296,12 +254,8 @@ namespace Capnp.Rpc.Interception /// Unintercepts all capabilies inside the input arguments /// /// Policy to remove, or null to remove present policy - /// InArgs not set public void UninterceptInCaps(IInterceptionPolicy? policyOverride = null) { - if (InArgs == null) - throw new InvalidOperationException("InArgs not set"); - UninterceptCaps(InArgs, policyOverride ?? _censorCapability.Policy); } @@ -317,15 +271,8 @@ namespace Capnp.Rpc.Interception /// /// Forwards this intercepted call to the target capability ("Bob"). /// - /// Bob/InArgs not set public void ForwardToBob() { - if (Bob == null) - throw new InvalidOperationException("Bob is null"); - - if (InArgs == null) - throw new InvalidOperationException("InArgs not set"); - var answer = BobProxy!.Call(InterfaceId, MethodId, InArgs.Rewrap(), default, CancelToBob); State = InterceptionState.ForwardedToBob; diff --git a/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs b/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs index 1413f6c..aeee3f5 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs @@ -45,7 +45,8 @@ namespace Capnp.Rpc.Interception switch (cap) { case Proxy proxy: - return (CapabilityReflection.CreateProxy(Attach(policy, proxy.ConsumedCap!)) as TCap)!; + return (CapabilityReflection.CreateProxy( + Attach(policy, proxy.ConsumedCap!)) as TCap)!; case ConsumedCapability ccap: return (new CensorCapability(ccap, policy) as TCap)!; From 01513ef71f94e68de8a1873d4a3b745fb936eff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 4 Apr 2020 23:10:54 +0200 Subject: [PATCH 30/76] PendingQuestion: removed unnecessary finalizer --- Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 81 ++++++------------------ 1 file changed, 21 insertions(+), 60 deletions(-) diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index 394f4f2..2009b14 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -49,13 +49,7 @@ namespace Capnp.Rpc /// /// Question object was disposed. /// - Disposed = 16, - - /// - /// Question object was finalized by GC. - /// This flag should only be observable when debugging the finalizer itself. - /// - Finalized = 32 + Disposed = 16 } readonly TaskCompletionSource _tcs = new TaskCompletionSource(); @@ -76,7 +70,7 @@ namespace Capnp.Rpc { foreach (var cap in inParams.Caps!) { - cap?.AddRef(); + cap.AddRef(); } } @@ -279,7 +273,7 @@ namespace Capnp.Rpc { foreach (var cap in inParams.Caps!) { - cap?.Release(); + cap.Release(); } } @@ -293,7 +287,7 @@ namespace Capnp.Rpc { foreach (var cap in outParams.Caps!) { - cap?.Release(); + cap.Release(); } } @@ -332,54 +326,7 @@ namespace Capnp.Rpc OnException(exception); } - ReleaseCaps(target!, inParams); - } - - #region IDisposable Support - - void Dispose(bool disposing) - { - SerializerState? inParams; - ConsumedCapability? target; - bool justDisposed = false; - - lock (ReentrancyBlocker) - { - inParams = _inParams; - _inParams = null; - target = _target; - _target = null; - - if (disposing) - { - if (!StateFlags.HasFlag(State.Disposed)) - { - StateFlags |= State.Disposed; - justDisposed = true; - - AutoFinish(); - } - } - else - { - StateFlags |= State.Finalized; - } - } - ReleaseCaps(target, inParams); - - if (justDisposed) - { - _tcs.TrySetCanceled(); - } - } - - /// - /// Finalizer - /// - ~PendingQuestion() - { - Dispose(false); } /// @@ -387,9 +334,23 @@ namespace Capnp.Rpc /// public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); + bool justDisposed = false; + + lock (ReentrancyBlocker) + { + if (!StateFlags.HasFlag(State.Disposed)) + { + StateFlags |= State.Disposed; + justDisposed = true; + + AutoFinish(); + } + } + + if (justDisposed) + { + _tcs.TrySetCanceled(); + } } - #endregion } } \ No newline at end of file From bdc8240e5b932ff35ed4068e1b459fb142026036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 5 Apr 2020 16:53:40 +0200 Subject: [PATCH 31/76] tests & fixes --- Capnp.Net.Runtime.Tests/General.cs | 2 + .../Mock/TestCapImplementations.cs | 135 ++++++- Capnp.Net.Runtime.Tests/Mock/test.cs | 375 +++++++++--------- .../TcpRpcAdvancedStuff.cs | 72 ++++ Capnp.Net.Runtime.Tests/Util/TestBase.cs | 7 +- Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs | 5 + Capnp.Net.Runtime/Rpc/Impatient.cs | 6 +- .../Rpc/Interception/CallContext.cs | 4 +- Capnp.Net.Runtime/Rpc/LocalAnswer.cs | 2 + Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 45 ++- .../Rpc/RefCountingCapability.cs | 4 +- .../Rpc/RemoteAnswerCapability.cs | 31 +- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 28 ++ Capnp.Net.Runtime/Rpc/Skeleton.cs | 2 +- .../Rpc/TailCallNoDataException.cs | 9 + 15 files changed, 495 insertions(+), 232 deletions(-) create mode 100644 Capnp.Net.Runtime/Rpc/TailCallNoDataException.cs diff --git a/Capnp.Net.Runtime.Tests/General.cs b/Capnp.Net.Runtime.Tests/General.cs index c8067ef..f5cb811 100644 --- a/Capnp.Net.Runtime.Tests/General.cs +++ b/Capnp.Net.Runtime.Tests/General.cs @@ -100,6 +100,8 @@ namespace Capnp.Net.Runtime.Tests throw new NotImplementedException(); } + public bool IsTailCall => false; + public void Dispose() { } diff --git a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs index bb93eef..44e9014 100644 --- a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs @@ -622,20 +622,6 @@ namespace Capnp.Net.Runtime.Tests.GenImpls } #endregion TestCallOrder - #region TestTailCaller - class TestTailCaller : ITestTailCaller - { - public void Dispose() - { - } - - public Task Foo(int i, ITestTailCallee callee, CancellationToken cancellationToken_) - { - return callee.Foo(i, "from TestTailCaller", cancellationToken_); - } - } - #endregion TestTailCaller - #region TestTailCaller class TestTailCallerImpl : ITestTailCaller { @@ -660,6 +646,41 @@ namespace Capnp.Net.Runtime.Tests.GenImpls } } } + + class TestTailCallerImpl2 : ITestTailCaller + { + ITestCallOrder _keeper; + + public TestTailCallerImpl2() + { + } + + public void Dispose() + { + _keeper?.Dispose(); + } + + public Task Foo(int i, ITestTailCallee callee, CancellationToken cancellationToken_) + { + using (callee) + { + if (_keeper == null) + { + var task = callee.Foo(i, "from TestTailCaller", cancellationToken_); + _keeper = task.C(); + return task; + } + else + { + return Task.FromResult( + new TestTailCallee.TailResult() + { + C = _keeper + }); + } + } + } + } #endregion TestTailCaller #region TestTailCallee @@ -937,6 +958,92 @@ namespace Capnp.Net.Runtime.Tests.GenImpls } } + class TestMoreStuffImpl3 : ITestMoreStuff + { + readonly TaskCompletionSource _heldCap = new TaskCompletionSource(); + + public Task CallFoo(ITestInterface cap, CancellationToken cancellationToken_ = default) + { + using (cap) + { + return cap.Foo(123, true); + } + } + + public Task CallFooWhenResolved(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task CallHeld(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public async void Dispose() + { + using (var cap = await _heldCap.Task) + { + } + } + + public Task Echo(ITestCallOrder Cap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task ExpectCancel(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task GetEnormousString(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task GetHandle(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public async Task GetHeld(CancellationToken cancellationToken_ = default) + { + return await _heldCap.Task; + } + + public Task GetNull(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task Hold(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + _heldCap.SetResult(Cap); + return Task.CompletedTask; + } + + public Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task MethodWithNullDefault(string A, ITestInterface B, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task NeverReturn(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + } + #endregion TestMoreStuff #region TestHandle diff --git a/Capnp.Net.Runtime.Tests/Mock/test.cs b/Capnp.Net.Runtime.Tests/Mock/test.cs index 8108823..51b4975 100644 --- a/Capnp.Net.Runtime.Tests/Mock/test.cs +++ b/Capnp.Net.Runtime.Tests/Mock/test.cs @@ -1,13 +1,14 @@ using Capnp; using Capnp.Rpc; using System; +using System.CodeDom.Compiler; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace Capnproto_test.Capnp.Test { - [TypeId(0x9c8e9318b29d9cd3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9c8e9318b29d9cd3UL)] public enum TestEnum : ushort { foo, @@ -20,7 +21,7 @@ namespace Capnproto_test.Capnp.Test garply } - [TypeId(0xa0a8f314b80b63fdUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa0a8f314b80b63fdUL)] public class TestAllTypes : ICapnpSerializable { public const UInt64 typeId = 0xa0a8f314b80b63fdUL; @@ -545,7 +546,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xeb3f9ebe98c73cb6UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xeb3f9ebe98c73cb6UL)] public class TestDefaults : ICapnpSerializable { public const UInt64 typeId = 0xeb3f9ebe98c73cb6UL; @@ -1216,7 +1217,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe3da5a2ccd28c0d8UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe3da5a2ccd28c0d8UL)] public class TestAnyPointer : ICapnpSerializable { public const UInt64 typeId = 0xe3da5a2ccd28c0d8UL; @@ -1276,7 +1277,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf49850f63c2bfa59UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf49850f63c2bfa59UL)] public class TestAnyOthers : ICapnpSerializable { public const UInt64 typeId = 0xf49850f63c2bfa59UL; @@ -1366,7 +1367,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa9d5f8efe770022bUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa9d5f8efe770022bUL)] public class TestOutOfOrder : ICapnpSerializable { public const UInt64 typeId = 0xa9d5f8efe770022bUL; @@ -1546,7 +1547,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf47697362233ce52UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf47697362233ce52UL)] public class TestUnion : ICapnpSerializable { public const UInt64 typeId = 0xf47697362233ce52UL; @@ -1766,7 +1767,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfc76a82eecb7a718UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfc76a82eecb7a718UL)] public class union0 : ICapnpSerializable { public const UInt64 typeId = 0xfc76a82eecb7a718UL; @@ -2186,7 +2187,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xee0a6b99b7dc7ab2UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xee0a6b99b7dc7ab2UL)] public class union1 : ICapnpSerializable { public const UInt64 typeId = 0xee0a6b99b7dc7ab2UL; @@ -2768,7 +2769,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xafc5fd419f0d66d4UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xafc5fd419f0d66d4UL)] public class union2 : ICapnpSerializable { public const UInt64 typeId = 0xafc5fd419f0d66d4UL; @@ -2983,7 +2984,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa2fb022ec7f30053UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa2fb022ec7f30053UL)] public class union3 : ICapnpSerializable { public const UInt64 typeId = 0xa2fb022ec7f30053UL; @@ -3199,7 +3200,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9e2e784c915329b6UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9e2e784c915329b6UL)] public class TestUnnamedUnion : ICapnpSerializable { public const UInt64 typeId = 0x9e2e784c915329b6UL; @@ -3380,7 +3381,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x89a9494f1b900f22UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x89a9494f1b900f22UL)] public class TestUnionInUnion : ICapnpSerializable { public const UInt64 typeId = 0x89a9494f1b900f22UL; @@ -3438,7 +3439,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd005f6c63707670cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd005f6c63707670cUL)] public class outer : ICapnpSerializable { public const UInt64 typeId = 0xd005f6c63707670cUL; @@ -3570,7 +3571,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xff9ce111c6f8e5dbUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xff9ce111c6f8e5dbUL)] public class inner : ICapnpSerializable { public const UInt64 typeId = 0xff9ce111c6f8e5dbUL; @@ -3706,7 +3707,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdc841556134c3103UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdc841556134c3103UL)] public class TestGroups : ICapnpSerializable { public const UInt64 typeId = 0xdc841556134c3103UL; @@ -3764,7 +3765,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe22ae74ff9113268UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe22ae74ff9113268UL)] public class groups : ICapnpSerializable { public const UInt64 typeId = 0xe22ae74ff9113268UL; @@ -3921,7 +3922,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf5fcba89c0c1196fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf5fcba89c0c1196fUL)] public class foo : ICapnpSerializable { public const UInt64 typeId = 0xf5fcba89c0c1196fUL; @@ -4010,7 +4011,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf0fa30304066a4b3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf0fa30304066a4b3UL)] public class baz : ICapnpSerializable { public const UInt64 typeId = 0xf0fa30304066a4b3UL; @@ -4099,7 +4100,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb727c0d0091a001dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb727c0d0091a001dUL)] public class bar : ICapnpSerializable { public const UInt64 typeId = 0xb727c0d0091a001dUL; @@ -4190,7 +4191,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf77ed6f7454eec40UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf77ed6f7454eec40UL)] public class TestInterleavedGroups : ICapnpSerializable { public const UInt64 typeId = 0xf77ed6f7454eec40UL; @@ -4262,7 +4263,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc7485a3516c7d3c8UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc7485a3516c7d3c8UL)] public class group1 : ICapnpSerializable { public const UInt64 typeId = 0xc7485a3516c7d3c8UL; @@ -4467,7 +4468,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdb0afd413f4a313aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdb0afd413f4a313aUL)] public class corge : ICapnpSerializable { public const UInt64 typeId = 0xdb0afd413f4a313aUL; @@ -4572,7 +4573,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xcc85a335569990e9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xcc85a335569990e9UL)] public class group2 : ICapnpSerializable { public const UInt64 typeId = 0xcc85a335569990e9UL; @@ -4777,7 +4778,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa017f0366827ee37UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa017f0366827ee37UL)] public class corge : ICapnpSerializable { public const UInt64 typeId = 0xa017f0366827ee37UL; @@ -4883,7 +4884,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x94f7e0b103b4b718UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x94f7e0b103b4b718UL)] public class TestUnionDefaults : ICapnpSerializable { public const UInt64 typeId = 0x94f7e0b103b4b718UL; @@ -5030,7 +5031,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd9f2b5941a343bcdUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd9f2b5941a343bcdUL)] public class TestNestedTypes : ICapnpSerializable { public const UInt64 typeId = 0xd9f2b5941a343bcdUL; @@ -5121,14 +5122,14 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb651d2fba42056d4UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb651d2fba42056d4UL)] public enum NestedEnum : ushort { foo, bar } - [TypeId(0x82cd03a53b29d76bUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x82cd03a53b29d76bUL)] public class NestedStruct : ICapnpSerializable { public const UInt64 typeId = 0x82cd03a53b29d76bUL; @@ -5204,7 +5205,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xcfa0d546993a3df3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xcfa0d546993a3df3UL)] public enum NestedEnum : ushort { baz, @@ -5214,7 +5215,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe78aac389e77b065UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe78aac389e77b065UL)] public class TestUsing : ICapnpSerializable { public const UInt64 typeId = 0xe78aac389e77b065UL; @@ -5291,7 +5292,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe41885c94393277eUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe41885c94393277eUL)] public class TestLists : ICapnpSerializable { public const UInt64 typeId = 0xe41885c94393277eUL; @@ -5485,7 +5486,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8412c03b75b2cfeeUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8412c03b75b2cfeeUL)] public class Struct0 : ICapnpSerializable { public const UInt64 typeId = 0x8412c03b75b2cfeeUL; @@ -5530,7 +5531,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe0fe5870b141ad69UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe0fe5870b141ad69UL)] public class Struct1 : ICapnpSerializable { public const UInt64 typeId = 0xe0fe5870b141ad69UL; @@ -5590,7 +5591,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa6411a353090145bUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa6411a353090145bUL)] public class Struct8 : ICapnpSerializable { public const UInt64 typeId = 0xa6411a353090145bUL; @@ -5650,7 +5651,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa8abf7a82928986cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa8abf7a82928986cUL)] public class Struct16 : ICapnpSerializable { public const UInt64 typeId = 0xa8abf7a82928986cUL; @@ -5710,7 +5711,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xad7beedc4ed30742UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xad7beedc4ed30742UL)] public class Struct32 : ICapnpSerializable { public const UInt64 typeId = 0xad7beedc4ed30742UL; @@ -5770,7 +5771,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xef9a34f2ff7cc646UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xef9a34f2ff7cc646UL)] public class Struct64 : ICapnpSerializable { public const UInt64 typeId = 0xef9a34f2ff7cc646UL; @@ -5830,7 +5831,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc6abf1b0329e6227UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc6abf1b0329e6227UL)] public class StructP : ICapnpSerializable { public const UInt64 typeId = 0xc6abf1b0329e6227UL; @@ -5890,7 +5891,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x943a234ca336b16aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x943a234ca336b16aUL)] public class Struct0c : ICapnpSerializable { public const UInt64 typeId = 0x943a234ca336b16aUL; @@ -5950,7 +5951,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8991bc0e74a594cdUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8991bc0e74a594cdUL)] public class Struct1c : ICapnpSerializable { public const UInt64 typeId = 0x8991bc0e74a594cdUL; @@ -6025,7 +6026,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xed267416528c7a24UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xed267416528c7a24UL)] public class Struct8c : ICapnpSerializable { public const UInt64 typeId = 0xed267416528c7a24UL; @@ -6100,7 +6101,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9978837b037d58e6UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9978837b037d58e6UL)] public class Struct16c : ICapnpSerializable { public const UInt64 typeId = 0x9978837b037d58e6UL; @@ -6175,7 +6176,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xed5fa940f54a7904UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xed5fa940f54a7904UL)] public class Struct32c : ICapnpSerializable { public const UInt64 typeId = 0xed5fa940f54a7904UL; @@ -6250,7 +6251,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xbc743778f2597c7dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbc743778f2597c7dUL)] public class Struct64c : ICapnpSerializable { public const UInt64 typeId = 0xbc743778f2597c7dUL; @@ -6325,7 +6326,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc2e364a40182013dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc2e364a40182013dUL)] public class StructPc : ICapnpSerializable { public const UInt64 typeId = 0xc2e364a40182013dUL; @@ -6401,7 +6402,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x92fc29a80f3ddd5cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x92fc29a80f3ddd5cUL)] public class TestFieldZeroIsBit : ICapnpSerializable { public const UInt64 typeId = 0x92fc29a80f3ddd5cUL; @@ -6493,7 +6494,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa851ad32cbc2ffeaUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa851ad32cbc2ffeaUL)] public class TestListDefaults : ICapnpSerializable { public const UInt64 typeId = 0xa851ad32cbc2ffeaUL; @@ -6588,7 +6589,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa76e3c9bb7fd56d3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa76e3c9bb7fd56d3UL)] public class TestLateUnion : ICapnpSerializable { public const UInt64 typeId = 0xa76e3c9bb7fd56d3UL; @@ -6705,7 +6706,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x807280a2901aa079UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x807280a2901aa079UL)] public class theUnion : ICapnpSerializable { public const UInt64 typeId = 0x807280a2901aa079UL; @@ -6866,7 +6867,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc1973984dee98e3aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc1973984dee98e3aUL)] public class anotherUnion : ICapnpSerializable { public const UInt64 typeId = 0xc1973984dee98e3aUL; @@ -7028,7 +7029,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x95b30dd14e01dda8UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x95b30dd14e01dda8UL)] public class TestOldVersion : ICapnpSerializable { public const UInt64 typeId = 0x95b30dd14e01dda8UL; @@ -7118,7 +7119,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8ed75a7469f04ce3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8ed75a7469f04ce3UL)] public class TestNewVersion : ICapnpSerializable { public const UInt64 typeId = 0x8ed75a7469f04ce3UL; @@ -7240,7 +7241,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xbd5fe16e5170c492UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbd5fe16e5170c492UL)] public class TestOldUnionVersion : ICapnpSerializable { public const UInt64 typeId = 0xbd5fe16e5170c492UL; @@ -7356,7 +7357,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc7e4c513a975492bUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc7e4c513a975492bUL)] public class TestNewUnionVersion : ICapnpSerializable { public const UInt64 typeId = 0xc7e4c513a975492bUL; @@ -7489,7 +7490,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x86232c1de4513e84UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x86232c1de4513e84UL)] public class a : ICapnpSerializable { public const UInt64 typeId = 0x86232c1de4513e84UL; @@ -7605,7 +7606,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfaf781ef89a00e39UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfaf781ef89a00e39UL)] public class TestStructUnion : ICapnpSerializable { public const UInt64 typeId = 0xfaf781ef89a00e39UL; @@ -7663,7 +7664,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x992edc677bef5a3cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x992edc677bef5a3cUL)] public class un : ICapnpSerializable { public const UInt64 typeId = 0x992edc677bef5a3cUL; @@ -7797,7 +7798,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9daec9823f171085UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9daec9823f171085UL)] public class SomeStruct : ICapnpSerializable { public const UInt64 typeId = 0x9daec9823f171085UL; @@ -7873,7 +7874,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdec497819d097c3cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdec497819d097c3cUL)] public class TestPrintInlineStructs : ICapnpSerializable { public const UInt64 typeId = 0xdec497819d097c3cUL; @@ -7947,7 +7948,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8e4936003708dac2UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8e4936003708dac2UL)] public class InlineStruct : ICapnpSerializable { public const UInt64 typeId = 0x8e4936003708dac2UL; @@ -8023,7 +8024,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x91afd4a864dbb030UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x91afd4a864dbb030UL)] public class TestWholeFloatDefault : ICapnpSerializable { public const UInt64 typeId = 0x91afd4a864dbb030UL; @@ -8100,7 +8101,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9d5b8cd8de9922ebUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9d5b8cd8de9922ebUL)] public class TestGenerics : ICapnpSerializable where TFoo : class where TBar : class { public const UInt64 typeId = 0x9d5b8cd8de9922ebUL; @@ -8260,7 +8261,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb46a779beaf3384eUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb46a779beaf3384eUL)] public class ug : ICapnpSerializable { public const UInt64 typeId = 0xb46a779beaf3384eUL; @@ -8319,7 +8320,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf6a841117e19ac73UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf6a841117e19ac73UL)] public class Inner : ICapnpSerializable { public const UInt64 typeId = 0xf6a841117e19ac73UL; @@ -8394,7 +8395,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa9ab42b118d6d435UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa9ab42b118d6d435UL)] public class Inner2 : ICapnpSerializable where TBaz : class { public const UInt64 typeId = 0xa9ab42b118d6d435UL; @@ -8498,7 +8499,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb6a0829c762b06f3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb6a0829c762b06f3UL)] public class DeepNest : ICapnpSerializable where TQux : class { public const UInt64 typeId = 0xb6a0829c762b06f3UL; @@ -8602,7 +8603,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8839ed86c9794287UL), Proxy(typeof(DeepNestInterface_Proxy<>)), Skeleton(typeof(DeepNestInterface_Skeleton<>))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8839ed86c9794287UL), Proxy(typeof(DeepNestInterface_Proxy<>)), Skeleton(typeof(DeepNestInterface_Skeleton<>))] public interface IDeepNestInterface : IDisposable where TQuux : class { Task Call(CancellationToken cancellationToken_ = default); @@ -8646,7 +8647,7 @@ namespace Capnproto_test.Capnp.Test public static class DeepNestInterface where TQuux : class { - [TypeId(0xb84eecc799437049UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb84eecc799437049UL)] public class Params_Call : ICapnpSerializable { public const UInt64 typeId = 0xb84eecc799437049UL; @@ -8691,7 +8692,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe080f0fc54614f6fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe080f0fc54614f6fUL)] public class Result_Call : ICapnpSerializable { public const UInt64 typeId = 0xe080f0fc54614f6fUL; @@ -8739,7 +8740,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc9e749e8dd54da5cUL), Proxy(typeof(Interface_Proxy<>)), Skeleton(typeof(Interface_Skeleton<>))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc9e749e8dd54da5cUL), Proxy(typeof(Interface_Proxy<>)), Skeleton(typeof(Interface_Skeleton<>))] public interface IInterface : IDisposable where TQux : class { Task<(TQux, Capnproto_test.Capnp.Test.TestGenerics)> Call(Capnproto_test.Capnp.Test.TestGenerics.Inner2 arg_, CancellationToken cancellationToken_ = default); @@ -8792,7 +8793,7 @@ namespace Capnproto_test.Capnp.Test public static class Interface where TQux : class { - [TypeId(0xa5b46224e33581adUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa5b46224e33581adUL)] public class Result_Call : ICapnpSerializable { public const UInt64 typeId = 0xa5b46224e33581adUL; @@ -8868,7 +8869,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8e656edfb45ba6cfUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8e656edfb45ba6cfUL)] public class UseAliases : ICapnpSerializable { public const UInt64 typeId = 0x8e656edfb45ba6cfUL; @@ -9004,7 +9005,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa9b2b1f52dde845dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa9b2b1f52dde845dUL)] public class TestGenericsWrapper : ICapnpSerializable where TFoo : class where TBar : class { public const UInt64 typeId = 0xa9b2b1f52dde845dUL; @@ -9064,7 +9065,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf28f83667a557a04UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf28f83667a557a04UL)] public class TestGenericsWrapper2 : ICapnpSerializable { public const UInt64 typeId = 0xf28f83667a557a04UL; @@ -9124,7 +9125,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8b9717a3f8d85a9aUL), Proxy(typeof(TestImplicitMethodParams_Proxy)), Skeleton(typeof(TestImplicitMethodParams_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8b9717a3f8d85a9aUL), Proxy(typeof(TestImplicitMethodParams_Proxy)), Skeleton(typeof(TestImplicitMethodParams_Skeleton))] public interface ITestImplicitMethodParams : IDisposable { Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) @@ -9181,7 +9182,7 @@ namespace Capnproto_test.Capnp.Test public static class TestImplicitMethodParams { - [TypeId(0xf83f8caf54bdc486UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf83f8caf54bdc486UL)] public class Params_Call : ICapnpSerializable where TT : class where TU : class { public const UInt64 typeId = 0xf83f8caf54bdc486UL; @@ -9257,7 +9258,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdf9ccdeb81a704c9UL), Proxy(typeof(TestImplicitMethodParamsInGeneric_Proxy<>)), Skeleton(typeof(TestImplicitMethodParamsInGeneric_Skeleton<>))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdf9ccdeb81a704c9UL), Proxy(typeof(TestImplicitMethodParamsInGeneric_Proxy<>)), Skeleton(typeof(TestImplicitMethodParamsInGeneric_Skeleton<>))] public interface ITestImplicitMethodParamsInGeneric : IDisposable where TV : class { Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) @@ -9315,7 +9316,7 @@ namespace Capnproto_test.Capnp.Test public static class TestImplicitMethodParamsInGeneric where TV : class { - [TypeId(0x9aab8e25c808d71eUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9aab8e25c808d71eUL)] public class Params_Call : ICapnpSerializable where TT : class where TU : class { public const UInt64 typeId = 0x9aab8e25c808d71eUL; @@ -9391,7 +9392,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa54870440e919063UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa54870440e919063UL)] public class TestGenericsUnion : ICapnpSerializable where TFoo : class where TBar : class { public const UInt64 typeId = 0xa54870440e919063UL; @@ -9526,7 +9527,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9427b2a71030338fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9427b2a71030338fUL)] public class TestUseGenerics : ICapnpSerializable { public const UInt64 typeId = 0x9427b2a71030338fUL; @@ -10625,7 +10626,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc5598844441096dcUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc5598844441096dcUL)] public class TestEmptyStruct : ICapnpSerializable { public const UInt64 typeId = 0xc5598844441096dcUL; @@ -10670,7 +10671,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xabed745cd8c92095UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xabed745cd8c92095UL)] public class TestConstants : ICapnpSerializable { public const UInt64 typeId = 0xabed745cd8c92095UL; @@ -10715,7 +10716,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xddc280dbee9c99b3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddc280dbee9c99b3UL)] public class TestAnyPointerConstants : ICapnpSerializable { public const UInt64 typeId = 0xddc280dbee9c99b3UL; @@ -10820,7 +10821,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x88eb12a0e0af92b2UL), Proxy(typeof(TestInterface_Proxy)), Skeleton(typeof(TestInterface_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x88eb12a0e0af92b2UL), Proxy(typeof(TestInterface_Proxy)), Skeleton(typeof(TestInterface_Skeleton))] public interface ITestInterface : IDisposable { Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default); @@ -10919,7 +10920,7 @@ namespace Capnproto_test.Capnp.Test public static class TestInterface { - [TypeId(0xb874edc0d559b391UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb874edc0d559b391UL)] public class Params_Foo : ICapnpSerializable { public const UInt64 typeId = 0xb874edc0d559b391UL; @@ -10994,7 +10995,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb04fcaddab714ba4UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb04fcaddab714ba4UL)] public class Result_Foo : ICapnpSerializable { public const UInt64 typeId = 0xb04fcaddab714ba4UL; @@ -11054,7 +11055,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd044893357b42568UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd044893357b42568UL)] public class Params_Bar : ICapnpSerializable { public const UInt64 typeId = 0xd044893357b42568UL; @@ -11099,7 +11100,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9bf141df4247d52fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9bf141df4247d52fUL)] public class Result_Bar : ICapnpSerializable { public const UInt64 typeId = 0x9bf141df4247d52fUL; @@ -11144,7 +11145,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd9ac8abb2a91cfbcUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd9ac8abb2a91cfbcUL)] public class Params_Baz : ICapnpSerializable { public const UInt64 typeId = 0xd9ac8abb2a91cfbcUL; @@ -11204,7 +11205,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9b99d14f2f375b2dUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9b99d14f2f375b2dUL)] public class Result_Baz : ICapnpSerializable { public const UInt64 typeId = 0x9b99d14f2f375b2dUL; @@ -11250,7 +11251,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe4e9bac98670b748UL), Proxy(typeof(TestExtends_Proxy)), Skeleton(typeof(TestExtends_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe4e9bac98670b748UL), Proxy(typeof(TestExtends_Proxy)), Skeleton(typeof(TestExtends_Skeleton))] public interface ITestExtends : Capnproto_test.Capnp.Test.ITestInterface { Task Qux(CancellationToken cancellationToken_ = default); @@ -11383,7 +11384,7 @@ namespace Capnproto_test.Capnp.Test public static class TestExtends { - [TypeId(0x83a4bc5471363f17UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x83a4bc5471363f17UL)] public class Params_Qux : ICapnpSerializable { public const UInt64 typeId = 0x83a4bc5471363f17UL; @@ -11428,7 +11429,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8e4b3d1a3e2753ddUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8e4b3d1a3e2753ddUL)] public class Result_Qux : ICapnpSerializable { public const UInt64 typeId = 0x8e4b3d1a3e2753ddUL; @@ -11473,7 +11474,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xacf67532a7e7bad9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xacf67532a7e7bad9UL)] public class Result_Corge : ICapnpSerializable { public const UInt64 typeId = 0xacf67532a7e7bad9UL; @@ -11518,7 +11519,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf3b834e851ea8af6UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf3b834e851ea8af6UL)] public class Params_Grault : ICapnpSerializable { public const UInt64 typeId = 0xf3b834e851ea8af6UL; @@ -11564,7 +11565,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x98d7e0ef61488783UL), Proxy(typeof(TestExtends2_Proxy)), Skeleton(typeof(TestExtends2_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x98d7e0ef61488783UL), Proxy(typeof(TestExtends2_Proxy)), Skeleton(typeof(TestExtends2_Skeleton))] public interface ITestExtends2 : Capnproto_test.Capnp.Test.ITestExtends { } @@ -11658,7 +11659,7 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 11013518732491786115UL; } - [TypeId(0xa5a404caa61d4cd0UL), Proxy(typeof(TestPipeline_Proxy)), Skeleton(typeof(TestPipeline_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa5a404caa61d4cd0UL), Proxy(typeof(TestPipeline_Proxy)), Skeleton(typeof(TestPipeline_Skeleton))] public interface ITestPipeline : IDisposable { Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint N, Capnproto_test.Capnp.Test.ITestInterface InCap, CancellationToken cancellationToken_ = default); @@ -11774,7 +11775,7 @@ namespace Capnproto_test.Capnp.Test public static class TestPipeline { - [TypeId(0xb0b29e51db0e26b1UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb0b29e51db0e26b1UL)] public class Box : ICapnpSerializable { public const UInt64 typeId = 0xb0b29e51db0e26b1UL; @@ -11834,7 +11835,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9442ad5a1d2c8acbUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9442ad5a1d2c8acbUL)] public class AnyBox : ICapnpSerializable { public const UInt64 typeId = 0x9442ad5a1d2c8acbUL; @@ -11894,7 +11895,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc7e8df5096257034UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc7e8df5096257034UL)] public class Params_GetCap : ICapnpSerializable { public const UInt64 typeId = 0xc7e8df5096257034UL; @@ -11969,7 +11970,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb2442a9e0ba28fdfUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb2442a9e0ba28fdfUL)] public class Result_GetCap : ICapnpSerializable { public const UInt64 typeId = 0xb2442a9e0ba28fdfUL; @@ -12044,7 +12045,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa604ee63cf37819fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa604ee63cf37819fUL)] public class Params_TestPointers : ICapnpSerializable { public const UInt64 typeId = 0xa604ee63cf37819fUL; @@ -12134,7 +12135,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8eda54756c6070d6UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8eda54756c6070d6UL)] public class Result_TestPointers : ICapnpSerializable { public const UInt64 typeId = 0x8eda54756c6070d6UL; @@ -12179,7 +12180,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf8e36b53ab093d4eUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf8e36b53ab093d4eUL)] public class Params_GetAnyCap : ICapnpSerializable { public const UInt64 typeId = 0xf8e36b53ab093d4eUL; @@ -12254,7 +12255,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xbf44b4c94c26ef79UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbf44b4c94c26ef79UL)] public class Result_GetAnyCap : ICapnpSerializable { public const UInt64 typeId = 0xbf44b4c94c26ef79UL; @@ -12330,7 +12331,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa0e77035bdff0051UL), Proxy(typeof(TestCallOrder_Proxy)), Skeleton(typeof(TestCallOrder_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa0e77035bdff0051UL), Proxy(typeof(TestCallOrder_Proxy)), Skeleton(typeof(TestCallOrder_Skeleton))] public interface ITestCallOrder : IDisposable { Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default); @@ -12380,7 +12381,7 @@ namespace Capnproto_test.Capnp.Test public static class TestCallOrder { - [TypeId(0x8f1e8cd56ceb74dcUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8f1e8cd56ceb74dcUL)] public class Params_GetCallSequence : ICapnpSerializable { public const UInt64 typeId = 0x8f1e8cd56ceb74dcUL; @@ -12440,7 +12441,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdedbb6bf3810eab7UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdedbb6bf3810eab7UL)] public class Result_GetCallSequence : ICapnpSerializable { public const UInt64 typeId = 0xdedbb6bf3810eab7UL; @@ -12501,7 +12502,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xddd699207eb8e23bUL), Proxy(typeof(TestTailCallee_Proxy)), Skeleton(typeof(TestTailCallee_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddd699207eb8e23bUL), Proxy(typeof(TestTailCallee_Proxy)), Skeleton(typeof(TestTailCallee_Skeleton))] public interface ITestTailCallee : IDisposable { Task Foo(int I, string T, CancellationToken cancellationToken_ = default); @@ -12555,7 +12556,7 @@ namespace Capnproto_test.Capnp.Test public static class TestTailCallee { - [TypeId(0xa9ed2e5a9fd53d19UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa9ed2e5a9fd53d19UL)] public class TailResult : ICapnpSerializable { public const UInt64 typeId = 0xa9ed2e5a9fd53d19UL; @@ -12645,7 +12646,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc5e1efc325614957UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc5e1efc325614957UL)] public class Params_Foo : ICapnpSerializable { public const UInt64 typeId = 0xc5e1efc325614957UL; @@ -12721,7 +12722,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x870bf40110ce3035UL), Proxy(typeof(TestTailCaller_Proxy)), Skeleton(typeof(TestTailCaller_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x870bf40110ce3035UL), Proxy(typeof(TestTailCaller_Proxy)), Skeleton(typeof(TestTailCaller_Skeleton))] public interface ITestTailCaller : IDisposable { Task Foo(int I, Capnproto_test.Capnp.Test.ITestTailCallee Callee, CancellationToken cancellationToken_ = default); @@ -12775,7 +12776,7 @@ namespace Capnproto_test.Capnp.Test public static class TestTailCaller { - [TypeId(0xb07a279515dc8ac5UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb07a279515dc8ac5UL)] public class Params_Foo : ICapnpSerializable { public const UInt64 typeId = 0xb07a279515dc8ac5UL; @@ -12851,7 +12852,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa38e5efe41e53a15UL), Proxy(typeof(TestHandle_Proxy)), Skeleton(typeof(TestHandle_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa38e5efe41e53a15UL), Proxy(typeof(TestHandle_Proxy)), Skeleton(typeof(TestHandle_Skeleton))] public interface ITestHandle : IDisposable { } @@ -12870,7 +12871,7 @@ namespace Capnproto_test.Capnp.Test public override ulong InterfaceId => 11785461720995412501UL; } - [TypeId(0xddc70bf9784133cfUL), Proxy(typeof(TestMoreStuff_Proxy)), Skeleton(typeof(TestMoreStuff_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddc70bf9784133cfUL), Proxy(typeof(TestMoreStuff_Proxy)), Skeleton(typeof(TestMoreStuff_Skeleton))] public interface ITestMoreStuff : Capnproto_test.Capnp.Test.ITestCallOrder { Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); @@ -13307,7 +13308,7 @@ namespace Capnproto_test.Capnp.Test public static class TestMoreStuff { - [TypeId(0x931ba418da60f6e4UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x931ba418da60f6e4UL)] public class Params_CallFoo : ICapnpSerializable { public const UInt64 typeId = 0x931ba418da60f6e4UL; @@ -13367,7 +13368,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9a28970beccecdd0UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9a28970beccecdd0UL)] public class Result_CallFoo : ICapnpSerializable { public const UInt64 typeId = 0x9a28970beccecdd0UL; @@ -13427,7 +13428,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfabc700c2ebe6378UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfabc700c2ebe6378UL)] public class Params_CallFooWhenResolved : ICapnpSerializable { public const UInt64 typeId = 0xfabc700c2ebe6378UL; @@ -13487,7 +13488,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa54ce1e9aa822f90UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa54ce1e9aa822f90UL)] public class Result_CallFooWhenResolved : ICapnpSerializable { public const UInt64 typeId = 0xa54ce1e9aa822f90UL; @@ -13547,7 +13548,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x94fe60465c95182bUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x94fe60465c95182bUL)] public class Params_NeverReturn : ICapnpSerializable { public const UInt64 typeId = 0x94fe60465c95182bUL; @@ -13607,7 +13608,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdef4e5fa6999c5dcUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdef4e5fa6999c5dcUL)] public class Result_NeverReturn : ICapnpSerializable { public const UInt64 typeId = 0xdef4e5fa6999c5dcUL; @@ -13667,7 +13668,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfe7c8fbb769d8e58UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfe7c8fbb769d8e58UL)] public class Params_Hold : ICapnpSerializable { public const UInt64 typeId = 0xfe7c8fbb769d8e58UL; @@ -13727,7 +13728,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf839fb1374d003c9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf839fb1374d003c9UL)] public class Result_Hold : ICapnpSerializable { public const UInt64 typeId = 0xf839fb1374d003c9UL; @@ -13772,7 +13773,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf8c5e5ef1edf83beUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf8c5e5ef1edf83beUL)] public class Params_CallHeld : ICapnpSerializable { public const UInt64 typeId = 0xf8c5e5ef1edf83beUL; @@ -13817,7 +13818,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe59935f160ac7578UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe59935f160ac7578UL)] public class Result_CallHeld : ICapnpSerializable { public const UInt64 typeId = 0xe59935f160ac7578UL; @@ -13877,7 +13878,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfeffc025fce317e3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfeffc025fce317e3UL)] public class Params_GetHeld : ICapnpSerializable { public const UInt64 typeId = 0xfeffc025fce317e3UL; @@ -13922,7 +13923,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xef4e146185af67ceUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xef4e146185af67ceUL)] public class Result_GetHeld : ICapnpSerializable { public const UInt64 typeId = 0xef4e146185af67ceUL; @@ -13982,7 +13983,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc07526f7e2e533b9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc07526f7e2e533b9UL)] public class Params_Echo : ICapnpSerializable { public const UInt64 typeId = 0xc07526f7e2e533b9UL; @@ -14042,7 +14043,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa6224536593d5b92UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa6224536593d5b92UL)] public class Result_Echo : ICapnpSerializable { public const UInt64 typeId = 0xa6224536593d5b92UL; @@ -14102,7 +14103,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa1cc32d87f3edeb1UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa1cc32d87f3edeb1UL)] public class Params_ExpectCancel : ICapnpSerializable { public const UInt64 typeId = 0xa1cc32d87f3edeb1UL; @@ -14162,7 +14163,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8a3eba1758c0916eUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8a3eba1758c0916eUL)] public class Result_ExpectCancel : ICapnpSerializable { public const UInt64 typeId = 0x8a3eba1758c0916eUL; @@ -14207,7 +14208,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x99160a25fa50fbf1UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x99160a25fa50fbf1UL)] public class Params_MethodWithDefaults : ICapnpSerializable { public const UInt64 typeId = 0x99160a25fa50fbf1UL; @@ -14299,7 +14300,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9c7e066f845a6c56UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9c7e066f845a6c56UL)] public class Result_MethodWithDefaults : ICapnpSerializable { public const UInt64 typeId = 0x9c7e066f845a6c56UL; @@ -14375,7 +14376,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xead024a301a092a1UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xead024a301a092a1UL)] public class Params_GetHandle : ICapnpSerializable { public const UInt64 typeId = 0xead024a301a092a1UL; @@ -14420,7 +14421,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc3490d75420a1fe8UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc3490d75420a1fe8UL)] public class Result_GetHandle : ICapnpSerializable { public const UInt64 typeId = 0xc3490d75420a1fe8UL; @@ -14480,7 +14481,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd8493f0e175d61f2UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd8493f0e175d61f2UL)] public class Params_GetNull : ICapnpSerializable { public const UInt64 typeId = 0xd8493f0e175d61f2UL; @@ -14525,7 +14526,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe6955d8ef1023671UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe6955d8ef1023671UL)] public class Result_GetNull : ICapnpSerializable { public const UInt64 typeId = 0xe6955d8ef1023671UL; @@ -14585,7 +14586,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x805df436f55dd07aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x805df436f55dd07aUL)] public class Params_GetEnormousString : ICapnpSerializable { public const UInt64 typeId = 0x805df436f55dd07aUL; @@ -14630,7 +14631,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x860e7512dc3925b0UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x860e7512dc3925b0UL)] public class Result_GetEnormousString : ICapnpSerializable { public const UInt64 typeId = 0x860e7512dc3925b0UL; @@ -14690,7 +14691,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xfb92899aeb0ee74fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xfb92899aeb0ee74fUL)] public class Params_MethodWithNullDefault : ICapnpSerializable { public const UInt64 typeId = 0xfb92899aeb0ee74fUL; @@ -14765,7 +14766,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8467348247305cf7UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8467348247305cf7UL)] public class Result_MethodWithNullDefault : ICapnpSerializable { public const UInt64 typeId = 0x8467348247305cf7UL; @@ -14811,7 +14812,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc07d8dcd80a69c0cUL), Proxy(typeof(TestMembrane_Proxy)), Skeleton(typeof(TestMembrane_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc07d8dcd80a69c0cUL), Proxy(typeof(TestMembrane_Proxy)), Skeleton(typeof(TestMembrane_Skeleton))] public interface ITestMembrane : IDisposable { Task MakeThing(CancellationToken cancellationToken_ = default); @@ -14985,7 +14986,7 @@ namespace Capnproto_test.Capnp.Test public static class TestMembrane { - [TypeId(0x9352e4e41f173917UL), Proxy(typeof(Thing_Proxy)), Skeleton(typeof(Thing_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9352e4e41f173917UL), Proxy(typeof(Thing_Proxy)), Skeleton(typeof(Thing_Skeleton))] public interface IThing : IDisposable { Task PassThrough(CancellationToken cancellationToken_ = default); @@ -15062,7 +15063,7 @@ namespace Capnproto_test.Capnp.Test public static class Thing { - [TypeId(0xff9bdcd05085d786UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xff9bdcd05085d786UL)] public class Params_PassThrough : ICapnpSerializable { public const UInt64 typeId = 0xff9bdcd05085d786UL; @@ -15107,7 +15108,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xee94bed3615ee745UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xee94bed3615ee745UL)] public class Params_Intercept : ICapnpSerializable { public const UInt64 typeId = 0xee94bed3615ee745UL; @@ -15153,7 +15154,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb0c6163faf291965UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb0c6163faf291965UL)] public class Result : ICapnpSerializable { public const UInt64 typeId = 0xb0c6163faf291965UL; @@ -15213,7 +15214,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd8ac2acc3ece6556UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd8ac2acc3ece6556UL)] public class Params_MakeThing : ICapnpSerializable { public const UInt64 typeId = 0xd8ac2acc3ece6556UL; @@ -15258,7 +15259,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe5d4904814ccbf29UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe5d4904814ccbf29UL)] public class Result_MakeThing : ICapnpSerializable { public const UInt64 typeId = 0xe5d4904814ccbf29UL; @@ -15318,7 +15319,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x945d9f634a6a29daUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x945d9f634a6a29daUL)] public class Params_CallPassThrough : ICapnpSerializable { public const UInt64 typeId = 0x945d9f634a6a29daUL; @@ -15393,7 +15394,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8749aac3375c5c71UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8749aac3375c5c71UL)] public class Params_CallIntercept : ICapnpSerializable { public const UInt64 typeId = 0x8749aac3375c5c71UL; @@ -15468,7 +15469,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x869a1b7ab34b42c9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x869a1b7ab34b42c9UL)] public class Params_Loopback : ICapnpSerializable { public const UInt64 typeId = 0x869a1b7ab34b42c9UL; @@ -15528,7 +15529,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xecd19398fd88ab5cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xecd19398fd88ab5cUL)] public class Result_Loopback : ICapnpSerializable { public const UInt64 typeId = 0xecd19398fd88ab5cUL; @@ -15588,7 +15589,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x8f6bb30cc62917ffUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8f6bb30cc62917ffUL)] public class Params_WaitForever : ICapnpSerializable { public const UInt64 typeId = 0x8f6bb30cc62917ffUL; @@ -15633,7 +15634,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc343a4907280be01UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc343a4907280be01UL)] public class Result_WaitForever : ICapnpSerializable { public const UInt64 typeId = 0xc343a4907280be01UL; @@ -15679,7 +15680,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x949449ad7c11fa5cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x949449ad7c11fa5cUL)] public class TestContainMembrane : ICapnpSerializable { public const UInt64 typeId = 0x949449ad7c11fa5cUL; @@ -15754,7 +15755,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdd2b66a791a279f0UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdd2b66a791a279f0UL)] public class TestTransferCap : ICapnpSerializable { public const UInt64 typeId = 0xdd2b66a791a279f0UL; @@ -15813,7 +15814,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc7263e8f88844abcUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc7263e8f88844abcUL)] public class Element : ICapnpSerializable { public const UInt64 typeId = 0xc7263e8f88844abcUL; @@ -15889,7 +15890,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9ae342d394247cfcUL), Proxy(typeof(TestKeywordMethods_Proxy)), Skeleton(typeof(TestKeywordMethods_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9ae342d394247cfcUL), Proxy(typeof(TestKeywordMethods_Proxy)), Skeleton(typeof(TestKeywordMethods_Skeleton))] public interface ITestKeywordMethods : IDisposable { Task Delete(CancellationToken cancellationToken_ = default); @@ -16004,7 +16005,7 @@ namespace Capnproto_test.Capnp.Test public static class TestKeywordMethods { - [TypeId(0xca3a89cdeb6bd6b7UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xca3a89cdeb6bd6b7UL)] public class Params_Delete : ICapnpSerializable { public const UInt64 typeId = 0xca3a89cdeb6bd6b7UL; @@ -16049,7 +16050,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xeeb5843598307592UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xeeb5843598307592UL)] public class Result_Delete : ICapnpSerializable { public const UInt64 typeId = 0xeeb5843598307592UL; @@ -16094,7 +16095,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9cf5a8313c5db036UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9cf5a8313c5db036UL)] public class Params_Class : ICapnpSerializable { public const UInt64 typeId = 0x9cf5a8313c5db036UL; @@ -16139,7 +16140,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc0253868ac12e7d8UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc0253868ac12e7d8UL)] public class Result_Class : ICapnpSerializable { public const UInt64 typeId = 0xc0253868ac12e7d8UL; @@ -16184,7 +16185,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa4a08763833c7757UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa4a08763833c7757UL)] public class Params_Void : ICapnpSerializable { public const UInt64 typeId = 0xa4a08763833c7757UL; @@ -16229,7 +16230,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xde82773089c0aeabUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xde82773089c0aeabUL)] public class Result_Void : ICapnpSerializable { public const UInt64 typeId = 0xde82773089c0aeabUL; @@ -16274,7 +16275,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x99817360625e8ca3UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x99817360625e8ca3UL)] public class Params_Return : ICapnpSerializable { public const UInt64 typeId = 0x99817360625e8ca3UL; @@ -16319,7 +16320,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xb70872e07eaa992fUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb70872e07eaa992fUL)] public class Result_Return : ICapnpSerializable { public const UInt64 typeId = 0xb70872e07eaa992fUL; @@ -16365,7 +16366,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xea72cc77253798cdUL), Proxy(typeof(TestAuthenticatedBootstrap_Proxy<>)), Skeleton(typeof(TestAuthenticatedBootstrap_Skeleton<>))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xea72cc77253798cdUL), Proxy(typeof(TestAuthenticatedBootstrap_Proxy<>)), Skeleton(typeof(TestAuthenticatedBootstrap_Skeleton<>))] public interface ITestAuthenticatedBootstrap : IDisposable where TVatId : class { Task GetCallerId(CancellationToken cancellationToken_ = default); @@ -16420,7 +16421,7 @@ namespace Capnproto_test.Capnp.Test public static class TestAuthenticatedBootstrap where TVatId : class { - [TypeId(0x8ec30e2451f1cffeUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8ec30e2451f1cffeUL)] public class Params_GetCallerId : ICapnpSerializable { public const UInt64 typeId = 0x8ec30e2451f1cffeUL; @@ -16465,7 +16466,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc71cf776034a3e67UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc71cf776034a3e67UL)] public class Result_GetCallerId : ICapnpSerializable { public const UInt64 typeId = 0xc71cf776034a3e67UL; @@ -16526,7 +16527,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xceba982cb629f6c2UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xceba982cb629f6c2UL)] public class TestSturdyRef : ICapnpSerializable { public const UInt64 typeId = 0xceba982cb629f6c2UL; @@ -16601,7 +16602,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xe02d3bbe1010e342UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe02d3bbe1010e342UL)] public class TestSturdyRefHostId : ICapnpSerializable { public const UInt64 typeId = 0xe02d3bbe1010e342UL; @@ -16661,7 +16662,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xaeb2ad168e2f5697UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xaeb2ad168e2f5697UL)] public class TestSturdyRefObjectId : ICapnpSerializable { public const UInt64 typeId = 0xaeb2ad168e2f5697UL; @@ -16720,7 +16721,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xef428f2f67c4d439UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xef428f2f67c4d439UL)] public enum Tag : ushort { testInterface, @@ -16732,7 +16733,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x9e5c574772b1d462UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9e5c574772b1d462UL)] public class TestProvisionId : ICapnpSerializable { public const UInt64 typeId = 0x9e5c574772b1d462UL; @@ -16777,7 +16778,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xea2fb7dca9cdbdeaUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xea2fb7dca9cdbdeaUL)] public class TestRecipientId : ICapnpSerializable { public const UInt64 typeId = 0xea2fb7dca9cdbdeaUL; @@ -16822,7 +16823,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xa805157b98b65469UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa805157b98b65469UL)] public class TestThirdPartyCapId : ICapnpSerializable { public const UInt64 typeId = 0xa805157b98b65469UL; @@ -16867,7 +16868,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf4c58a8ebcd0f600UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf4c58a8ebcd0f600UL)] public class TestJoinResult : ICapnpSerializable { public const UInt64 typeId = 0xf4c58a8ebcd0f600UL; @@ -16912,7 +16913,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd1fd8e9caf2a5d58UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd1fd8e9caf2a5d58UL)] public class TestNameAnnotation : ICapnpSerializable { public const UInt64 typeId = 0xd1fd8e9caf2a5d58UL; @@ -17076,7 +17077,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0x89d9d1626b34017cUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x89d9d1626b34017cUL)] public class badlyNamedUnion : ICapnpSerializable { public const UInt64 typeId = 0x89d9d1626b34017cUL; @@ -17208,7 +17209,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xc3594bce5b24b722UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc3594bce5b24b722UL)] public class badlyNamedGroup : ICapnpSerializable { public const UInt64 typeId = 0xc3594bce5b24b722UL; @@ -17253,7 +17254,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf610d1deb4c9e84aUL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf610d1deb4c9e84aUL)] public enum BadlyNamedEnum : ushort { foo, @@ -17261,7 +17262,7 @@ namespace Capnproto_test.Capnp.Test baz } - [TypeId(0xbe406b6341d52284UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbe406b6341d52284UL)] public class NestedStruct : ICapnpSerializable { public const UInt64 typeId = 0xbe406b6341d52284UL; @@ -17335,7 +17336,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xf6cb3f9c7a4322e0UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf6cb3f9c7a4322e0UL)] public enum DeeplyNestedEnum : ushort { quux, @@ -17345,7 +17346,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xd112a69d31ed918bUL), Proxy(typeof(TestNameAnnotationInterface_Proxy)), Skeleton(typeof(TestNameAnnotationInterface_Skeleton))] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd112a69d31ed918bUL), Proxy(typeof(TestNameAnnotationInterface_Proxy)), Skeleton(typeof(TestNameAnnotationInterface_Skeleton))] public interface ITestNameAnnotationInterface : IDisposable { Task BadlyNamedMethod(byte BadlyNamedParam, CancellationToken cancellationToken_ = default); @@ -17389,7 +17390,7 @@ namespace Capnproto_test.Capnp.Test public static class TestNameAnnotationInterface { - [TypeId(0xc12efc3b075adfe9UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc12efc3b075adfe9UL)] public class Params_BadlyNamedMethod : ICapnpSerializable { public const UInt64 typeId = 0xc12efc3b075adfe9UL; @@ -17449,7 +17450,7 @@ namespace Capnproto_test.Capnp.Test } } - [TypeId(0xdcc3cdb4b28f6c86UL)] + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdcc3cdb4b28f6c86UL)] public class Result_BadlyNamedMethod : ICapnpSerializable { public const UInt64 typeId = 0xdcc3cdb4b28f6c86UL; diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index ecd5d8d..3b7eb41 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -173,5 +173,77 @@ namespace Capnp.Net.Runtime.Tests } } } + + [TestMethod] + public void ExportCapToThirdParty() + { + using (var server = SetupServer()) + { + var counters = new Counters(); + server.Main = new TestMoreStuffImpl3(); + + using (var client = SetupClient()) + { + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); + + using (var main = client.GetMain()) + { + var held = main.GetHeld().Eager(); + + using (var server2 = SetupServer()) + { + server2.Main = new TestMoreStuffImpl2(); + + using (var client2 = SetupClient()) + { + Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout)); + + using (var main2 = client2.GetMain()) + { + var fooTask = main2.CallFoo(held); + Assert.IsTrue(main.Hold(new TestInterfaceImpl(new Counters())).Wait(MediumNonDbgTimeout)); + Assert.IsTrue(fooTask.Wait(MediumNonDbgTimeout)); + Assert.AreEqual("bar", fooTask.Result); + } + } + } + } + } + } + } + + [TestMethod] + public void ExportTailCallCapToThirdParty() + { + using (var server = SetupServer()) + { + server.Main = new TestTailCallerImpl2(); + + using (var client = SetupClient()) + { + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); + + using (var main = client.GetMain()) + { + var callee = new TestTailCalleeImpl(new Counters()); + var fooTask = main.Foo(123, callee); + Assert.IsTrue(fooTask.Wait(MediumNonDbgTimeout)); + + using (var c = fooTask.Result.C) + using (var client2 = SetupClient()) + { + Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout)); + + using (var main2 = client2.GetMain()) + { + var fooTask2 = main2.Foo(123, null); + Assert.IsTrue(fooTask2.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(fooTask2.C().GetCallSequence(1).Wait(MediumNonDbgTimeout)); + } + } + } + } + } + } } } diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 6352051..000b810 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -193,9 +193,14 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(0, _enginePair.Endpoint1.ExportedCapabilityCount); Assert.AreEqual(0, _enginePair.Endpoint1.ImportedCapabilityCount); + Assert.AreEqual(0, _enginePair.Endpoint1.PendingQuestionCount); + Assert.AreEqual(0, _enginePair.Endpoint1.PendingAnswerCount); + Assert.AreEqual(0, _enginePair.Endpoint2.ExportedCapabilityCount); Assert.AreEqual(0, _enginePair.Endpoint2.ImportedCapabilityCount); - + Assert.AreEqual(0, _enginePair.Endpoint2.PendingQuestionCount); + Assert.AreEqual(0, _enginePair.Endpoint2.PendingAnswerCount); + GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); diff --git a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs index 729b34d..a641a6b 100644 --- a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs @@ -31,5 +31,10 @@ namespace Capnp.Rpc /// Task returning the proxy whose ownership will be taken over /// ConsumedCapability? Access(MemberAccessPath access, Task proxyTask); + + /// + /// Whether the question was asked as tail call + /// + bool IsTailCall { get; } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index 4bdbc8a..d969ddc 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -26,7 +26,11 @@ namespace Capnp.Rpc { async Task AwaitAnswer() { - return then(await promise.WhenReturned); + var result = await promise.WhenReturned; + if (promise.IsTailCall) + throw new TailCallNoDataException(); + + return then(result); } var rtask = AwaitAnswer(); diff --git a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs index 86c4db9..0843119 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs @@ -70,6 +70,8 @@ namespace Capnp.Rpc.Interception _cancelFromAlice.Dispose(); } } + + public bool IsTailCall => false; } /// @@ -194,7 +196,7 @@ namespace Capnp.Rpc.Interception _censorCapability = censorCapability; _promisedAnswer = new PromisedAnswer(this); _inArgs = inArgs; - _bob = null!; // Will beinitialized by setting Bob + _bob = null!; // Will be initialized later here CancelFromAlice = _promisedAnswer.CancelFromAlice; CancelToBob = CancelFromAlice; diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswer.cs b/Capnp.Net.Runtime/Rpc/LocalAnswer.cs index f1f3f86..516b6a7 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswer.cs @@ -25,6 +25,8 @@ namespace Capnp.Rpc public Task WhenReturned { get; } + public bool IsTailCall => false; + public ConsumedCapability Access(MemberAccessPath access) { return new LocalAnswerCapability(WhenReturned, access); diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index 2009b14..5884656 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -49,14 +49,14 @@ namespace Capnp.Rpc /// /// Question object was disposed. /// - Disposed = 16 + CanceledByDispose = 16 } readonly TaskCompletionSource _tcs = new TaskCompletionSource(); readonly uint _questionId; ConsumedCapability? _target; SerializerState? _inParams; - int _inhibitFinishCounter; + int _inhibitFinishCounter, _refCounter; internal PendingQuestion(IRpcEndpoint ep, uint id, ConsumedCapability? target, SerializerState? inParams) { @@ -91,10 +91,13 @@ namespace Capnp.Rpc /// public Task WhenReturned => _tcs.Task; - internal bool IsTailCall + /// + /// Whether this question represents a tail call + /// + public bool IsTailCall { get => StateFlags.HasFlag(State.TailCall); - set + internal set { if (value) StateFlags |= State.TailCall; @@ -102,7 +105,6 @@ namespace Capnp.Rpc StateFlags &= ~State.TailCall; } } - internal bool IsReturned => StateFlags.HasFlag(State.Returned); internal void DisallowFinish() { @@ -115,6 +117,23 @@ namespace Capnp.Rpc AutoFinish(); } + internal void AddRef() + { + lock (ReentrancyBlocker) + { + ++_refCounter; + } + } + + internal void Release() + { + lock (ReentrancyBlocker) + { + --_refCounter; + AutoFinish(); + } + } + const string ReturnDespiteTailCallMessage = "Peer sent actual results despite the question was sent as tail call. This was not expected and is a protocol error."; internal void OnReturn(DeserializerState results) @@ -189,11 +208,6 @@ namespace Capnp.Rpc RpcEndpoint.DeleteQuestion(this); } - internal void RequestFinish() - { - RpcEndpoint.Finish(_questionId); - } - void AutoFinish() { if (StateFlags.HasFlag(State.FinishRequested)) @@ -201,12 +215,13 @@ namespace Capnp.Rpc return; } - if ((_inhibitFinishCounter == 0 && StateFlags.HasFlag(State.Returned) && !StateFlags.HasFlag(State.TailCall)) - || StateFlags.HasFlag(State.Disposed)) + if ((!IsTailCall && _inhibitFinishCounter == 0 && StateFlags.HasFlag(State.Returned)) || + ( IsTailCall && _refCounter == 0 && StateFlags.HasFlag(State.Returned)) || + StateFlags.HasFlag(State.CanceledByDispose)) { StateFlags |= State.FinishRequested; - RequestFinish(); + RpcEndpoint.Finish(_questionId); } } @@ -338,9 +353,9 @@ namespace Capnp.Rpc lock (ReentrancyBlocker) { - if (!StateFlags.HasFlag(State.Disposed)) + if (!StateFlags.HasFlag(State.CanceledByDispose)) { - StateFlags |= State.Disposed; + StateFlags |= State.CanceledByDispose; justDisposed = true; AutoFinish(); diff --git a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs index 7ad404e..c88d523 100644 --- a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs @@ -70,7 +70,7 @@ namespace Capnp.Rpc } } - internal sealed override void AddRef() + internal override void AddRef() { lock (_reentrancyBlocker) { @@ -88,7 +88,7 @@ namespace Capnp.Rpc } } - internal sealed override void Release() + internal override void Release() { lock (_reentrancyBlocker) { diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index 734899b..38aaa6b 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -122,7 +122,7 @@ namespace Capnp.Rpc #if DebugEmbargos Logger.LogDebug("Call by proxy"); #endif - if (_question.StateFlags.HasFlag(PendingQuestion.State.Disposed)) + if (_question.StateFlags.HasFlag(PendingQuestion.State.CanceledByDispose)) { args.Dispose(); throw new ObjectDisposedException(nameof(PendingQuestion)); @@ -218,12 +218,12 @@ namespace Capnp.Rpc { lock (_question.ReentrancyBlocker) { - if (_question.StateFlags.HasFlag(PendingQuestion.State.Disposed)) + if (_question.StateFlags.HasFlag(PendingQuestion.State.CanceledByDispose)) throw new ObjectDisposedException(nameof(PendingQuestion)); - if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned)) + if (_question.StateFlags.HasFlag(PendingQuestion.State.Returned) && !_question.IsTailCall) { - ResolvedCap?.Export(endpoint, writer); + ResolvedCap!.Export(endpoint, writer); } else { @@ -238,10 +238,6 @@ namespace Capnp.Rpc } else if (_question.IsTailCall) { - // FIXME: Resource management! We should prevent finishing this - // cap as long as it is exported. Unfortunately, we cannot determine - // when it gets removed from the export table. - var vine = Vine.Create(this); uint id = endpoint.AllocateExport(vine, out bool first); @@ -260,8 +256,23 @@ namespace Capnp.Rpc protected async override void ReleaseRemotely() { - try { using var _ = await _whenResolvedProxy; } - catch { } + if (!_question.IsTailCall) + { + try { using var _ = await _whenResolvedProxy; } + catch { } + } + } + + internal override void AddRef() + { + base.AddRef(); + _question.AddRef(); + } + + internal override void Release() + { + _question.Release(); + base.Release(); } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index e7e0df1..021c8ec 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -175,6 +175,34 @@ namespace Capnp.Rpc } } + /// + /// Current number of unanswered questions + /// + public int PendingQuestionCount + { + get + { + lock (_reentrancyBlocker) + { + return _questionTable.Count; + } + } + } + + /// + /// Current number of unfinished answers + /// + public int PendingAnswerCount + { + get + { + lock (_reentrancyBlocker) + { + return _answerTable.Count; + } + } + } + void Tx(WireFrame frame) { try diff --git a/Capnp.Net.Runtime/Rpc/Skeleton.cs b/Capnp.Net.Runtime/Rpc/Skeleton.cs index 842bf06..32cdbaf 100644 --- a/Capnp.Net.Runtime/Rpc/Skeleton.cs +++ b/Capnp.Net.Runtime/Rpc/Skeleton.cs @@ -281,7 +281,7 @@ namespace Capnp.Rpc CheckCtsDisposal(); } - if (Impl is IDisposable disposable) + if (disposing && Impl is IDisposable disposable) { disposable.Dispose(); } diff --git a/Capnp.Net.Runtime/Rpc/TailCallNoDataException.cs b/Capnp.Net.Runtime/Rpc/TailCallNoDataException.cs new file mode 100644 index 0000000..ef16c27 --- /dev/null +++ b/Capnp.Net.Runtime/Rpc/TailCallNoDataException.cs @@ -0,0 +1,9 @@ +namespace Capnp.Rpc +{ + public class TailCallNoDataException: System.Exception + { + public TailCallNoDataException(): base("Because the question was asked as tail call, it won't return data") + { + } + } +} \ No newline at end of file From be10b356aa065d7b1ab992d8fa860bf927e833c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 5 Apr 2020 22:32:57 +0200 Subject: [PATCH 32/76] added test --- .../Mock/TestCapImplementations.cs | 22 ++++++++++--- .../TcpRpcAdvancedStuff.cs | 31 +++++++++++++++++++ 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs index 44e9014..e26b84d 100644 --- a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs @@ -958,7 +958,7 @@ namespace Capnp.Net.Runtime.Tests.GenImpls } } - class TestMoreStuffImpl3 : ITestMoreStuff + class TestMoreStuffImpl3 : ITestMoreStuff, ITestCallOrder { readonly TaskCompletionSource _heldCap = new TaskCompletionSource(); @@ -987,9 +987,18 @@ namespace Capnp.Net.Runtime.Tests.GenImpls } } - public Task Echo(ITestCallOrder Cap, CancellationToken cancellationToken_ = default) + int _echoCounter; + + public Task Echo(ITestCallOrder cap, CancellationToken cancellationToken_ = default) { - throw new NotImplementedException(); + if (_echoCounter++ < 20) + { + return Task.FromResult(((Proxy)cap).Cast(true).Echo(cap).Eager()); + } + else + { + return Task.FromResult(cap); + } } public Task ExpectCancel(ITestInterface Cap, CancellationToken cancellationToken_ = default) @@ -997,9 +1006,12 @@ namespace Capnp.Net.Runtime.Tests.GenImpls throw new NotImplementedException(); } - public Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default) + uint _counter; + + public Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) { - throw new NotImplementedException(); + Assert.AreEqual(_counter, expected); + return Task.FromResult(_counter++); } public Task GetEnormousString(CancellationToken cancellationToken_ = default) diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index 3b7eb41..f9483bf 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -245,5 +245,36 @@ namespace Capnp.Net.Runtime.Tests } } } + + [TestMethod] + public void SalamiTactics() + { + using (var server = SetupServer()) + { + server.Main = new TestMoreStuffImpl3(); + + using (var client = SetupClient()) + { + client.WhenConnected.Wait(); + + using (var main = client.GetMain()) + { + var echoTask = main.Echo(Proxy.Share(main)); + Assert.IsTrue(echoTask.Wait(MediumNonDbgTimeout)); + var echo = echoTask.Result; + var list = new Task[1000]; + for (uint i = 0; i < list.Length; i++) + { + list[i] = echo.GetCallSequence(i); + } + Assert.IsTrue(Task.WaitAll(list, MediumNonDbgTimeout)); + for (uint i = 0; i < list.Length; i++) + { + Assert.AreEqual(i, list[i].Result); + } + } + } + } + } } } From e3b6fd5c62d98cc39bd3669870ec58c0bc4e2cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Mon, 6 Apr 2020 21:12:08 +0200 Subject: [PATCH 33/76] factoring out Freeze/Unfreeze --- Capnp.Net.Runtime/Rpc/ConsumedCapability.cs | 3 +- Capnp.Net.Runtime/Rpc/ImportedCapability.cs | 9 +- .../Rpc/Interception/CensorCapability.cs | 9 +- Capnp.Net.Runtime/Rpc/LazyCapability.cs | 25 +--- .../Rpc/LocalAnswerCapability.cs | 10 +- Capnp.Net.Runtime/Rpc/LocalCapability.cs | 9 +- Capnp.Net.Runtime/Rpc/PromisedCapability.cs | 56 +------- Capnp.Net.Runtime/Rpc/Proxy.cs | 17 --- .../Rpc/RemoteAnswerCapability.cs | 40 +----- .../Rpc/RemoteResolvingCapability.cs | 131 ++++++++---------- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 20 +-- 11 files changed, 73 insertions(+), 256 deletions(-) diff --git a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs index 3faa492..675fa97 100644 --- a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs @@ -16,8 +16,7 @@ namespace Capnp.Rpc /// protected abstract void ReleaseRemotely(); internal abstract Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer); - internal abstract void Freeze(out IRpcEndpoint? boundEndpoint); - internal abstract void Unfreeze(); + internal abstract IRpcEndpoint? Endpoint { get; } internal abstract void AddRef(); internal abstract void Release(); diff --git a/Capnp.Net.Runtime/Rpc/ImportedCapability.cs b/Capnp.Net.Runtime/Rpc/ImportedCapability.cs index 5564351..ca9d75a 100644 --- a/Capnp.Net.Runtime/Rpc/ImportedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/ImportedCapability.cs @@ -28,14 +28,7 @@ namespace Capnp.Rpc return call; } - internal override void Freeze(out IRpcEndpoint boundEndpoint) - { - boundEndpoint = _ep; - } - - internal override void Unfreeze() - { - } + internal override IRpcEndpoint? Endpoint => _ep; internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER capDesc) { diff --git a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs index 0889c87..d6f1fbd 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs @@ -35,13 +35,6 @@ namespace Capnp.Rpc.Interception return null; } - internal override void Freeze(out IRpcEndpoint? boundEndpoint) - { - boundEndpoint = null; - } - - internal override void Unfreeze() - { - } + internal override IRpcEndpoint? Endpoint => null; } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index 3e11953..1289280 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -33,30 +33,7 @@ namespace Capnp.Rpc _capTask = AwaitCap(); } - internal override void Freeze(out IRpcEndpoint? boundEndpoint) - { - if (WhenResolved.IsCompleted) - { - boundEndpoint = null; - - try - { - _capTask.Result?.Freeze(out boundEndpoint); - } - catch (AggregateException exception) - { - throw exception.InnerException!; - } - } - else - { - boundEndpoint = null; - } - } - - internal override void Unfreeze() - { - } + internal override IRpcEndpoint? Endpoint => null; internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs index e29a1b3..bfd9208 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs @@ -29,15 +29,7 @@ namespace Capnp.Rpc } - internal override void Freeze(out IRpcEndpoint? boundEndpoint) - { - boundEndpoint = null; - } - - internal override void Unfreeze() - { - } - + internal override IRpcEndpoint? Endpoint => null; public Task WhenResolved => _whenResolvedProxy; diff --git a/Capnp.Net.Runtime/Rpc/LocalCapability.cs b/Capnp.Net.Runtime/Rpc/LocalCapability.cs index 3e1954a..c3ab966 100644 --- a/Capnp.Net.Runtime/Rpc/LocalCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalCapability.cs @@ -52,14 +52,7 @@ namespace Capnp.Rpc return null; } - internal override void Freeze(out IRpcEndpoint? boundEndpoint) - { - boundEndpoint = null; - } - - internal override void Unfreeze() - { - } + internal override IRpcEndpoint? Endpoint => null; protected override void ReleaseRemotely() { diff --git a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs index 0b5bfbf..779f5ab 100644 --- a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs @@ -23,61 +23,7 @@ namespace Capnp.Rpc public override Task WhenResolved => _resolvedCap.Task; public override T? GetResolvedCapability() where T: class => _whenResolvedProxy.GetResolvedCapability(); - internal override void Freeze(out IRpcEndpoint? boundEndpoint) - { - lock (_reentrancyBlocker) - { - if (_resolvedCap.Task.IsCompleted && _pendingCallsOnPromise == 0) - { - boundEndpoint = null; - - try - { - _resolvedCap.Task.Result?.Freeze(out boundEndpoint); - } - catch (AggregateException exception) - { - throw exception.InnerException!; - } - } - else - { - Debug.Assert(!_released); - ++_pendingCallsOnPromise; - - boundEndpoint = _ep; - } - } - } - - internal override void Unfreeze() - { - bool release = false; - - lock (_reentrancyBlocker) - { - if (_pendingCallsOnPromise == 0) - { - _resolvedCap.Task.Result?.Unfreeze(); - } - else - { - Debug.Assert(_pendingCallsOnPromise > 0); - Debug.Assert(!_released); - - if (--_pendingCallsOnPromise == 0 && _resolvedCap.Task.IsCompleted) - { - release = true; - _released = true; - } - } - } - - if (release) - { - _ep.ReleaseImport(_remoteId); - } - } + internal override IRpcEndpoint? Endpoint => _ep; internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index 34f09c1..419826e 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -238,23 +238,6 @@ namespace Capnp.Rpc } } - internal void Freeze(out IRpcEndpoint? boundEndpoint) - { - if (_disposedValue) - throw new ObjectDisposedException(nameof(Proxy)); - - boundEndpoint = null; - ConsumedCap?.Freeze(out boundEndpoint); - } - - internal void Unfreeze() - { - if (_disposedValue) - throw new ObjectDisposedException(nameof(Proxy)); - - ConsumedCap?.Unfreeze(); - } - #if DebugFinalizers string CreatorStackTrace { get; set; } #endif diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index 38aaa6b..214a077 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -174,45 +174,7 @@ namespace Capnp.Rpc return call; } - internal override void Freeze(out IRpcEndpoint? boundEndpoint) - { - lock (_question.ReentrancyBlocker) - { - if ( _question.StateFlags.HasFlag(PendingQuestion.State.Returned) && - !_question.StateFlags.HasFlag(PendingQuestion.State.TailCall) && - _pendingCallsOnPromise == 0) - { - if (ResolvedCap == null) - { - throw new RpcException("Answer did not resolve to expected capability"); - } - - ResolvedCap.Freeze(out boundEndpoint); - } - else - { - ++_pendingCallsOnPromise; - _question.DisallowFinish(); - boundEndpoint = _ep; - } - } - } - - internal override void Unfreeze() - { - lock (_question.ReentrancyBlocker) - { - if (_pendingCallsOnPromise > 0) - { - --_pendingCallsOnPromise; - _question.AllowFinish(); - } - else - { - ResolvedCap?.Unfreeze(); - } - } - } + internal override IRpcEndpoint Endpoint => _ep; internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { diff --git a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs index 6f3ba0b..c8f4108 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs @@ -37,91 +37,78 @@ namespace Capnp.Rpc try { - ResolvedCap.Freeze(out var resolvedCapEndpoint); - - try + if (ResolvedCap.Endpoint!= null && ResolvedCap.Endpoint != _ep) { - if (resolvedCapEndpoint != null && resolvedCapEndpoint != _ep) - { - // Carol lives in a different Vat C. - throw new NotImplementedException("Sorry, level 3 RPC is not yet supported."); - } + // Carol lives in a different Vat C. + throw new NotImplementedException("Sorry, level 3 RPC is not yet supported."); + } - if (ResolvedCap == null || - // If the capability resolves to null, disembargo must not be requested. - // Take the direct path, well-knowing that the call will result in an exception. + if (ResolvedCap.Endpoint != null || + //# Note that in the case where Carol actually lives in Vat B (i.e., the same vat that the promise + //# already pointed at), no embargo is needed, because the pipelined calls are delivered over the + //# same path as the later direct calls. - resolvedCapEndpoint != null || - //# Note that in the case where Carol actually lives in Vat B (i.e., the same vat that the promise - //# already pointed at), no embargo is needed, because the pipelined calls are delivered over the - //# same path as the later direct calls. + (_disembargo == null && _pendingCallsOnPromise == 0) || + // No embargo is needed since all outstanding replies have returned - (_disembargo == null && _pendingCallsOnPromise == 0) || - // No embargo is needed since all outstanding replies have returned - - _disembargo?.IsCompleted == true - // Disembargo has returned - ) + _disembargo?.IsCompleted == true + // Disembargo has returned + ) + { +#if DebugEmbargos + Logger.LogDebug("Direct call"); +#endif + using var proxy = new Proxy(ResolvedCap); + return proxy.Call(interfaceId, methodId, args, default); + } + else + { + if (_disembargo == null) { #if DebugEmbargos - Logger.LogDebug("Direct call"); + Logger.LogDebug("Requesting disembargo"); #endif - using var proxy = new Proxy(ResolvedCap); - return proxy.Call(interfaceId, methodId, args, default); + _disembargo = _ep.RequestSenderLoopback(GetMessageTarget); } else { - if (_disembargo == null) - { #if DebugEmbargos - Logger.LogDebug("Requesting disembargo"); + Logger.LogDebug("Waiting for requested disembargo"); #endif - _disembargo = _ep.RequestSenderLoopback(GetMessageTarget); - } - else - { -#if DebugEmbargos - Logger.LogDebug("Waiting for requested disembargo"); -#endif - } - - var cancellationTokenSource = new CancellationTokenSource(); - - var callAfterDisembargo = _disembargo.ContinueWith(_ => - { - // Two reasons for ignoring exceptions on the previous task (i.e. not _.Wait()ing): - // 1. A faulting predecessor, especially due to cancellation, must not have any impact on this one. - // 2. A faulting disembargo request would imply that the other side cannot send pending requests anyway. - - if (cancellationTokenSource.Token.IsCancellationRequested) - { - args.Dispose(); - cancellationTokenSource.Token.ThrowIfCancellationRequested(); - } - - using var proxy = new Proxy(ResolvedCap); - return proxy.Call(interfaceId, methodId, args, default); - - }, TaskContinuationOptions.ExecuteSynchronously); - - _disembargo = callAfterDisembargo; - - async Task AwaitAnswer() - { - var promisedAnswer = await callAfterDisembargo; - - using (cancellationTokenSource.Token.Register(promisedAnswer.Dispose)) - { - return await promisedAnswer.WhenReturned; - } - } - - return new LocalAnswer(cancellationTokenSource, AwaitAnswer()); } - } - finally - { - ResolvedCap.Unfreeze(); + + var cancellationTokenSource = new CancellationTokenSource(); + + var callAfterDisembargo = _disembargo.ContinueWith(_ => + { + // Two reasons for ignoring exceptions on the previous task (i.e. not _.Wait()ing): + // 1. A faulting predecessor, especially due to cancellation, must not have any impact on this one. + // 2. A faulting disembargo request would imply that the other side cannot send pending requests anyway. + + if (cancellationTokenSource.Token.IsCancellationRequested) + { + args.Dispose(); + cancellationTokenSource.Token.ThrowIfCancellationRequested(); + } + + using var proxy = new Proxy(ResolvedCap); + return proxy.Call(interfaceId, methodId, args, default); + + }, TaskContinuationOptions.ExecuteSynchronously); + + _disembargo = callAfterDisembargo; + + async Task AwaitAnswer() + { + var promisedAnswer = await callAfterDisembargo; + + using (cancellationTokenSource.Token.Register(promisedAnswer.Dispose)) + { + return await promisedAnswer.WhenReturned; + } + } + + return new LocalAnswer(cancellationTokenSource, AwaitAnswer()); } } catch (System.Exception exception) diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 021c8ec..ed13068 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -890,27 +890,19 @@ namespace Capnp.Rpc try { using var proxy = await t; - proxy.Freeze(out var boundEndpoint); - try + if (proxy.ConsumedCap?.Endpoint == this) { - if (boundEndpoint == this) - { #if DebugEmbargos Logger.LogDebug($"Sender loopback disembargo. Thread = {Thread.CurrentThread.Name}"); #endif - Tx(mb.Frame); - } - else - { - Logger.LogWarning("Sender loopback request: Peer asked for disembargoing an answer which does not resolve back to the sender."); - - throw new RpcProtocolErrorException("'Disembargo': Answer does not resolve back to me"); - } + Tx(mb.Frame); } - finally + else { - proxy.Unfreeze(); + Logger.LogWarning("Sender loopback request: Peer asked for disembargoing an answer which does not resolve back to the sender."); + + throw new RpcProtocolErrorException("'Disembargo': Answer does not resolve back to me"); } } catch (System.Exception exception) From 747d350b20a102b6720ef5c030ba55e18c5349de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Mon, 6 Apr 2020 21:55:02 +0200 Subject: [PATCH 34/76] moved Endpoint prop. to RemoteCapability --- Capnp.Net.Runtime/Rpc/ConsumedCapability.cs | 2 -- Capnp.Net.Runtime/Rpc/ImportedCapability.cs | 2 -- .../Rpc/Interception/CensorCapability.cs | 2 -- Capnp.Net.Runtime/Rpc/LazyCapability.cs | 2 -- Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs | 2 -- Capnp.Net.Runtime/Rpc/LocalCapability.cs | 2 -- Capnp.Net.Runtime/Rpc/PromisedCapability.cs | 2 -- Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs | 2 -- Capnp.Net.Runtime/Rpc/RemoteCapability.cs | 2 ++ Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs | 13 +++---------- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 2 +- 11 files changed, 6 insertions(+), 27 deletions(-) diff --git a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs index 675fa97..594f375 100644 --- a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs @@ -16,8 +16,6 @@ namespace Capnp.Rpc /// protected abstract void ReleaseRemotely(); internal abstract Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer); - internal abstract IRpcEndpoint? Endpoint { get; } - internal abstract void AddRef(); internal abstract void Release(); diff --git a/Capnp.Net.Runtime/Rpc/ImportedCapability.cs b/Capnp.Net.Runtime/Rpc/ImportedCapability.cs index ca9d75a..0cb2be4 100644 --- a/Capnp.Net.Runtime/Rpc/ImportedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/ImportedCapability.cs @@ -28,8 +28,6 @@ namespace Capnp.Rpc return call; } - internal override IRpcEndpoint? Endpoint => _ep; - internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER capDesc) { if (endpoint == _ep) diff --git a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs index d6f1fbd..54f4754 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs @@ -34,7 +34,5 @@ namespace Capnp.Rpc.Interception writer.SenderHosted = endpoint.AllocateExport(MyVine, out bool _); return null; } - - internal override IRpcEndpoint? Endpoint => null; } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index 1289280..90f91a8 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -33,8 +33,6 @@ namespace Capnp.Rpc _capTask = AwaitCap(); } - internal override IRpcEndpoint? Endpoint => null; - internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { if (WhenResolved.ReplacementTaskIsCompletedSuccessfully()) diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs index bfd9208..be55b2c 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs @@ -29,8 +29,6 @@ namespace Capnp.Rpc } - internal override IRpcEndpoint? Endpoint => null; - public Task WhenResolved => _whenResolvedProxy; public T? GetResolvedCapability() where T : class => _whenResolvedProxy.GetResolvedCapability(); diff --git a/Capnp.Net.Runtime/Rpc/LocalCapability.cs b/Capnp.Net.Runtime/Rpc/LocalCapability.cs index c3ab966..140fa50 100644 --- a/Capnp.Net.Runtime/Rpc/LocalCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalCapability.cs @@ -52,8 +52,6 @@ namespace Capnp.Rpc return null; } - internal override IRpcEndpoint? Endpoint => null; - protected override void ReleaseRemotely() { } diff --git a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs index 779f5ab..1f3a782 100644 --- a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs @@ -23,8 +23,6 @@ namespace Capnp.Rpc public override Task WhenResolved => _resolvedCap.Task; public override T? GetResolvedCapability() where T: class => _whenResolvedProxy.GetResolvedCapability(); - internal override IRpcEndpoint? Endpoint => _ep; - internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { lock (_reentrancyBlocker) diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index 214a077..b2be02f 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -174,8 +174,6 @@ namespace Capnp.Rpc return call; } - internal override IRpcEndpoint Endpoint => _ep; - internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { lock (_question.ReentrancyBlocker) diff --git a/Capnp.Net.Runtime/Rpc/RemoteCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteCapability.cs index 1852c56..f767fff 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteCapability.cs @@ -13,6 +13,8 @@ namespace Capnp.Rpc _ep = ep; } + internal IRpcEndpoint Endpoint => _ep; + internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) { var call = SetupMessage(args, interfaceId, methodId); diff --git a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs index c8f4108..7ff6553 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs @@ -32,18 +32,11 @@ namespace Capnp.Rpc protected IPromisedAnswer CallOnResolution(ulong interfaceId, ushort methodId, DynamicSerializerState args) { - if (ResolvedCap == null) - throw new InvalidOperationException("Capability not yet resolved, calling on resolution not possible"); + var resolvedCap = ResolvedCap!; try { - if (ResolvedCap.Endpoint!= null && ResolvedCap.Endpoint != _ep) - { - // Carol lives in a different Vat C. - throw new NotImplementedException("Sorry, level 3 RPC is not yet supported."); - } - - if (ResolvedCap.Endpoint != null || + if (resolvedCap is RemoteCapability || //# Note that in the case where Carol actually lives in Vat B (i.e., the same vat that the promise //# already pointed at), no embargo is needed, because the pipelined calls are delivered over the //# same path as the later direct calls. @@ -58,7 +51,7 @@ namespace Capnp.Rpc #if DebugEmbargos Logger.LogDebug("Direct call"); #endif - using var proxy = new Proxy(ResolvedCap); + using var proxy = new Proxy(resolvedCap); return proxy.Call(interfaceId, methodId, args, default); } else diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index ed13068..5a55cd6 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -891,7 +891,7 @@ namespace Capnp.Rpc { using var proxy = await t; - if (proxy.ConsumedCap?.Endpoint == this) + if (proxy.ConsumedCap is RemoteCapability remote && remote.Endpoint == this) { #if DebugEmbargos Logger.LogDebug($"Sender loopback disembargo. Thread = {Thread.CurrentThread.Name}"); From 5a04f2f3dadf629c68e3ec4c52cc052ea94481fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Fri, 10 Apr 2020 00:01:12 +0200 Subject: [PATCH 35/76] coverage & fixes --- Capnp.Net.Runtime.Tests/Dtbdct.cs | 18 ++ .../Mock/TestCapImplementations.cs | 254 +++++++++++++++++- .../TcpRpcAdvancedStuff.cs | 27 +- Capnp.Net.Runtime.Tests/TcpRpcInterop.cs | 60 +++-- Capnp.Net.Runtime.Tests/Testsuite.cs | 69 +++++ Capnp.Net.Runtime.Tests/Util/TestBase.cs | 5 + Capnp.Net.Runtime/Capnp.Net.Runtime.csproj | 2 +- Capnp.Net.Runtime/Rpc/Impatient.cs | 16 +- Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 30 +-- Capnp.Net.Runtime/Rpc/Proxy.cs | 29 +- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 64 +++-- Capnp.Net.Runtime/Rpc/Vine.cs | 7 +- 12 files changed, 472 insertions(+), 109 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/Dtbdct.cs b/Capnp.Net.Runtime.Tests/Dtbdct.cs index fa48434..57ae39c 100644 --- a/Capnp.Net.Runtime.Tests/Dtbdct.cs +++ b/Capnp.Net.Runtime.Tests/Dtbdct.cs @@ -158,5 +158,23 @@ namespace Capnp.Net.Runtime.Tests { NewDtbdctTestbed().RunTest(Testsuite.ImportReceiverCanceled); } + + [TestMethod] + public void ButNoTailCall() + { + NewDtbdctTestbed().RunTest(Testsuite.ButNoTailCall); + } + + [TestMethod] + public void SecondIsTailCall() + { + NewDtbdctTestbed().RunTest(Testsuite.SecondIsTailCall); + } + + [TestMethod] + public void ReexportSenderPromise() + { + NewDtbdctTestbed().RunTest(Testsuite.ReexportSenderPromise); + } } } diff --git a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs index e26b84d..795d451 100644 --- a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs @@ -681,6 +681,72 @@ namespace Capnp.Net.Runtime.Tests.GenImpls } } } + + class TestTailCallerImpl3 : ITestTailCaller + { + public TestTailCallerImpl3() + { + } + + public void Dispose() + { + } + + public Task Foo(int i, ITestTailCallee callee, CancellationToken cancellationToken_) + { + using (callee) + { + var task1 = callee.Foo(i, "from TestTailCaller 1", cancellationToken_); + + async void FinishTask() + { + var r = await task1; + r.C.Dispose(); + } + + FinishTask(); + + var task2 = callee.Foo(i, "from TestTailCaller 2", cancellationToken_); + + async void AssertIsTailCall() + { + try + { + await task2; + Assert.Fail("Not a tail call"); + } + catch (TailCallNoDataException) + { + } + } + + AssertIsTailCall(); + + return task2; + } + } + } + + class TestTailCallerImpl4 : ITestTailCaller + { + public TestTailCallerImpl4() + { + } + + public void Dispose() + { + } + + public async Task Foo(int i, ITestTailCallee callee, CancellationToken cancellationToken_) + { + await Task.Yield(); + + using (callee) + { + return await callee.Foo(i, "from TestTailCaller", cancellationToken_); + } + } + } #endregion TestTailCaller #region TestTailCallee @@ -993,7 +1059,7 @@ namespace Capnp.Net.Runtime.Tests.GenImpls { if (_echoCounter++ < 20) { - return Task.FromResult(((Proxy)cap).Cast(true).Echo(cap).Eager()); + return Task.FromResult(((Proxy)cap).Cast(false).Echo(cap).Eager()); } else { @@ -1056,6 +1122,192 @@ namespace Capnp.Net.Runtime.Tests.GenImpls } } + class TestMoreStuffImpl4 : ITestMoreStuff, ITestCallOrder + { + readonly TaskCompletionSource _heldCap = new TaskCompletionSource(); + + public Task CallFoo(ITestInterface cap, CancellationToken cancellationToken_ = default) + { + using (cap) + { + return cap.Foo(123, true); + } + } + + public Task CallFooWhenResolved(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task CallHeld(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public async void Dispose() + { + using (var cap = await _heldCap.Task) + { + } + } + + public Task Echo(ITestCallOrder cap, CancellationToken cancellationToken_ = default) + { + using (var target = ((Proxy)cap).Cast(false)) + { + return Task.FromResult(target.Echo(cap).Eager()); + } + } + + public Task ExpectCancel(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + uint _counter; + + public Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) + { + Assert.AreEqual(_counter, expected); + return Task.FromResult(_counter++); + } + + public Task GetEnormousString(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task GetHandle(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task GetHeld(CancellationToken cancellationToken_ = default) + { + return Task.FromResult(_heldCap.Task.Eager(true)); + } + + public Task GetNull(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task Hold(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + _heldCap.SetResult(Cap); + return Task.CompletedTask; + } + + public Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task MethodWithNullDefault(string A, ITestInterface B, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task NeverReturn(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + } + + class TestMoreStuffImpl5 : ITestMoreStuff, ITestCallOrder + { + readonly TaskCompletionSource _heldCap = new TaskCompletionSource(); + + public Task CallFoo(ITestInterface cap, CancellationToken cancellationToken_ = default) + { + using (cap) + { + return cap.Foo(123, true); + } + } + + public Task CallFooWhenResolved(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task CallHeld(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public async void Dispose() + { + using (var cap = await _heldCap.Task) + { + } + } + + TaskCompletionSource _echoEnabled = new TaskCompletionSource(); + + public void EnableEcho() => _echoEnabled.SetResult(0); + + public async Task Echo(ITestCallOrder cap, CancellationToken cancellationToken_ = default) + { + await _echoEnabled.Task; + return cap; + } + + public Task ExpectCancel(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + uint _counter; + + public Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) + { + Assert.AreEqual(_counter, expected); + return Task.FromResult(_counter++); + } + + public Task GetEnormousString(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task GetHandle(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task GetHeld(CancellationToken cancellationToken_ = default) + { + return Task.FromResult(_heldCap.Task.Eager(true)); + } + + public Task GetNull(CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task Hold(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + _heldCap.SetResult(Cap); + return Task.CompletedTask; + } + + public Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task MethodWithNullDefault(string A, ITestInterface B, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + + public Task NeverReturn(ITestInterface Cap, CancellationToken cancellationToken_ = default) + { + throw new NotImplementedException(); + } + } + #endregion TestMoreStuff #region TestHandle diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index f9483bf..6d41fc9 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -261,20 +261,29 @@ namespace Capnp.Net.Runtime.Tests { var echoTask = main.Echo(Proxy.Share(main)); Assert.IsTrue(echoTask.Wait(MediumNonDbgTimeout)); - var echo = echoTask.Result; - var list = new Task[1000]; - for (uint i = 0; i < list.Length; i++) + using (var echo = echoTask.Result) { - list[i] = echo.GetCallSequence(i); - } - Assert.IsTrue(Task.WaitAll(list, MediumNonDbgTimeout)); - for (uint i = 0; i < list.Length; i++) - { - Assert.AreEqual(i, list[i].Result); + var list = new Task[1000]; + for (uint i = 0; i < list.Length; i++) + { + list[i] = echo.GetCallSequence(i); + } + Assert.IsTrue(Task.WaitAll(list, MediumNonDbgTimeout)); + for (uint i = 0; i < list.Length; i++) + { + Assert.AreEqual(i, list[i].Result); + } } } } } } + + + [TestMethod] + public void NoTailCallMt() + { + NewLocalhostTcpTestbed().RunTest(Testsuite.NoTailCallMt); + } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs index e093a27..5886456 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs @@ -415,20 +415,22 @@ namespace Capnp.Net.Runtime.Tests var callee = new TestTailCalleeImpl(calleeCallCount); var promise = main.Foo(456, callee, default); - var dependentCall0 = promise.C().GetCallSequence(0, default); + using (var c = promise.C()) + { + var dependentCall0 = c.GetCallSequence(0, default); - Assert.IsTrue(promise.Wait(MediumNonDbgTimeout)); - Assert.AreEqual(456u, promise.Result.I); - Assert.AreEqual("from TestTailCaller", promise.Result.T); + Assert.IsTrue(promise.Wait(MediumNonDbgTimeout)); + Assert.AreEqual(456u, promise.Result.I); + Assert.AreEqual("from TestTailCaller", promise.Result.T); - var dependentCall1 = promise.C().GetCallSequence(0, default); - var dependentCall2 = promise.C().GetCallSequence(0, default); - - AssertOutput(stdout, "foo"); - Assert.IsTrue(dependentCall0.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(dependentCall1.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(dependentCall2.Wait(MediumNonDbgTimeout)); + var dependentCall1 = c.GetCallSequence(0, default); + var dependentCall2 = c.GetCallSequence(0, default); + AssertOutput(stdout, "foo"); + Assert.IsTrue(dependentCall0.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(dependentCall1.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(dependentCall2.Wait(MediumNonDbgTimeout)); + } Assert.AreEqual(1, calleeCallCount.CallCount); } } @@ -523,28 +525,30 @@ namespace Capnp.Net.Runtime.Tests using (var main = client.GetMain()) { var tcs = new TaskCompletionSource(); - var eager = tcs.Task.Eager(true); + using (var eager = tcs.Task.Eager(true)) + { + var request = main.CallFoo(Proxy.Share(eager), default); + AssertOutput(stdout, "callFoo"); + var request2 = main.CallFooWhenResolved(Proxy.Share(eager), default); + AssertOutput(stdout, "callFooWhenResolved"); - var request = main.CallFoo(eager, default); - AssertOutput(stdout, "callFoo"); - var request2 = main.CallFooWhenResolved(eager, default); - AssertOutput(stdout, "callFooWhenResolved"); + var gcs = main.GetCallSequence(0, default); + AssertOutput(stdout, "getCallSequence"); + Assert.IsTrue(gcs.Wait(MediumNonDbgTimeout)); + Assert.AreEqual(2u, gcs.Result); - var gcs = main.GetCallSequence(0, default); - AssertOutput(stdout, "getCallSequence"); - Assert.IsTrue(gcs.Wait(MediumNonDbgTimeout)); - Assert.AreEqual(2u, gcs.Result); + var chainedCallCount = new Counters(); + var tiimpl = new TestInterfaceImpl(chainedCallCount); + tcs.SetResult(tiimpl); - var chainedCallCount = new Counters(); - var tiimpl = new TestInterfaceImpl(chainedCallCount); - tcs.SetResult(tiimpl); + Assert.IsTrue(request.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(request2.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(request.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(request2.Wait(MediumNonDbgTimeout)); + Assert.AreEqual("bar", request.Result); + Assert.AreEqual("bar", request2.Result); + Assert.AreEqual(2, chainedCallCount.CallCount); - Assert.AreEqual("bar", request.Result); - Assert.AreEqual("bar", request2.Result); - Assert.AreEqual(2, chainedCallCount.CallCount); + } AssertOutput(stdout, "fin"); AssertOutput(stdout, "fin"); diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs index 443beea..c64c0be 100644 --- a/Capnp.Net.Runtime.Tests/Testsuite.cs +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -749,5 +749,74 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(foo.IsCanceled); } } + + public static void ButNoTailCall(ITestbed testbed) + { + var impl = new TestMoreStuffImpl4(); + using (var main = testbed.ConnectMain(impl)) + { + var peer = new TestMoreStuffImpl5(); + var heldTask = main.Echo(peer); + + testbed.MustComplete(heldTask); + + var r = heldTask.Result as IResolvingCapability; + + peer.EnableEcho(); + + testbed.MustComplete(r.WhenResolved); + + heldTask.Result.Dispose(); + } + } + + public static void SecondIsTailCall(ITestbed testbed) + { + var impl = new TestTailCallerImpl3(); + using (var main = testbed.ConnectMain(impl)) + { + var callee = new TestTailCalleeImpl(new Counters()); + var task = main.Foo(123, callee); + testbed.MustComplete(task); + Assert.AreEqual("from TestTailCaller 2", task.Result.T); + } + } + + public static void NoTailCallMt(ITestbed testbed) + { + var impl = new TestTailCallerImpl4(); + using (var main = testbed.ConnectMain(impl)) + using (var callee = Proxy.Share(new TestTailCalleeImpl(new Counters()))) + { + var tasks = ParallelEnumerable + .Range(0, 1000) + .Select(async i => + { + var r = await main.Foo(i, Proxy.Share(callee)); + Assert.AreEqual((uint)i, r.I); + }) + .ToArray(); + + testbed.MustComplete(tasks); + Assert.IsFalse(tasks.Any(t => t.IsCanceled || t.IsFaulted)); + } + } + + public static void ReexportSenderPromise(ITestbed testbed) + { + var impl = new TestTailCallerImpl(new Counters()); + using (var main = testbed.ConnectMain(impl)) + { + var tcs = new TaskCompletionSource(); + using (var promise = Proxy.Share(tcs.Task.Eager(true))) + { + var task1 = main.Foo(1, Proxy.Share(promise)); + var task2 = main.Foo(2, Proxy.Share(promise)); + var callee = new TestTailCalleeImpl(new Counters()); + tcs.SetResult(callee); + testbed.MustComplete(task1, task2); + } + } + } } } diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 000b810..e40b7a1 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -242,11 +242,16 @@ namespace Capnp.Net.Runtime.Tests { (_server, _client) = SetupClientServerPair(); _client.WhenConnected.Wait(MediumNonDbgTimeout); + Assert.IsTrue(SpinWait.SpinUntil(() => _server.ConnectionCount > 0, MediumNonDbgTimeout)); + var conn = _server.Connections[0]; using (_server) using (_client) { action(this); + + Assert.IsTrue(SpinWait.SpinUntil(() => _client.SendCount == conn.RecvCount, MediumNonDbgTimeout)); + Assert.IsTrue(SpinWait.SpinUntil(() => conn.SendCount == _client.RecvCount, MediumNonDbgTimeout)); } } diff --git a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj index b7675b9..6f81750 100644 --- a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj +++ b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj @@ -29,7 +29,7 @@ - + DebugFinalizers diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index d969ddc..0f4685c 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -11,7 +12,7 @@ namespace Capnp.Rpc public static class Impatient { static readonly ConditionalWeakTable _taskTable = new ConditionalWeakTable(); - static readonly ThreadLocal _askingEndpoint = new ThreadLocal(); + static readonly ThreadLocal> _askingEndpoint = new ThreadLocal>(() => new Stack()); /// /// Attaches a continuation to the given promise and registers the resulting task for pipelining. @@ -171,8 +172,17 @@ namespace Capnp.Rpc internal static IRpcEndpoint? AskingEndpoint { - get => _askingEndpoint.Value; - set { _askingEndpoint.Value = value; } + get => _askingEndpoint.Value!.Count > 0 ? _askingEndpoint.Value.Peek() : null; + } + + internal static void PushAskingEndpoint(IRpcEndpoint endpoint) + { + _askingEndpoint.Value!.Push(endpoint); + } + + internal static void PopAskingEndpoint() + { + _askingEndpoint.Value!.Pop(); } /// diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index 5884656..5d6aa50 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -66,14 +66,6 @@ namespace Capnp.Rpc _inParams = inParams; StateFlags = inParams == null ? State.Sent : State.None; - if (inParams != null) - { - foreach (var cap in inParams.Caps!) - { - cap.AddRef(); - } - } - if (target != null) { target.AddRef(); @@ -282,22 +274,6 @@ namespace Capnp.Rpc return new RemoteAnswerCapability(this, access, proxyTask); } - static void ReleaseCaps(ConsumedCapability? target, SerializerState? inParams) - { - if (inParams != null) - { - foreach (var cap in inParams.Caps!) - { - cap.Release(); - } - } - - if (target != null) - { - target.Release(); - } - } - static void ReleaseOutCaps(DeserializerState outParams) { foreach (var cap in outParams.Caps!) @@ -327,8 +303,8 @@ namespace Capnp.Rpc Debug.Assert(msg.Call!.Target.which != MessageTarget.WHICH.undefined); var call = msg.Call; call.QuestionId = QuestionId; - call.SendResultsTo.which = IsTailCall ? - Call.sendResultsTo.WHICH.Yourself : + call.SendResultsTo.which = IsTailCall ? + Call.sendResultsTo.WHICH.Yourself : Call.sendResultsTo.WHICH.Caller; try @@ -341,7 +317,7 @@ namespace Capnp.Rpc OnException(exception); } - ReleaseCaps(target, inParams); + target?.Release(); } /// diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index 419826e..bcfa0be 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Logging; using System; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -25,10 +26,6 @@ namespace Capnp.Rpc return BareProxy.FromImpl(obj).Cast(true); } -#if DebugFinalizers - ILogger Logger { get; } = Logging.CreateLogger(); -#endif - bool _disposedValue = false; /// @@ -56,15 +53,23 @@ namespace Capnp.Rpc return CapabilityReflection.CreateProxy(ConsumedCap) as T; } + ConsumedCapability? _consumedCap; + /// /// Underlying low-level capability /// - protected internal ConsumedCapability? ConsumedCap { get; private set; } + protected internal ConsumedCapability? ConsumedCap => _disposedValue ? + throw new ObjectDisposedException(nameof(Proxy)) : _consumedCap; /// /// Whether is this a broken capability. /// - public bool IsNull => ConsumedCap == null; + public bool IsNull => _consumedCap == null; + + /// + /// Whether was called on this Proxy. + /// + public bool IsDisposed => _disposedValue; static async void DisposeCtrWhenReturned(CancellationTokenRegistration ctr, IPromisedAnswer answer) { @@ -134,12 +139,12 @@ namespace Capnp.Rpc if (cap == null) return; - ConsumedCap = cap; + _consumedCap = cap; cap.AddRef(); #if DebugFinalizers - if (ConsumedCap != null) - ConsumedCap.OwningProxy = this; + if (_consumedCap != null) + _consumedCap.OwningProxy = this; #endif } @@ -166,14 +171,14 @@ namespace Capnp.Rpc { if (disposing) { - ConsumedCap?.Release(); + _consumedCap?.Release(); } else { // When called from the Finalizer, we must not throw. // But when reference counting goes wrong, ConsumedCapability.Release() will throw an InvalidOperationException. // The only option here is to suppress that exception. - try { ConsumedCap?.Release(); } + try { _consumedCap?.Release(); } catch { } } @@ -187,7 +192,7 @@ namespace Capnp.Rpc ~Proxy() { #if DebugFinalizers - Logger?.LogWarning($"Caught orphaned Proxy, created from here: {CreatorStackTrace}."); + Debugger.Log(0, "DebugFinalizers", $"Caught orphaned Proxy, created from here: {CreatorStackTrace}."); #endif Dispose(false); diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 5a55cd6..c271d53 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -66,7 +66,7 @@ namespace Capnp.Rpc Dismissed } - static readonly ThreadLocal _tailCall = new ThreadLocal(); + static readonly ThreadLocal _deferredCall = new ThreadLocal(); static readonly ThreadLocal _canDeferCalls = new ThreadLocal(); ILogger Logger { get; } = Logging.CreateLogger(); @@ -81,6 +81,7 @@ namespace Capnp.Rpc readonly Dictionary _answerTable = new Dictionary(); readonly Dictionary> _pendingDisembargos = new Dictionary>(); readonly object _reentrancyBlocker = new object(); + readonly object _callReturnBlocker = new object(); long _recvCount; long _sendCount; @@ -284,16 +285,8 @@ namespace Capnp.Rpc if (_revExportTable.TryGetValue(providedCapability, out uint id)) { + _exportTable[id].AddRef(); first = false; - - if (_exportTable.TryGetValue(id, out var rc)) - { - rc.AddRef(); - } - else - { - Logger.LogError("Inconsistent export table: Capability with id {0} exists in reverse table only", id); - } } else { @@ -305,7 +298,6 @@ namespace Capnp.Rpc _revExportTable.Add(providedCapability, id); _exportTable.Add(id, new RefCounted(providedCapability)); - first = true; } @@ -407,8 +399,22 @@ namespace Capnp.Rpc } } + void DispatchDeferredCalls() + { + var call = _deferredCall.Value; + _deferredCall.Value = null; + call?.Send(); + } void ProcessCall(Call.READER req) + { + lock (_callReturnBlocker) + { + ProcessCallLocked(req); + } + } + + void ProcessCallLocked(Call.READER req) { Return.WRITER SetupReturn(MessageBuilder mb) { @@ -420,8 +426,10 @@ namespace Capnp.Rpc return ret; } - void ReturnCall(Action why) + void ReturnCallNoCapTable(Action why) { + DispatchDeferredCalls(); + var mb = MessageBuilder.Create(); mb.InitCapTable(); var ret = SetupReturn(mb); @@ -430,7 +438,10 @@ namespace Capnp.Rpc try { - Tx(mb.Frame); + lock (_callReturnBlocker) + { + Tx(mb.Frame); + } } catch (RpcException exception) { @@ -473,7 +484,7 @@ namespace Capnp.Rpc { Debug.Fail("Either answer or counter question must be present"); } - else if (aorcq.Answer != null || aorcq.Counterquestion != _tailCall.Value) + else if (aorcq.Answer != null || aorcq.Counterquestion != _deferredCall.Value) { var results = aorcq.Answer ?? (DynamicSerializerState)(await aorcq.Counterquestion!.WhenReturned); var ret = SetupReturn(results.MsgBuilder!); @@ -484,12 +495,13 @@ namespace Capnp.Rpc ret.which = Return.WHICH.Results; ret.Results!.Content = results.Rewrap(); ret.ReleaseParamCaps = releaseParamCaps; + DispatchDeferredCalls(); ExportCapTableAndSend(results, ret.Results); pendingAnswer.CapTable = ret.Results.CapTable; break; case Call.sendResultsTo.WHICH.Yourself: - ReturnCall(ret2 => + ReturnCallNoCapTable(ret2 => { ret2.which = Return.WHICH.ResultsSentElsewhere; ret2.ReleaseParamCaps = releaseParamCaps; @@ -499,11 +511,11 @@ namespace Capnp.Rpc } else if (aorcq.Counterquestion != null) { - _tailCall.Value = null; + _deferredCall.Value = null; aorcq.Counterquestion.IsTailCall = true; aorcq.Counterquestion.Send(); - ReturnCall(ret2 => + ReturnCallNoCapTable(ret2 => { ret2.which = Return.WHICH.TakeFromOtherQuestion; ret2.TakeFromOtherQuestion = aorcq.Counterquestion.QuestionId; @@ -513,7 +525,7 @@ namespace Capnp.Rpc } catch (TaskCanceledException) { - ReturnCall(ret => + ReturnCallNoCapTable(ret => { ret.which = Return.WHICH.Canceled; ret.ReleaseParamCaps = releaseParamCaps; @@ -521,7 +533,7 @@ namespace Capnp.Rpc } catch (System.Exception exception) { - ReturnCall(ret => + ReturnCallNoCapTable(ret => { ret.which = Return.WHICH.Exception; ret.Exception!.Reason = exception.Message; @@ -543,7 +555,7 @@ namespace Capnp.Rpc } finally { - ReturnCall(ret => + ReturnCallNoCapTable(ret => { ret.which = Return.WHICH.ResultsSentElsewhere; ret.ReleaseParamCaps = releaseParamCaps; @@ -600,7 +612,7 @@ namespace Capnp.Rpc } _canDeferCalls.Value = true; - Impatient.AskingEndpoint = this; + Impatient.PushAskingEndpoint(this); try { @@ -683,10 +695,8 @@ namespace Capnp.Rpc finally { _canDeferCalls.Value = false; - Impatient.AskingEndpoint = null; - var call = _tailCall.Value; - _tailCall.Value = null; - call?.Send(); + Impatient.PopAskingEndpoint(); + DispatchDeferredCalls(); } } @@ -1419,8 +1429,8 @@ namespace Capnp.Rpc if (_canDeferCalls.Value) { - _tailCall.Value?.Send(); - _tailCall.Value = question; + DispatchDeferredCalls(); + _deferredCall.Value = question; } else { diff --git a/Capnp.Net.Runtime/Rpc/Vine.cs b/Capnp.Net.Runtime/Rpc/Vine.cs index 3572f6c..1c4f29c 100644 --- a/Capnp.Net.Runtime/Rpc/Vine.cs +++ b/Capnp.Net.Runtime/Rpc/Vine.cs @@ -76,7 +76,12 @@ namespace Capnp.Rpc protected override void Dispose(bool disposing) { - Proxy.Dispose(); + if (disposing) + Proxy.Dispose(); + else + try { Proxy.Dispose(); } + catch { } + base.Dispose(disposing); } } From 3d0683288a3d9ad878c8878d1af2bbd15fded8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Fri, 10 Apr 2020 18:29:06 +0200 Subject: [PATCH 36/76] redesigned ConsumedCapability <> Skeleton conversion --- .../ProvidedCapabilityMock.cs | 2 +- .../ProvidedCapabilityMultiCallMock.cs | 2 +- Capnp.Net.Runtime.Tests/TcpRpc.cs | 8 +- Capnp.Net.Runtime.Tests/Testsuite.cs | 2 +- Capnp.Net.Runtime/DeserializerState.cs | 8 +- Capnp.Net.Runtime/Rpc/BareProxy.cs | 4 +- Capnp.Net.Runtime/Rpc/CapabilityReflection.cs | 2 +- Capnp.Net.Runtime/Rpc/ConsumedCapability.cs | 1 + Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs | 4 +- Capnp.Net.Runtime/Rpc/Impatient.cs | 4 +- Capnp.Net.Runtime/Rpc/ImportedCapability.cs | 2 +- .../Rpc/Interception/CallContext.cs | 34 ++-- .../Rpc/Interception/CensorCapability.cs | 4 +- .../Rpc/Interception/Interceptor.cs | 7 +- Capnp.Net.Runtime/Rpc/LazyCapability.cs | 15 +- Capnp.Net.Runtime/Rpc/LocalCapability.cs | 12 +- Capnp.Net.Runtime/Rpc/MemberAccessPath.cs | 4 +- Capnp.Net.Runtime/Rpc/NullCapability.cs | 54 +++++++ Capnp.Net.Runtime/Rpc/NullSkeleton.cs | 41 +++++ Capnp.Net.Runtime/Rpc/PendingAnswer.cs | 13 +- Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 6 +- Capnp.Net.Runtime/Rpc/PolySkeleton.cs | 2 +- Capnp.Net.Runtime/Rpc/PromisedCapability.cs | 7 +- Capnp.Net.Runtime/Rpc/Proxy.cs | 33 +--- .../Rpc/RefCountingCapability.cs | 11 ++ Capnp.Net.Runtime/Rpc/RefCountingSkeleton.cs | 80 ++++++++++ .../Rpc/RemoteAnswerCapability.cs | 16 +- .../Rpc/RemoteResolvingCapability.cs | 7 +- .../Rpc/ResolvingCapabilityExtensions.cs | 12 +- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 36 ++--- Capnp.Net.Runtime/Rpc/Skeleton.cs | 146 +----------------- Capnp.Net.Runtime/Rpc/Vine.cs | 66 ++------ Capnp.Net.Runtime/SerializerState.cs | 28 ++-- 33 files changed, 330 insertions(+), 343 deletions(-) create mode 100644 Capnp.Net.Runtime/Rpc/NullCapability.cs create mode 100644 Capnp.Net.Runtime/Rpc/NullSkeleton.cs create mode 100644 Capnp.Net.Runtime/Rpc/RefCountingSkeleton.cs diff --git a/Capnp.Net.Runtime.Tests/ProvidedCapabilityMock.cs b/Capnp.Net.Runtime.Tests/ProvidedCapabilityMock.cs index 2e987f6..7cd187e 100644 --- a/Capnp.Net.Runtime.Tests/ProvidedCapabilityMock.cs +++ b/Capnp.Net.Runtime.Tests/ProvidedCapabilityMock.cs @@ -4,7 +4,7 @@ using Capnp.Rpc; namespace Capnp.Net.Runtime.Tests { - class ProvidedCapabilityMock : Skeleton + class ProvidedCapabilityMock : RefCountingSkeleton { readonly TaskCompletionSource<(ulong, ushort, DeserializerState, CancellationToken)> _call = new TaskCompletionSource<(ulong, ushort, DeserializerState, CancellationToken)>(); diff --git a/Capnp.Net.Runtime.Tests/ProvidedCapabilityMultiCallMock.cs b/Capnp.Net.Runtime.Tests/ProvidedCapabilityMultiCallMock.cs index 58bb57a..771c786 100644 --- a/Capnp.Net.Runtime.Tests/ProvidedCapabilityMultiCallMock.cs +++ b/Capnp.Net.Runtime.Tests/ProvidedCapabilityMultiCallMock.cs @@ -6,7 +6,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Capnp.Net.Runtime.Tests { - class ProvidedCapabilityMultiCallMock : Skeleton + class ProvidedCapabilityMultiCallMock : RefCountingSkeleton { readonly BufferBlock _ccs = new BufferBlock(); diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index 7836f96..009c94d 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -389,7 +389,7 @@ namespace Capnp.Net.Runtime.Tests var result = DynamicSerializerState.CreateForRpc(); result.SetStruct(1, 2); result.WriteData(0, 654321); - uint id = result.ProvideCapability(mock2); + uint id = result.ProvideCapability(mock2).Value; result.LinkToCapability(1, id); mock.Return.SetResult(result); @@ -453,7 +453,7 @@ namespace Capnp.Net.Runtime.Tests var result = DynamicSerializerState.CreateForRpc(); result.SetStruct(1, 2); result.WriteData(0, 654321); - uint id = result.ProvideCapability(mock2); + uint id = result.ProvideCapability(mock2).Value; result.LinkToCapability(1, id); mock.Return.SetResult(result); @@ -543,7 +543,7 @@ namespace Capnp.Net.Runtime.Tests var result = DynamicSerializerState.CreateForRpc(); result.SetStruct(1, 2); result.WriteData(0, 654321); - uint id = result.ProvideCapability(mock2); + uint id = result.ProvideCapability(mock2).Value; result.LinkToCapability(1, id); mock.Return.SetResult(result); @@ -707,7 +707,7 @@ namespace Capnp.Net.Runtime.Tests var result = DynamicSerializerState.CreateForRpc(); result.SetStruct(1, 2); result.WriteData(0, 654321); - uint id = result.ProvideCapability(mock2); + uint id = result.ProvideCapability(mock2).Value; result.LinkToCapability(1, id); mock.Return.SetResult(result); diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs index c64c0be..a888d65 100644 --- a/Capnp.Net.Runtime.Tests/Testsuite.cs +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -677,7 +677,7 @@ namespace Capnp.Net.Runtime.Tests } } - class ThrowingSkeleton : Skeleton + class ThrowingSkeleton : RefCountingSkeleton { public bool WasCalled { get; private set; } diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs index 5773466..c5e7b71 100644 --- a/Capnp.Net.Runtime/DeserializerState.cs +++ b/Capnp.Net.Runtime/DeserializerState.cs @@ -386,7 +386,7 @@ namespace Capnp /// offset negative or out of range /// capability table not set /// not a capability pointer or invalid capability index - internal Rpc.ConsumedCapability? DecodeCapPointer(int offset) + internal Rpc.ConsumedCapability DecodeCapPointer(int offset) { if (offset < 0) { @@ -404,7 +404,7 @@ namespace Capnp { // Despite this behavior is not officially specified, // the official C++ implementation seems to send null pointers for null caps. - return null; + return Rpc.NullCapability.Instance; } if (pointer.Kind != PointerKind.Other) @@ -496,13 +496,13 @@ namespace Capnp return state; } - internal Rpc.ConsumedCapability? StructReadRawCap(int index) + internal Rpc.ConsumedCapability StructReadRawCap(int index) { if (Kind != ObjectKind.Struct && Kind != ObjectKind.Nil) throw new InvalidOperationException("Allowed on structs only"); if (index >= StructPtrCount) - return null; + return Rpc.NullCapability.Instance; return DecodeCapPointer(index + StructDataCount); } diff --git a/Capnp.Net.Runtime/Rpc/BareProxy.cs b/Capnp.Net.Runtime/Rpc/BareProxy.cs index 5f9dca5..ff68ab0 100644 --- a/Capnp.Net.Runtime/Rpc/BareProxy.cs +++ b/Capnp.Net.Runtime/Rpc/BareProxy.cs @@ -19,7 +19,7 @@ /// Problem with building the Skeleton type, or problem with loading some dependent class. public static BareProxy FromImpl(object impl) { - return new BareProxy(LocalCapability.Create(CapabilityReflection.CreateSkeleton(impl))); + return new BareProxy(CapabilityReflection.CreateSkeleton(impl).AsCapability()); } /// @@ -33,7 +33,7 @@ /// Constructs an instance and binds it to the given low-level capability. /// /// low-level capability - public BareProxy(ConsumedCapability? cap): base(cap) + public BareProxy(ConsumedCapability cap): base(cap) { } diff --git a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs index ce0205a..97b8b63 100644 --- a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs +++ b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs @@ -259,7 +259,7 @@ namespace Capnp.Rpc /// Problem with instatiating the Proxy (constructor threw exception). /// Caller does not have permission to invoke the Proxy constructor. /// Problem with building the Proxy type, or problem with loading some dependent class. - public static Proxy CreateProxy(ConsumedCapability? cap) + public static Proxy CreateProxy(ConsumedCapability cap) { var factory = GetProxyFactory(typeof(TInterface)); var proxy = factory.NewProxy(); diff --git a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs index 594f375..ea8c5b3 100644 --- a/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/ConsumedCapability.cs @@ -18,6 +18,7 @@ namespace Capnp.Rpc internal abstract Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer); internal abstract void AddRef(); internal abstract void Release(); + internal abstract Skeleton AsSkeleton(); #if DebugFinalizers internal Proxy? OwningProxy { get; set; } diff --git a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs index a641a6b..6c0de2f 100644 --- a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs @@ -22,7 +22,7 @@ namespace Capnp.Rpc /// /// Path to the desired capability inside the result struct. /// Pipelined low-level capability - ConsumedCapability? Access(MemberAccessPath access); + ConsumedCapability Access(MemberAccessPath access); /// /// @@ -30,7 +30,7 @@ namespace Capnp.Rpc /// Creates a low-level capability for promise pipelining. /// Task returning the proxy whose ownership will be taken over /// - ConsumedCapability? Access(MemberAccessPath access, Task proxyTask); + ConsumedCapability Access(MemberAccessPath access, Task proxyTask); /// /// Whether the question was asked as tail call diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index 0f4685c..a7be980 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -76,7 +76,7 @@ namespace Capnp.Rpc /// path to the desired capability /// task returning a proxy to the desired capability /// Pipelined low-level capability - public static ConsumedCapability? Access(Task task, MemberAccessPath access, Task proxyTask) + public static ConsumedCapability Access(Task task, MemberAccessPath access, Task proxyTask) { var answer = TryGetAnswer(task); if (answer != null) return answer.Access(access, proxyTask); @@ -164,7 +164,7 @@ namespace Capnp.Rpc return cap; var unwrapped = await proxy.ConsumedCap.Unwrap(); - if (unwrapped == null) + if (unwrapped == null || unwrapped == NullCapability.Instance) return null; return ((CapabilityReflection.CreateProxy(unwrapped)) as TInterface)!; diff --git a/Capnp.Net.Runtime/Rpc/ImportedCapability.cs b/Capnp.Net.Runtime/Rpc/ImportedCapability.cs index 0cb2be4..1635e8b 100644 --- a/Capnp.Net.Runtime/Rpc/ImportedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/ImportedCapability.cs @@ -38,7 +38,7 @@ namespace Capnp.Rpc else { capDesc.which = CapDescriptor.WHICH.SenderHosted; - capDesc.SenderHosted = endpoint.AllocateExport(Vine.Create(this), out var _); + capDesc.SenderHosted = endpoint.AllocateExport(AsSkeleton(), out var _); } return null; } diff --git a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs index 0843119..9169022 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs @@ -25,12 +25,12 @@ namespace Capnp.Rpc.Interception public Task WhenReturned => _futureResult.Task; public CancellationToken CancelFromAlice => _cancelFromAlice.Token; - public ConsumedCapability? Access(MemberAccessPath access) + public ConsumedCapability Access(MemberAccessPath access) { return new LocalAnswerCapability(_futureResult.Task, access); } - public ConsumedCapability? Access(MemberAccessPath _, Task task) + public ConsumedCapability Access(MemberAccessPath _, Task task) { var proxyTask = task.AsProxyTask(); return new LocalAnswerCapability(proxyTask); @@ -165,12 +165,18 @@ namespace Capnp.Rpc.Interception BobProxy = proxy.Cast(false); break; - case ConsumedCapability cap: using (var temp = CapabilityReflection.CreateProxy(cap)) { - Bob = temp; } + case ConsumedCapability cap: + using (var temp = CapabilityReflection.CreateProxy(cap)) + { + Bob = temp; + } break; case Skeleton skeleton: - Bob = LocalCapability.Create(skeleton); + using (var nullProxy = new Proxy()) + { + Bob = (object?)skeleton.AsCapability() ?? nullProxy; + } break; default: @@ -213,9 +219,12 @@ namespace Capnp.Rpc.Interception for (int i = 0; i < state.Caps.Count; i++) { var cap = state.Caps[i]; - cap = policy.Attach(cap); - state.Caps[i] = cap; - cap.AddRef(); + if (cap != null) + { + cap = policy.Attach(cap); + state.Caps[i] = cap; + cap.AddRef(); + } } } } @@ -227,9 +236,12 @@ namespace Capnp.Rpc.Interception for (int i = 0; i < state.Caps.Count; i++) { var cap = state.Caps[i]; - cap = policy.Detach(cap); - state.Caps[i] = cap; - cap.AddRef(); + if (cap != null) + { + cap = policy.Detach(cap); + state.Caps[i] = cap; + cap.AddRef(); + } } } } diff --git a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs index 54f4754..cef2dc2 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CensorCapability.cs @@ -9,12 +9,10 @@ namespace Capnp.Rpc.Interception InterceptedCapability = interceptedCapability; interceptedCapability.AddRef(); Policy = policy; - MyVine = Vine.Create(this); } public ConsumedCapability InterceptedCapability { get; } public IInterceptionPolicy Policy { get; } - internal Skeleton MyVine { get; } protected override void ReleaseRemotely() { @@ -31,7 +29,7 @@ namespace Capnp.Rpc.Interception internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { writer.which = CapDescriptor.WHICH.SenderHosted; - writer.SenderHosted = endpoint.AllocateExport(MyVine, out bool _); + writer.SenderHosted = endpoint.AllocateExport(AsSkeleton(), out bool _); return null; } } diff --git a/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs b/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs index aeee3f5..d2f241d 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs @@ -52,10 +52,9 @@ namespace Capnp.Rpc.Interception return (new CensorCapability(ccap, policy) as TCap)!; default: - return (Attach(policy, - (CapabilityReflection.CreateProxy( - LocalCapability.Create( - Skeleton.GetOrCreateSkeleton(cap, false))) as TCap)!)); + var temp = (CapabilityReflection.CreateProxy( + Skeleton.GetOrCreateSkeleton(cap, false).AsCapability())) as TCap; + return Attach(policy, temp!)!; } } diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index 90f91a8..9794e3f 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -4,22 +4,23 @@ using System.Threading.Tasks; namespace Capnp.Rpc { + class LazyCapability : RefCountingCapability, IResolvingCapability { public static LazyCapability CreateBrokenCap(string message) { - return new LazyCapability(Task.FromException(new RpcException(message))); + return new LazyCapability(Task.FromException(new RpcException(message))); } public static LazyCapability CreateCanceledCap(CancellationToken token) { - return new LazyCapability(Task.FromCanceled(token)); + return new LazyCapability(Task.FromCanceled(token)); } readonly Task? _proxyTask; - readonly Task _capTask; + readonly Task _capTask; - public LazyCapability(Task capabilityTask) + public LazyCapability(Task capabilityTask) { _capTask = capabilityTask; } @@ -28,7 +29,7 @@ namespace Capnp.Rpc { _proxyTask = proxyTask; - async Task AwaitCap() => (await _proxyTask!).ConsumedCap; + async Task AwaitCap() => (await _proxyTask!).ConsumedCap; _capTask = AwaitCap(); } @@ -68,7 +69,7 @@ namespace Capnp.Rpc { try { - return CapabilityReflection.CreateProxy(_capTask.Result) as T; + return (CapabilityReflection.CreateProxy(_capTask.Result) as T)!; } catch (AggregateException exception) { @@ -83,7 +84,7 @@ namespace Capnp.Rpc async Task CallImpl(ulong interfaceId, ushort methodId, DynamicSerializerState args, CancellationToken cancellationToken) { - ConsumedCapability? cap; + ConsumedCapability cap; try { cap = await _capTask; diff --git a/Capnp.Net.Runtime/Rpc/LocalCapability.cs b/Capnp.Net.Runtime/Rpc/LocalCapability.cs index 140fa50..4024f32 100644 --- a/Capnp.Net.Runtime/Rpc/LocalCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalCapability.cs @@ -7,14 +7,6 @@ namespace Capnp.Rpc { class LocalCapability : ConsumedCapability { - public static ConsumedCapability Create(Skeleton skeleton) - { - if (skeleton is Vine vine) - return vine.Proxy.ConsumedCap!; - else - return new LocalCapability(skeleton); - } - static async Task AwaitAnswer(Task call) { var aorcq = await call; @@ -23,7 +15,9 @@ namespace Capnp.Rpc public Skeleton ProvidedCap { get; } - LocalCapability(Skeleton providedCap) + internal override Skeleton AsSkeleton() => ProvidedCap; + + public LocalCapability(Skeleton providedCap) { ProvidedCap = providedCap ?? throw new ArgumentNullException(nameof(providedCap)); } diff --git a/Capnp.Net.Runtime/Rpc/MemberAccessPath.cs b/Capnp.Net.Runtime/Rpc/MemberAccessPath.cs index 3b4cf20..1eaed67 100644 --- a/Capnp.Net.Runtime/Rpc/MemberAccessPath.cs +++ b/Capnp.Net.Runtime/Rpc/MemberAccessPath.cs @@ -169,7 +169,7 @@ namespace Capnp.Rpc /// The object (usually "params struct") on which to evaluate this path. /// Resulting low-level capability /// Evaluation of this path did not give a capability - public ConsumedCapability? Eval(DeserializerState rpcState) + public ConsumedCapability Eval(DeserializerState rpcState) { var cur = rpcState; @@ -181,7 +181,7 @@ namespace Capnp.Rpc switch (cur.Kind) { case ObjectKind.Nil: - return null; + return NullCapability.Instance; case ObjectKind.Capability: return rpcState.Caps![(int)cur.CapabilityIndex]; diff --git a/Capnp.Net.Runtime/Rpc/NullCapability.cs b/Capnp.Net.Runtime/Rpc/NullCapability.cs new file mode 100644 index 0000000..55e20d0 --- /dev/null +++ b/Capnp.Net.Runtime/Rpc/NullCapability.cs @@ -0,0 +1,54 @@ +using System; + +namespace Capnp.Rpc +{ + /// + /// Null capability + /// + public sealed class NullCapability : ConsumedCapability + { + /// + /// Singleton instance + /// + public static readonly NullCapability Instance = new NullCapability(); + + NullCapability() + { + } + + /// + /// Does nothing + /// + protected override void ReleaseRemotely() + { + } + + internal override void AddRef() + { + } + + internal override Skeleton AsSkeleton() => NullSkeleton.Instance; + + internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) + { + args.Dispose(); + throw new InvalidOperationException("Cannot call null capability"); + } + + internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) + { + writer.which = CapDescriptor.WHICH.None; + return null; + } + + internal override void Release() + { + } + + /// + /// String hint + /// + /// "Null capability" + public override string ToString() => "Null capability"; + } +} \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/NullSkeleton.cs b/Capnp.Net.Runtime/Rpc/NullSkeleton.cs new file mode 100644 index 0000000..17cd828 --- /dev/null +++ b/Capnp.Net.Runtime/Rpc/NullSkeleton.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Capnp.Rpc +{ + /// + /// Null skeleton + /// + public sealed class NullSkeleton : Skeleton + { + /// + /// Singleton instance + /// + public static readonly NullSkeleton Instance = new NullSkeleton(); + + NullSkeleton() + { + } + + /// + /// Always throws an exception + /// + /// always thrown + public override Task Invoke(ulong interfaceId, ushort methodId, DeserializerState args, CancellationToken cancellationToken = default) + { + args.Dispose(); + throw new InvalidOperationException("Cannot call null capability"); + } + + internal override ConsumedCapability AsCapability() => NullCapability.Instance; + + internal override void Claim() + { + } + + internal override void Relinquish() + { + } + } +} \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs index a195b0c..8692f6f 100644 --- a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs @@ -88,7 +88,7 @@ namespace Capnp.Rpc } catch (System.Exception) { - throw new ArgumentOutOfRangeException("Illegal pointer field in transformation operation"); + throw new RpcException("Illegal pointer field in transformation operation"); } break; @@ -100,21 +100,20 @@ namespace Capnp.Rpc } } - Proxy proxy; - switch (cur.Kind) { case ObjectKind.Capability: try { - var cap = aorcq.Answer.Caps![(int)cur.CapabilityIndex]; - proxy = new Proxy(cap); + return new Proxy(aorcq.Answer.Caps![(int)cur.CapabilityIndex]); } catch (ArgumentOutOfRangeException) { - throw new ArgumentOutOfRangeException("Bad capability table in internal answer - internal error?"); + throw new RpcException("Capability index out of range"); } - return proxy; + + case ObjectKind.Nil: + return new Proxy(NullCapability.Instance); default: throw new ArgumentOutOfRangeException("Transformation did not result in a capability"); diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index 5d6aa50..c822893 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -58,7 +58,7 @@ namespace Capnp.Rpc SerializerState? _inParams; int _inhibitFinishCounter, _refCounter; - internal PendingQuestion(IRpcEndpoint ep, uint id, ConsumedCapability? target, SerializerState? inParams) + internal PendingQuestion(IRpcEndpoint ep, uint id, ConsumedCapability target, SerializerState? inParams) { RpcEndpoint = ep ?? throw new ArgumentNullException(nameof(ep)); _questionId = id; @@ -237,7 +237,7 @@ namespace Capnp.Rpc /// Access path /// Low-level capability /// The referenced member does not exist or does not resolve to a capability pointer. - public ConsumedCapability? Access(MemberAccessPath access) + public ConsumedCapability Access(MemberAccessPath access) { lock (ReentrancyBlocker) { @@ -268,7 +268,7 @@ namespace Capnp.Rpc /// promises the cap whose ownership is transferred to this object /// Low-level capability /// The referenced member does not exist or does not resolve to a capability pointer. - public ConsumedCapability? Access(MemberAccessPath access, Task task) + public ConsumedCapability Access(MemberAccessPath access, Task task) { var proxyTask = task.AsProxyTask(); return new RemoteAnswerCapability(this, access, proxyTask); diff --git a/Capnp.Net.Runtime/Rpc/PolySkeleton.cs b/Capnp.Net.Runtime/Rpc/PolySkeleton.cs index 002a75f..17def26 100644 --- a/Capnp.Net.Runtime/Rpc/PolySkeleton.cs +++ b/Capnp.Net.Runtime/Rpc/PolySkeleton.cs @@ -8,7 +8,7 @@ namespace Capnp.Rpc /// /// Combines multiple skeletons to represent objects which implement multiple interfaces. /// - public class PolySkeleton: Skeleton + public class PolySkeleton: RefCountingSkeleton { readonly Dictionary _ifmap = new Dictionary(); diff --git a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs index 1f3a782..ad8db50 100644 --- a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs @@ -8,7 +8,7 @@ namespace Capnp.Rpc { readonly uint _remoteId; readonly object _reentrancyBlocker = new object(); - readonly TaskCompletionSource _resolvedCap = new TaskCompletionSource(); + readonly TaskCompletionSource _resolvedCap = new TaskCompletionSource(); readonly Task _whenResolvedProxy; bool _released; @@ -149,9 +149,10 @@ namespace Capnp.Rpc lock (_reentrancyBlocker) { #if DebugFinalizers - resolvedCap.ResolvingCap = this; + if (resolvedCap != null) + resolvedCap.ResolvingCap = this; #endif - _resolvedCap.SetResult(resolvedCap); + _resolvedCap.SetResult(resolvedCap!); if (_pendingCallsOnPromise == 0) { diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index bcfa0be..de67ab1 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -53,18 +53,18 @@ namespace Capnp.Rpc return CapabilityReflection.CreateProxy(ConsumedCap) as T; } - ConsumedCapability? _consumedCap; + ConsumedCapability _consumedCap = NullCapability.Instance; /// /// Underlying low-level capability /// - protected internal ConsumedCapability? ConsumedCap => _disposedValue ? + protected internal ConsumedCapability ConsumedCap => _disposedValue ? throw new ObjectDisposedException(nameof(Proxy)) : _consumedCap; /// /// Whether is this a broken capability. /// - public bool IsNull => _consumedCap == null; + public bool IsNull => _consumedCap == NullCapability.Instance; /// /// Whether was called on this Proxy. @@ -100,12 +100,6 @@ namespace Capnp.Rpc throw new ObjectDisposedException(nameof(Proxy)); } - if (ConsumedCap == null) - { - args.Dispose(); - throw new InvalidOperationException("Cannot call null capability"); - } - var answer = ConsumedCap.DoCall(interfaceId, methodId, args); if (cancellationToken.CanBeCanceled) @@ -126,20 +120,17 @@ namespace Capnp.Rpc #endif } - internal Proxy(ConsumedCapability? cap): this() + internal Proxy(ConsumedCapability cap): this() { Bind(cap); } - internal void Bind(ConsumedCapability? cap) + internal void Bind(ConsumedCapability cap) { - if (ConsumedCap != null) + if (ConsumedCap != NullCapability.Instance) throw new InvalidOperationException("Proxy was already bound"); - if (cap == null) - return; - - _consumedCap = cap; + _consumedCap = cap ?? throw new ArgumentNullException(nameof(cap)); cap.AddRef(); #if DebugFinalizers @@ -151,15 +142,7 @@ namespace Capnp.Rpc internal async Task GetProvider() { var unwrapped = await ConsumedCap.Unwrap(); - - switch (unwrapped) - { - case LocalCapability lcap: - return lcap.ProvidedCap; - - default: - return Vine.Create(unwrapped); - } + return unwrapped.AsSkeleton(); } /// diff --git a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs index c88d523..f8ae439 100644 --- a/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RefCountingCapability.cs @@ -7,6 +7,7 @@ namespace Capnp.Rpc abstract class RefCountingCapability: ConsumedCapability { readonly object _reentrancyBlocker = new object(); + Vine? _vine; // Note on reference counting: Works in analogy to COM. AddRef() adds a reference, // Release() removes it. When the reference count reaches zero, the capability must be @@ -122,5 +123,15 @@ namespace Capnp.Rpc } } } + + internal override Skeleton AsSkeleton() + { + lock (_reentrancyBlocker) + { + if (_vine == null) + _vine = new Vine(this); + return _vine; + } + } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/RefCountingSkeleton.cs b/Capnp.Net.Runtime/Rpc/RefCountingSkeleton.cs new file mode 100644 index 0000000..7c1359a --- /dev/null +++ b/Capnp.Net.Runtime/Rpc/RefCountingSkeleton.cs @@ -0,0 +1,80 @@ +using System; +using System.Threading; + +namespace Capnp.Rpc +{ + /// + /// Skeleton with reference counting and dispose pattern + /// + public abstract class RefCountingSkeleton: Skeleton + { + int _refCount; + LocalCapability? _localCap; + + /// + /// Dispose pattern implementation + /// + protected virtual void Dispose(bool disposing) + { + } + + /// + /// Finalizer + /// + ~RefCountingSkeleton() + { + Dispose(false); + } + + internal sealed override void Claim() + { + int count, newCount; + + do + { + count = Volatile.Read(ref _refCount); + if (count < 0) + throw new ObjectDisposedException(nameof(RefCountingSkeleton)); + + newCount = count + 1; + + } while (Interlocked.CompareExchange(ref _refCount, newCount, count) != count); + } + + internal override void Relinquish() + { + int count, newCount; + + do + { + count = Volatile.Read(ref _refCount); + if (count < 0) + throw new ObjectDisposedException(nameof(RefCountingSkeleton)); + + newCount = count > 0 ? count - 1 : int.MinValue; + + } while (Interlocked.CompareExchange(ref _refCount, newCount, count) != count); + + if (newCount == 0) + { + Dispose(true); + GC.SuppressFinalize(this); + } + } + + /// + /// Whether this instance is in disposed state. + /// + public bool IsDisposed => Volatile.Read(ref _refCount) < 0; + + internal override ConsumedCapability AsCapability() + { + var cap = Volatile.Read(ref _localCap); + if (cap == null) + { + Interlocked.CompareExchange(ref _localCap, new LocalCapability(this), null); + } + return Volatile.Read(ref _localCap)!; + } + } +} \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index b2be02f..2a49425 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -102,19 +102,6 @@ namespace Capnp.Rpc if (!_question.StateFlags.HasFlag(PendingQuestion.State.TailCall) && _question.StateFlags.HasFlag(PendingQuestion.State.Returned)) { - try - { - if (ResolvedCap == null) - { - throw new RpcException("Answer did not resolve to expected capability"); - } - } - catch - { - args.Dispose(); - throw; - } - return CallOnResolution(interfaceId, methodId, args); } else @@ -198,8 +185,7 @@ namespace Capnp.Rpc } else if (_question.IsTailCall) { - var vine = Vine.Create(this); - uint id = endpoint.AllocateExport(vine, out bool first); + uint id = endpoint.AllocateExport(AsSkeleton(), out bool first); writer.which = CapDescriptor.WHICH.SenderHosted; writer.SenderHosted = id; diff --git a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs index 7ff6553..937b66b 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs @@ -36,7 +36,10 @@ namespace Capnp.Rpc try { - if (resolvedCap is RemoteCapability || + if (resolvedCap is NullCapability || + // Must not request disembargo on null cap + + resolvedCap is RemoteCapability || //# Note that in the case where Carol actually lives in Vat B (i.e., the same vat that the promise //# already pointed at), no embargo is needed, because the pipelined calls are delivered over the //# same path as the later direct calls. @@ -84,7 +87,7 @@ namespace Capnp.Rpc cancellationTokenSource.Token.ThrowIfCancellationRequested(); } - using var proxy = new Proxy(ResolvedCap); + using var proxy = new Proxy(resolvedCap); return proxy.Call(interfaceId, methodId, args, default); }, TaskContinuationOptions.ExecuteSynchronously); diff --git a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs index 7fae258..3fb8cbc 100644 --- a/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/ResolvingCapabilityExtensions.cs @@ -1,11 +1,12 @@ using System; +using System.Threading; using System.Threading.Tasks; namespace Capnp.Rpc { static class ResolvingCapabilityExtensions { - public static async Task Unwrap(this ConsumedCapability? cap) + public static async Task Unwrap(this ConsumedCapability cap) { while (cap is IResolvingCapability resolving) { @@ -20,7 +21,7 @@ namespace Capnp.Rpc public static Action? ExportAsSenderPromise(this T cap, IRpcEndpoint endpoint, CapDescriptor.WRITER writer) where T: ConsumedCapability, IResolvingCapability { - var vine = Vine.Create(cap); + var vine = cap.AsSkeleton(); uint preliminaryId = endpoint.AllocateExport(vine, out bool first); writer.which = CapDescriptor.WHICH.SenderPromise; @@ -58,7 +59,10 @@ namespace Capnp.Rpc } catch (TaskCanceledException exception) { - return new Proxy(LazyCapability.CreateCanceledCap(exception.CancellationToken)); + var token = exception.CancellationToken; + if (!token.IsCancellationRequested) + token = new CancellationToken(true); + return new Proxy(LazyCapability.CreateCanceledCap(token)); } catch (System.Exception exception) { @@ -68,7 +72,7 @@ namespace Capnp.Rpc switch (obj) { case Proxy proxy: return proxy; - case null: return new Proxy(null); + case null: return new Proxy(NullCapability.Instance); default: return BareProxy.FromImpl(obj); } } diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index c271d53..3a32481 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -310,7 +310,7 @@ namespace Capnp.Rpc return AllocateExport(providedCapability, out first); } - PendingQuestion AllocateQuestion(ConsumedCapability? target, SerializerState? inParams) + PendingQuestion AllocateQuestion(ConsumedCapability target, SerializerState? inParams) { lock (_reentrancyBlocker) { @@ -359,7 +359,7 @@ namespace Capnp.Rpc if (bootstrapCap != null) { ret.which = Return.WHICH.Results; - bootstrap.SetCapability(bootstrap.ProvideCapability(LocalCapability.Create(bootstrapCap))); + bootstrap.SetCapability(bootstrap.ProvideCapability(bootstrapCap.AsCapability())); ret.Results!.Content = bootstrap; bootstrapTask = Task.FromResult(bootstrap); @@ -897,29 +897,20 @@ namespace Capnp.Rpc disembargo.Target.PromisedAnswer, async t => { - try - { - using var proxy = await t; + using var proxy = await t; - if (proxy.ConsumedCap is RemoteCapability remote && remote.Endpoint == this) - { + if (proxy.ConsumedCap is RemoteCapability remote && remote.Endpoint == this) + { #if DebugEmbargos - Logger.LogDebug($"Sender loopback disembargo. Thread = {Thread.CurrentThread.Name}"); + Logger.LogDebug($"Sender loopback disembargo. Thread = {Thread.CurrentThread.Name}"); #endif - Tx(mb.Frame); - } - else - { - Logger.LogWarning("Sender loopback request: Peer asked for disembargoing an answer which does not resolve back to the sender."); - - throw new RpcProtocolErrorException("'Disembargo': Answer does not resolve back to me"); - } + Tx(mb.Frame); } - catch (System.Exception exception) + else { - Logger.LogWarning($"Sender loopback request: Peer asked for disembargoing an answer which either has not yet returned, was canceled, or faulted: {exception.Message}"); + Logger.LogWarning("Sender loopback request: Peer asked for disembargoing an answer which does not resolve back to the sender."); - throw new RpcProtocolErrorException($"'Disembargo' failure: {exception}"); + throw new RpcProtocolErrorException("'Disembargo': Answer does not resolve back to me"); } }); } @@ -1177,7 +1168,7 @@ namespace Capnp.Rpc mb.InitCapTable(); var req = mb.BuildRoot(); req.which = Message.WHICH.Bootstrap; - var pendingBootstrap = AllocateQuestion(null, null); + var pendingBootstrap = AllocateQuestion(NullCapability.Instance, null); req.Bootstrap!.QuestionId = pendingBootstrap.QuestionId; Tx(mb.Frame); @@ -1315,7 +1306,7 @@ namespace Capnp.Rpc case CapDescriptor.WHICH.ReceiverHosted: if (_exportTable.TryGetValue(capDesc.ReceiverHosted, out var rc)) { - return LocalCapability.Create(rc.Cap); + return rc.Cap.AsCapability(); } else { @@ -1370,6 +1361,9 @@ namespace Capnp.Rpc return newCap; } + case CapDescriptor.WHICH.None: + return NullCapability.Instance; + default: Logger.LogWarning("Unknown capability descriptor category"); throw new RpcUnimplementedException(); diff --git a/Capnp.Net.Runtime/Rpc/Skeleton.cs b/Capnp.Net.Runtime/Rpc/Skeleton.cs index 32cdbaf..e6a0e83 100644 --- a/Capnp.Net.Runtime/Rpc/Skeleton.cs +++ b/Capnp.Net.Runtime/Rpc/Skeleton.cs @@ -26,10 +26,6 @@ namespace Capnp.Rpc } } -#if DEBUG_DISPOSE - const int NoDisposeFlag = 0x4000000; -#endif - static readonly ConditionalWeakTable _implMap = new ConditionalWeakTable(); @@ -63,31 +59,6 @@ namespace Capnp.Rpc return new SkeletonRelinquisher(GetOrCreateSkeleton(impl, true)); } -#if DEBUG_DISPOSE - /// - /// This DEBUG-only diagnostic method states that the Skeleton corresponding to a given capability is not expected to - /// be disposed until the next call to EndAssertNotDisposed(). - /// - /// Capability interface - /// Capability implementation - public static void BeginAssertNotDisposed(T impl) where T : class - { - GetOrCreateSkeleton(impl, false).BeginAssertNotDisposed(); - } - - /// - /// This DEBUG-only diagnostic method ends a non-disposal period started with BeginAssertNotDisposed. - /// - /// Capability interface - /// Capability implementation - public static void EndAssertNotDisposed(T impl) where T : class - { - GetOrCreateSkeleton(impl, false).EndAssertNotDisposed(); - } -#endif - - int _refCount = 0; - /// /// Calls an interface method of this capability. /// @@ -98,43 +69,8 @@ namespace Capnp.Rpc /// A Task which will resolve to the call result public abstract Task Invoke(ulong interfaceId, ushort methodId, DeserializerState args, CancellationToken cancellationToken = default); - internal void Claim() - { - Interlocked.Increment(ref _refCount); - } - -#if DEBUG_DISPOSE - internal void BeginAssertNotDisposed() - { - if ((Interlocked.Add(ref _refCount, NoDisposeFlag) & NoDisposeFlag) == 0) - { - throw new InvalidOperationException("Flag already set. State is now broken."); - } - } - internal void EndAssertNotDisposed() - { - if ((Interlocked.Add(ref _refCount, -NoDisposeFlag) & NoDisposeFlag) != 0) - { - throw new InvalidOperationException("Flag already cleared. State is now broken."); - } - } -#endif - - internal void Relinquish() - { - int count = Interlocked.Decrement(ref _refCount); - - if (0 == count) - { -#if DEBUG_DISPOSE - if ((count & NoDisposeFlag) != 0) - throw new InvalidOperationException("Unexpected Skeleton disposal"); -#endif - - Dispose(true); - GC.SuppressFinalize(this); - } - } + internal abstract void Claim(); + internal abstract void Relinquish(); internal void Relinquish(int count) { @@ -145,41 +81,21 @@ namespace Capnp.Rpc Relinquish(); } - /// - /// Dispose pattern implementation - /// - protected virtual void Dispose(bool disposing) - { - } - - /// - /// Finalizer - /// - ~Skeleton() - { - Dispose(false); - } - internal virtual void Bind(object impl) { - throw new NotSupportedException(); + throw new NotSupportedException("Cannot bind"); } + + internal abstract ConsumedCapability AsCapability(); } /// /// Skeleton for a specific capability interface. /// /// Capability interface - public abstract class Skeleton : Skeleton, IMonoSkeleton + public abstract class Skeleton : RefCountingSkeleton, IMonoSkeleton { -#if DebugEmbargos - ILogger Logger { get; } = Logging.CreateLogger>(); -#endif - Func>[] _methods = null!; - CancellationTokenSource? _disposed = new CancellationTokenSource(); - readonly object _reentrancyBlocker = new object(); - int _pendingCalls; /// /// Constructs an instance. @@ -225,45 +141,7 @@ namespace Capnp.Rpc if (methodId >= _methods.Length) throw new NotImplementedException("Wrong method id"); - lock (_reentrancyBlocker) - { - if (_disposed == null || _disposed.IsCancellationRequested) - { - throw new ObjectDisposedException(nameof(Skeleton)); - } - - ++_pendingCalls; - } - - var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(_disposed.Token, cancellationToken); - - try - { - return await _methods[methodId](args, linkedSource.Token); - } - catch (System.Exception) - { - throw; - } - finally - { - lock (_reentrancyBlocker) - { - --_pendingCalls; - } - - linkedSource.Dispose(); - CheckCtsDisposal(); - } - } - - void CheckCtsDisposal() - { - if (_pendingCalls == 0 && _disposed != null && _disposed.IsCancellationRequested) - { - _disposed.Dispose(); - _disposed = null; - } + return await _methods[methodId](args, cancellationToken); } /// @@ -271,16 +149,6 @@ namespace Capnp.Rpc /// protected override void Dispose(bool disposing) { - lock (_reentrancyBlocker) - { - if (_disposed == null || _disposed.IsCancellationRequested) - return; - - _disposed.Cancel(); - - CheckCtsDisposal(); - } - if (disposing && Impl is IDisposable disposable) { disposable.Dispose(); diff --git a/Capnp.Net.Runtime/Rpc/Vine.cs b/Capnp.Net.Runtime/Rpc/Vine.cs index 1c4f29c..c17c1be 100644 --- a/Capnp.Net.Runtime/Rpc/Vine.cs +++ b/Capnp.Net.Runtime/Rpc/Vine.cs @@ -5,66 +5,37 @@ using System.Threading.Tasks; namespace Capnp.Rpc { + class Vine : Skeleton { - public static Skeleton Create(ConsumedCapability? cap) + public Vine(ConsumedCapability consumedCap) { - if (cap is LocalCapability lcap) - return lcap.ProvidedCap; - else - return new Vine(cap); + Cap = consumedCap; } - Vine(ConsumedCapability? consumedCap) - { - Proxy = new Proxy(consumedCap); + public ConsumedCapability Cap { get; } -#if DebugFinalizers - CreatorStackTrace = Environment.StackTrace; -#endif + internal override ConsumedCapability AsCapability() => Cap; + + internal override void Claim() + { + Cap.AddRef(); } -#if DebugFinalizers - ~Vine() + internal override void Relinquish() { - Logger.LogWarning($"Caught orphaned Vine, created from here: {CreatorStackTrace}."); - - Dispose(false); + Cap.Release(); } - ILogger Logger { get; } = Logging.CreateLogger(); - string CreatorStackTrace { get; } -#endif - - internal override void Bind(object impl) - { - throw new NotImplementedException(); - } - - public Proxy Proxy { get; } - public async override Task Invoke( ulong interfaceId, ushort methodId, DeserializerState args, CancellationToken cancellationToken = default) { - var promisedAnswer = Proxy.Call(interfaceId, methodId, (DynamicSerializerState)args, default); + using var proxy = new Proxy(Cap); + var promisedAnswer = proxy.Call(interfaceId, methodId, (DynamicSerializerState)args, false, cancellationToken); if (promisedAnswer is PendingQuestion pendingQuestion && pendingQuestion.RpcEndpoint == Impatient.AskingEndpoint) { - async void SetupCancellation() - { - try - { - using var registration = cancellationToken.Register(promisedAnswer.Dispose); - await promisedAnswer.WhenReturned; - } - catch - { - } - } - - SetupCancellation(); - return pendingQuestion; } else @@ -73,16 +44,5 @@ namespace Capnp.Rpc return (DynamicSerializerState)await promisedAnswer.WhenReturned; } } - - protected override void Dispose(bool disposing) - { - if (disposing) - Proxy.Dispose(); - else - try { Proxy.Dispose(); } - catch { } - - base.Dispose(disposing); - } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index c717f15..30fc21e 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -237,33 +237,31 @@ namespace Capnp } } - internal Rpc.ConsumedCapability? DecodeCapPointer(int offset) + internal Rpc.ConsumedCapability DecodeCapPointer(int offset) { if (Caps == null) throw new InvalidOperationException("Capbility table not set"); if (!IsAllocated) { - return null; + return Rpc.NullCapability.Instance; } WirePointer pointer = RawData[offset]; if (pointer.IsNull) { - return null; + return Rpc.NullCapability.Instance; } if (pointer.Kind != PointerKind.Other) { - throw new Rpc.RpcException( - "Expected a capability pointer, but got something different"); + 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"); + throw new Rpc.RpcException("Capability index out of range"); } return Caps[(int)pointer.CapabilityIndex]; @@ -1237,9 +1235,9 @@ namespace Capnp /// The low-level capability object to provide. /// Index of the given capability in the capability table, null if capability is null /// The underlying message builder was not configured for capability table support. - public uint? ProvideCapability(Rpc.ConsumedCapability? capability) + public uint? ProvideCapability(Rpc.ConsumedCapability capability) { - if (capability == null) + if (capability == null || capability == Rpc.NullCapability.Instance) return null; if (Caps == null) @@ -1251,7 +1249,7 @@ namespace Capnp { index = Caps.Count; Caps.Add(capability); - capability?.AddRef(); + capability.AddRef(); } return (uint)index; @@ -1263,9 +1261,9 @@ namespace Capnp /// The capability to provide, in terms of its skeleton. /// Index of the given capability in the capability table /// The underlying message builder was not configured for capability table support. - public uint ProvideCapability(Rpc.Skeleton capability) + public uint? ProvideCapability(Rpc.Skeleton capability) { - return ProvideCapability(Rpc.LocalCapability.Create(capability))!.Value; + return ProvideCapability(capability.AsCapability()); } /// @@ -1356,7 +1354,7 @@ namespace Capnp } } - internal Rpc.ConsumedCapability? StructReadRawCap(int index) + internal Rpc.ConsumedCapability StructReadRawCap(int index) { if (Kind != ObjectKind.Struct && Kind != ObjectKind.Nil) throw new InvalidOperationException("Allowed on structs only"); @@ -1376,10 +1374,10 @@ namespace Capnp /// is out of range. /// The desired interface does not qualify as capability interface () /// This state does not represent a struct. - public T? ReadCap(int slot) where T : class + public T ReadCap(int slot) where T : class { var cap = StructReadRawCap(slot); - return Rpc.CapabilityReflection.CreateProxy(cap) as T; + return (Rpc.CapabilityReflection.CreateProxy(cap) as T)!; } /// From de788bca6bcabcbbeb50aabdd258511f8fc1e9a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Fri, 10 Apr 2020 19:23:16 +0200 Subject: [PATCH 37/76] refactoring Skeleton creation --- Capnp.Net.Runtime.Tests/TcpRpcInterop.cs | 2 +- Capnp.Net.Runtime.Tests/TcpRpcStress.cs | 2 +- Capnp.Net.Runtime/Rpc/BareProxy.cs | 2 +- Capnp.Net.Runtime/Rpc/CapabilityReflection.cs | 20 +++++++++++---- .../Rpc/Interception/CallContext.cs | 2 +- .../Rpc/Interception/Interceptor.cs | 2 +- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 2 +- Capnp.Net.Runtime/Rpc/Skeleton.cs | 25 ++----------------- Capnp.Net.Runtime/SerializerState.cs | 2 +- 9 files changed, 24 insertions(+), 35 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs index 5886456..7ad9852 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs @@ -1046,7 +1046,7 @@ namespace Capnp.Net.Runtime.Tests { LaunchCompatTestProcess("server:MoreStuff", stdout => { - for (int i = 0; i < 100; i++) + for (int i = 0; i < 20; i++) { EmbargoErrorImpl(stdout); } diff --git a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs index 8f6eec1..7fb4590 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs @@ -67,7 +67,7 @@ namespace Capnp.Net.Runtime.Tests public void EmbargoServer() { var t2 = new TcpRpcInterop(); - Repeat(100, t2.EmbargoServer); + Repeat(20, t2.EmbargoServer); } [TestMethod] diff --git a/Capnp.Net.Runtime/Rpc/BareProxy.cs b/Capnp.Net.Runtime/Rpc/BareProxy.cs index ff68ab0..71c4dbe 100644 --- a/Capnp.Net.Runtime/Rpc/BareProxy.cs +++ b/Capnp.Net.Runtime/Rpc/BareProxy.cs @@ -19,7 +19,7 @@ /// Problem with building the Skeleton type, or problem with loading some dependent class. public static BareProxy FromImpl(object impl) { - return new BareProxy(CapabilityReflection.CreateSkeleton(impl).AsCapability()); + return new BareProxy(CapabilityReflection.CreateSkeletonInternal(impl).AsCapability()); } /// diff --git a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs index 97b8b63..2512bda 100644 --- a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs +++ b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs @@ -94,6 +94,8 @@ namespace Capnp.Rpc new ConditionalWeakTable(); static ConditionalWeakTable _skeletonMap = new ConditionalWeakTable(); + static ConditionalWeakTable _implMap = + new ConditionalWeakTable(); static CapabilityReflection() { @@ -155,15 +157,23 @@ namespace Capnp.Rpc /// Problem with instatiating the Skeleton (constructor threw exception). /// Caller does not have permission to invoke the Skeleton constructor. /// Problem with building the Skeleton type, or problem with loading some dependent class. - public static Skeleton CreateSkeleton(object obj) + [Obsolete("Do not use this method directly. Instead, pass objects directly or use Proxy.Share(). This method will be removed with next release.")] + public static Skeleton CreateSkeleton(object obj) => CreateSkeletonInternal(obj); + + internal static Skeleton CreateSkeletonInternal(object obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); - var factory = GetSkeletonFactory(obj.GetType()); - var skeleton = factory.NewSkeleton(); - skeleton.Bind(obj); - return skeleton; + var result = _implMap.GetValue(obj, _ => + { + var factory = GetSkeletonFactory(_.GetType()); + var skeleton = factory.NewSkeleton(); + skeleton.Bind(obj); + return skeleton; + }); + + return result; } static ProxyFactory GetProxyFactory(Type type) diff --git a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs index 9169022..3911fae 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs @@ -180,7 +180,7 @@ namespace Capnp.Rpc.Interception break; default: - Bob = Skeleton.GetOrCreateSkeleton(value, false); + Bob = CapabilityReflection.CreateSkeletonInternal(value); break; } diff --git a/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs b/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs index d2f241d..b951676 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs @@ -53,7 +53,7 @@ namespace Capnp.Rpc.Interception default: var temp = (CapabilityReflection.CreateProxy( - Skeleton.GetOrCreateSkeleton(cap, false).AsCapability())) as TCap; + CapabilityReflection.CreateSkeletonInternal(cap).AsCapability())) as TCap; return Attach(policy, temp!)!; } } diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 3a32481..3a8b8ed 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -1570,7 +1570,7 @@ namespace Capnp.Rpc /// public object Main { - set { BootstrapCap = Skeleton.GetOrCreateSkeleton(value, false); } + set { BootstrapCap = value is Skeleton skeleton ? skeleton : CapabilityReflection.CreateSkeletonInternal(value); } } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/Skeleton.cs b/Capnp.Net.Runtime/Rpc/Skeleton.cs index e6a0e83..f8ffaa0 100644 --- a/Capnp.Net.Runtime/Rpc/Skeleton.cs +++ b/Capnp.Net.Runtime/Rpc/Skeleton.cs @@ -18,6 +18,7 @@ namespace Capnp.Rpc public SkeletonRelinquisher(Skeleton skeleton) { _skeleton = skeleton; + _skeleton.Claim(); } public void Dispose() @@ -26,28 +27,6 @@ namespace Capnp.Rpc } } - static readonly ConditionalWeakTable _implMap = - new ConditionalWeakTable(); - - internal static Skeleton GetOrCreateSkeleton(T impl, bool addRef) - where T: class - { - if (impl == null) - throw new ArgumentNullException(nameof(impl)); - - if (impl is Skeleton skel) - return skel; - - skel = _implMap.GetValue(impl, _ => CapabilityReflection.CreateSkeleton(_)); - - if (addRef) - { - skel.Claim(); - } - - return skel; - } - /// /// Claims ownership on the given capability, preventing its automatic disposal. /// @@ -56,7 +35,7 @@ namespace Capnp.Rpc /// A disposable object. Calling Dispose() on the returned instance relinquishes ownership again. public static IDisposable Claim(T impl) where T: class { - return new SkeletonRelinquisher(GetOrCreateSkeleton(impl, true)); + return new SkeletonRelinquisher(CapabilityReflection.CreateSkeletonInternal(impl)); } /// diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index 30fc21e..39f7f80 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -1291,7 +1291,7 @@ namespace Capnp case Rpc.Skeleton providedCapability: return ProvideCapability(providedCapability); default: - return ProvideCapability(Rpc.Skeleton.GetOrCreateSkeleton(obj, false)); + return ProvideCapability(Rpc.CapabilityReflection.CreateSkeletonInternal(obj)); } } From 3c6f5019f23a66ddbfadfe8a381065c97444f843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Fri, 10 Apr 2020 22:33:46 +0200 Subject: [PATCH 38/76] test & fix --- .../Mock/TestCapImplementations.cs | 4 ++++ Capnp.Net.Runtime.Tests/Testsuite.cs | 22 ++++++++++--------- Capnp.Net.Runtime.Tests/Util/TestBase.cs | 2 +- Capnp.Net.Runtime/Rpc/PolySkeleton.cs | 6 +++-- Capnp.Net.Runtime/Rpc/Proxy.cs | 4 ++-- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs index 795d451..3c5093e 100644 --- a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs @@ -421,9 +421,12 @@ namespace Capnp.Net.Runtime.Tests.GenImpls public void Dispose() { _tcs?.TrySetResult(0); + Assert.IsFalse(IsDisposed); IsDisposed = true; + DisposeCallStack = Environment.StackTrace; } + public string DisposeCallStack { get; private set; } public bool IsDisposed { get; private set; } public virtual Task Foo(uint i, bool j, CancellationToken cancellationToken) @@ -836,6 +839,7 @@ namespace Capnp.Net.Runtime.Tests.GenImpls public void Dispose() { ClientToHold?.Dispose(); + ClientToHold = null; } public Task Echo(ITestCallOrder cap, CancellationToken cancellationToken_) diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs index a888d65..77e0a59 100644 --- a/Capnp.Net.Runtime.Tests/Testsuite.cs +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -311,7 +311,7 @@ namespace Capnp.Net.Runtime.Tests using (var claimer = Skeleton.Claim(cap)) { - var ftask = main.CallFoo(cap, default); + var ftask = main.CallFoo(Proxy.Share(cap), default); testbed.MustComplete(ftask); Assert.AreEqual("bar", ftask.Result); @@ -319,8 +319,8 @@ namespace Capnp.Net.Runtime.Tests testbed.MustComplete(ctask); Assert.AreEqual(1u, ctask.Result); - ftask1 = main.CallFoo(cap, default); - ftask2 = main.CallFoo(cap, default); + ftask1 = main.CallFoo(Proxy.Share(cap), default); + ftask2 = main.CallFoo(Proxy.Share(cap), default); } testbed.MustComplete(ftask1); @@ -804,18 +804,20 @@ namespace Capnp.Net.Runtime.Tests public static void ReexportSenderPromise(ITestbed testbed) { - var impl = new TestTailCallerImpl(new Counters()); - using (var main = testbed.ConnectMain(impl)) + var impl = new TestMoreStuffImpl(new Counters()); + using (var main = testbed.ConnectMain(impl)) { - var tcs = new TaskCompletionSource(); - using (var promise = Proxy.Share(tcs.Task.Eager(true))) + var tcs = new TaskCompletionSource(); + var tcsd = new TaskCompletionSource(); + using (var promise = tcs.Task.Eager(true)) { - var task1 = main.Foo(1, Proxy.Share(promise)); - var task2 = main.Foo(2, Proxy.Share(promise)); - var callee = new TestTailCalleeImpl(new Counters()); + var task1 = main.CallFooWhenResolved(Proxy.Share(promise)); + var task2 = main.CallFooWhenResolved(Proxy.Share(promise)); + var callee = new TestInterfaceImpl(new Counters(), tcsd); tcs.SetResult(callee); testbed.MustComplete(task1, task2); } + testbed.MustComplete(tcsd.Task); } } } diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index e40b7a1..5f13b70 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -161,7 +161,7 @@ namespace Capnp.Net.Runtime.Tests T ITestbed.ConnectMain(object main) { - return (T)main; + return Proxy.Share((T)main); } void ITestbed.FlushCommunication() diff --git a/Capnp.Net.Runtime/Rpc/PolySkeleton.cs b/Capnp.Net.Runtime/Rpc/PolySkeleton.cs index 17def26..c7762dd 100644 --- a/Capnp.Net.Runtime/Rpc/PolySkeleton.cs +++ b/Capnp.Net.Runtime/Rpc/PolySkeleton.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -54,7 +55,8 @@ namespace Capnp.Rpc /// protected override void Dispose(bool disposing) { - foreach (var cap in _ifmap.Values) + foreach (var cap in _ifmap.Values.Take(1)) + // releasing first skeleton is sufficient. Avoid double-Dispose! { cap.Relinquish(); } @@ -64,7 +66,7 @@ namespace Capnp.Rpc internal override void Bind(object impl) { - foreach (Skeleton skel in _ifmap.Values) + foreach (Skeleton skel in _ifmap.Values) { skel.Bind(impl); } diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index de67ab1..f82b6e0 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -154,14 +154,14 @@ namespace Capnp.Rpc { if (disposing) { - _consumedCap?.Release(); + _consumedCap.Release(); } else { // When called from the Finalizer, we must not throw. // But when reference counting goes wrong, ConsumedCapability.Release() will throw an InvalidOperationException. // The only option here is to suppress that exception. - try { _consumedCap?.Release(); } + try { _consumedCap.Release(); } catch { } } From 19b36a164377db805bc75b7325088d90b5281ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 11 Apr 2020 15:48:02 +0200 Subject: [PATCH 39/76] test & fix --- .../DeserializationTests.cs | 3 + Capnp.Net.Runtime.Tests/General.cs | 28 +----- Capnp.Net.Runtime.Tests/Interception.cs | 30 +++---- Capnp.Net.Runtime.Tests/LocalRpc.cs | 55 ++++++++++++ Capnp.Net.Runtime.Tests/TcpRpc.cs | 26 +++--- .../TcpRpcAdvancedStuff.cs | 20 ++--- Capnp.Net.Runtime.Tests/TcpRpcInterop.cs | 59 ++++--------- Capnp.Net.Runtime.Tests/TcpRpcPorted.cs | 4 +- Capnp.Net.Runtime.Tests/TcpRpcStress.cs | 4 +- Capnp.Net.Runtime.Tests/Util/TestBase.cs | 4 +- .../ListOfPrimitivesDeserializer.cs | 2 +- Capnp.Net.Runtime/Rpc/LazyCapability.cs | 15 ++-- Capnp.Net.Runtime/Rpc/PolySkeleton.cs | 5 +- Capnp.Net.Runtime/Rpc/TcpRpcClient.cs | 14 ++- .../Util/StrictlyOrderedAwaitTask.cs | 88 +++++++++++++++++++ 15 files changed, 227 insertions(+), 130 deletions(-) create mode 100644 Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs diff --git a/Capnp.Net.Runtime.Tests/DeserializationTests.cs b/Capnp.Net.Runtime.Tests/DeserializationTests.cs index 1f286b7..e90269d 100644 --- a/Capnp.Net.Runtime.Tests/DeserializationTests.cs +++ b/Capnp.Net.Runtime.Tests/DeserializationTests.cs @@ -151,6 +151,9 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(2, asListOfStructs.Count); Assert.AreEqual(0ul, asListOfStructs[0].ReadDataULong(0)); Assert.AreEqual(ulong.MaxValue, asListOfStructs[1].ReadDataULong(0)); + Assert.ThrowsException(() => asListOfStructs[-1].ReadDataUShort(0)); + Assert.ThrowsException(() => asListOfStructs[3].ReadDataUShort(0)); + CollectionAssert.AreEqual(new ulong[] { 0, ulong.MaxValue }, asListOfStructs.Select(_ => _.ReadDataULong(0)).ToArray()); } [TestMethod] diff --git a/Capnp.Net.Runtime.Tests/General.cs b/Capnp.Net.Runtime.Tests/General.cs index f5cb811..0b564f6 100644 --- a/Capnp.Net.Runtime.Tests/General.cs +++ b/Capnp.Net.Runtime.Tests/General.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; namespace Capnp.Net.Runtime.Tests { @@ -42,33 +43,6 @@ namespace Capnp.Net.Runtime.Tests Task.WhenAll(tasks).Wait(); } - [TestMethod] - public void AwaitOrderTest2() - { - int returnCounter = 0; - - async Task ExpectCount(Task task, int count) - { - await task; - Assert.AreEqual(count, returnCounter++); - } - - var tcs = new TaskCompletionSource(); - var cts = new CancellationTokenSource(); - - var tasks = - from i in Enumerable.Range(0, 100) - select ExpectCount(tcs.Task.ContinueWith( - t => t, - cts.Token, - TaskContinuationOptions.ExecuteSynchronously, - TaskScheduler.Current), i); - - tcs.SetResult(0); - - Task.WhenAll(tasks).Wait(); - } - class PromisedAnswerMock : IPromisedAnswer { readonly TaskCompletionSource _tcs = new TaskCompletionSource(); diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index f2f7b71..0e0e010 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -67,7 +67,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = policy.Attach(new TestInterfaceImpl(counters)); @@ -106,7 +106,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = policy.Attach(new TestInterfaceImpl(counters)); @@ -146,7 +146,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestInterfaceImpl(counters); @@ -204,7 +204,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestInterfaceImpl(counters); @@ -237,7 +237,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestInterfaceImpl(counters); @@ -268,7 +268,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestInterfaceImpl(counters); @@ -334,7 +334,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestInterfaceImpl(counters); @@ -369,7 +369,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestInterfaceImpl(counters); @@ -406,7 +406,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestInterfaceImpl(counters); @@ -431,7 +431,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestTailCallerImpl(counters); @@ -463,7 +463,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); @@ -503,7 +503,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = policy.Attach(new TestMoreStuffImpl(counters)); @@ -560,7 +560,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); @@ -628,7 +628,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); @@ -668,7 +668,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); server.Main = implAc; using (var main = client.GetMain()) diff --git a/Capnp.Net.Runtime.Tests/LocalRpc.cs b/Capnp.Net.Runtime.Tests/LocalRpc.cs index 7adc180..55e693a 100644 --- a/Capnp.Net.Runtime.Tests/LocalRpc.cs +++ b/Capnp.Net.Runtime.Tests/LocalRpc.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; namespace Capnp.Net.Runtime.Tests { @@ -138,5 +139,59 @@ namespace Capnp.Net.Runtime.Tests { NewLocalTestbed().RunTest(Testsuite.Ownership3); } + + [TestMethod] + public void EagerRace() + { + var impl = new TestMoreStuffImpl(new Counters()); + var tcs = new TaskCompletionSource(); + using (var promise = tcs.Task.Eager(true)) + using (var cts = new CancellationTokenSource()) + { + var bb = new BufferBlock>(); + int counter = 0; + + void Generator() + { + while (!cts.IsCancellationRequested) + { + bb.Post(promise.GetCallSequence((uint)Volatile.Read(ref counter))); + Interlocked.Increment(ref counter); + } + + bb.Complete(); + } + + async Task Verifier() + { + uint i = 0; + while (true) + { + Task t; + + try + { + t = await bb.ReceiveAsync(); + } + catch (InvalidOperationException) + { + break; + } + + uint j = await t; + Assert.AreEqual(i, j); + i++; + } + } + + var genTask = Task.Run(() => Generator()); + var verTask = Verifier(); + SpinWait.SpinUntil(() => Volatile.Read(ref counter) >= 100); + tcs.SetResult(impl); + cts.Cancel(); + Assert.IsTrue(genTask.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(verTask.Wait(MediumNonDbgTimeout)); + } + } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index 009c94d..af749ba 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -68,7 +68,7 @@ namespace Capnp.Net.Runtime.Tests { try { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); } @@ -97,7 +97,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); @@ -116,7 +116,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); @@ -134,7 +134,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); @@ -175,7 +175,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); @@ -214,7 +214,7 @@ namespace Capnp.Net.Runtime.Tests { try { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); @@ -258,7 +258,7 @@ namespace Capnp.Net.Runtime.Tests { try { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); @@ -317,7 +317,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); @@ -354,7 +354,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); @@ -427,7 +427,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); @@ -503,7 +503,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); @@ -620,7 +620,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); @@ -667,7 +667,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout); Assert.AreEqual(1, server.ConnectionCount); diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index 6d41fc9..1349fd5 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -26,7 +26,7 @@ namespace Capnp.Net.Runtime.Tests { using (var client = SetupClient()) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -62,8 +62,8 @@ namespace Capnp.Net.Runtime.Tests using (var client1 = SetupClient()) using (var client2 = SetupClient()) { - Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout)); + //Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout)); + //Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout)); using (var main = client1.GetMain()) { @@ -132,7 +132,7 @@ namespace Capnp.Net.Runtime.Tests using (var client = SetupClient()) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -154,7 +154,7 @@ namespace Capnp.Net.Runtime.Tests using (var client = SetupClient()) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -184,7 +184,7 @@ namespace Capnp.Net.Runtime.Tests using (var client = SetupClient()) { - Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); + //Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); using (var main = client.GetMain()) { @@ -196,7 +196,7 @@ namespace Capnp.Net.Runtime.Tests using (var client2 = SetupClient()) { - Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout)); + //Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout)); using (var main2 = client2.GetMain()) { @@ -221,7 +221,7 @@ namespace Capnp.Net.Runtime.Tests using (var client = SetupClient()) { - Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); + //Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); using (var main = client.GetMain()) { @@ -232,7 +232,7 @@ namespace Capnp.Net.Runtime.Tests using (var c = fooTask.Result.C) using (var client2 = SetupClient()) { - Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout)); + //Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout)); using (var main2 = client2.GetMain()) { @@ -255,7 +255,7 @@ namespace Capnp.Net.Runtime.Tests using (var client = SetupClient()) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { diff --git a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs index 7ad9852..d274d67 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs @@ -135,7 +135,7 @@ namespace Capnp.Net.Runtime.Tests { using (var client = new TcpRpcClient("localhost", TcpPort)) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -185,7 +185,7 @@ namespace Capnp.Net.Runtime.Tests using (var client = new TcpRpcClient("localhost", TcpPort)) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -239,7 +239,7 @@ namespace Capnp.Net.Runtime.Tests { using (var client = new TcpRpcClient("localhost", TcpPort)) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -305,7 +305,7 @@ namespace Capnp.Net.Runtime.Tests { using (var client = new TcpRpcClient("localhost", TcpPort)) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -407,7 +407,7 @@ namespace Capnp.Net.Runtime.Tests client.AttachTracer(tracer); client.Connect("localhost", TcpPort); - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -475,7 +475,7 @@ namespace Capnp.Net.Runtime.Tests using (var client = new TcpRpcClient("localhost", TcpPort)) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -520,7 +520,7 @@ namespace Capnp.Net.Runtime.Tests { using (var client = new TcpRpcClient("localhost", TcpPort)) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -589,7 +589,7 @@ namespace Capnp.Net.Runtime.Tests using (var client = new TcpRpcClient("localhost", TcpPort)) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -682,7 +682,7 @@ namespace Capnp.Net.Runtime.Tests { using (var client = new TcpRpcClient("localhost", TcpPort)) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var destructionPromise = new TaskCompletionSource(); var destructionTask = destructionPromise.Task; @@ -740,7 +740,7 @@ namespace Capnp.Net.Runtime.Tests { using (var client = new TcpRpcClient("localhost", TcpPort)) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -802,36 +802,15 @@ namespace Capnp.Net.Runtime.Tests { LaunchCompatTestProcess("server:MoreStuff", stdout => { - int retry = 0; - - label: using (var client = new TcpRpcClient("localhost", TcpPort)) { - Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout), "client connect"); + //Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout), "client connect"); - using (var main = client.GetMain()) + using (var wrapped = client.GetMain()) { - var resolving = main as IResolvingCapability; - - bool success; - - try - { - success = resolving.WhenResolved.Wait(MediumNonDbgTimeout); - } - catch - { - success = false; - } - - if (!success) - { - if (++retry == 5) - { - Assert.Fail("Attempting to obtain bootstrap interface failed. Bailing out."); - } - goto label; - } + var unwrap = wrapped.Unwrap(); + Assert.IsTrue(unwrap.Wait(MediumNonDbgTimeout)); + var main = unwrap.Result; var cap = new TestCallOrderImpl(); cap.CountToDispose = 6; @@ -892,7 +871,7 @@ namespace Capnp.Net.Runtime.Tests label: using (var client = new TcpRpcClient("localhost", TcpPort)) { - Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout), "client connect"); + //Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout), "client connect"); using (var main = client.GetMain()) { @@ -986,7 +965,7 @@ namespace Capnp.Net.Runtime.Tests using (var client = new TcpRpcClient("localhost", TcpPort)) { - Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); + //Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); using (var main = client.GetMain()) { @@ -1079,7 +1058,7 @@ namespace Capnp.Net.Runtime.Tests label: using (var client = new TcpRpcClient("localhost", TcpPort)) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { @@ -1152,7 +1131,7 @@ namespace Capnp.Net.Runtime.Tests { using (var client = new TcpRpcClient("localhost", TcpPort)) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); using (var main = client.GetMain()) { diff --git a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs index 9e7cd2a..20fc392 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs @@ -43,7 +43,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); @@ -151,7 +151,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); server.Main = impl; for (int i = 0; i < 10; i++) diff --git a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs index 7fb4590..43a3cbd 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs @@ -35,7 +35,7 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); var impl = new TestMoreStuffImpl(counters); @@ -109,7 +109,7 @@ namespace Capnp.Net.Runtime.Tests server.InjectMidlayer(s => new ScatteringStream(s, 7)); client.InjectMidlayer(s => new ScatteringStream(s, 10)); client.Connect("localhost", TcpPort); - client.WhenConnected.Wait(); + //client.WhenConnected.Wait(); var counters = new Counters(); server.Main = new TestInterfaceImpl(counters); diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 5f13b70..5770c2c 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -15,7 +15,7 @@ namespace Capnp.Net.Runtime.Tests { public interface ITestbed { - T ConnectMain(object main) where T : class; + T ConnectMain(object main) where T : class, IDisposable; void MustComplete(params Task[] tasks); void MustNotComplete(params Task[] tasks); void FlushCommunication(); @@ -241,7 +241,7 @@ namespace Capnp.Net.Runtime.Tests public void RunTest(Action action) { (_server, _client) = SetupClientServerPair(); - _client.WhenConnected.Wait(MediumNonDbgTimeout); + //_client.WhenConnected.Wait(MediumNonDbgTimeout); Assert.IsTrue(SpinWait.SpinUntil(() => _server.ConnectionCount > 0, MediumNonDbgTimeout)); var conn = _server.Connections[0]; diff --git a/Capnp.Net.Runtime/ListOfPrimitivesDeserializer.cs b/Capnp.Net.Runtime/ListOfPrimitivesDeserializer.cs index 072d371..a2f4616 100644 --- a/Capnp.Net.Runtime/ListOfPrimitivesDeserializer.cs +++ b/Capnp.Net.Runtime/ListOfPrimitivesDeserializer.cs @@ -31,7 +31,7 @@ namespace Capnp var state = _lpd.State; if (index < 0 || index >= _lpd.Count) - throw new ArgumentOutOfRangeException(nameof(index)); + throw new IndexOutOfRangeException(); state.Offset += index; state.Kind = ObjectKind.Struct; diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index 9794e3f..bd3f037 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -1,4 +1,5 @@ -using System; +using Capnp.Util; +using System; using System.Threading; using System.Threading.Tasks; @@ -18,11 +19,11 @@ namespace Capnp.Rpc } readonly Task? _proxyTask; - readonly Task _capTask; + readonly StrictlyOrderedAwaitTask _capTask; public LazyCapability(Task capabilityTask) { - _capTask = capabilityTask; + _capTask = capabilityTask.EnforceAwaitOrder(); } public LazyCapability(Task proxyTask) @@ -31,7 +32,7 @@ namespace Capnp.Rpc async Task AwaitCap() => (await _proxyTask!).ConsumedCap; - _capTask = AwaitCap(); + _capTask = AwaitCap().EnforceAwaitOrder(); } internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) @@ -61,11 +62,13 @@ namespace Capnp.Rpc } } - public Task WhenResolved => _capTask; + async Task AwaitWhenResolved() => await _capTask; + + public Task WhenResolved => AwaitWhenResolved(); public T? GetResolvedCapability() where T: class { - if (_capTask.IsCompleted) + if (_capTask.WrappedTask.IsCompleted) { try { diff --git a/Capnp.Net.Runtime/Rpc/PolySkeleton.cs b/Capnp.Net.Runtime/Rpc/PolySkeleton.cs index c7762dd..cf08a03 100644 --- a/Capnp.Net.Runtime/Rpc/PolySkeleton.cs +++ b/Capnp.Net.Runtime/Rpc/PolySkeleton.cs @@ -25,8 +25,9 @@ namespace Capnp.Rpc if (skeleton == null) throw new ArgumentNullException(nameof(skeleton)); - skeleton.Claim(); _ifmap.Add(interfaceId, skeleton); + if (_ifmap.Count == 1) // Claiming only the first one is sufficient + skeleton.Claim(); } internal void AddInterface(Skeleton skeleton) @@ -60,8 +61,6 @@ namespace Capnp.Rpc { cap.Relinquish(); } - - base.Dispose(disposing); } internal override void Bind(object impl) diff --git a/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs b/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs index 6b872fd..55771ad 100644 --- a/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs +++ b/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs @@ -151,24 +151,20 @@ namespace Capnp.Rpc /// Bootstrap capability interface /// A proxy for the bootstrap capability /// Not connected - public TProxy GetMain() where TProxy: class + public TProxy GetMain() where TProxy: class, IDisposable { if (WhenConnected == null) { throw new InvalidOperationException("Not connecting"); } - if (!WhenConnected.IsCompleted) + async Task GetMainAsync() { - throw new InvalidOperationException("Connection not yet established"); + await WhenConnected!; + return (CapabilityReflection.CreateProxy(_inboundEndpoint!.QueryMain()) as TProxy)!; } - if (!WhenConnected.ReplacementTaskIsCompletedSuccessfully()) - { - throw new InvalidOperationException("Connection not successfully established"); - } - - return (CapabilityReflection.CreateProxy(_inboundEndpoint!.QueryMain()) as TProxy)!; + return GetMainAsync().Eager(true); } /// diff --git a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs new file mode 100644 index 0000000..714ee2f --- /dev/null +++ b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Capnp.Util +{ + internal class StrictlyOrderedAwaitTask: INotifyCompletion + { + readonly Task _awaitedTask; + object _lock; + long _inOrder, _outOrder; + + public StrictlyOrderedAwaitTask(Task awaitedTask) + { + _awaitedTask = awaitedTask; + _lock = new object(); + } + + public StrictlyOrderedAwaitTask GetAwaiter() + { + return this; + } + + public async void OnCompleted(Action continuation) + { + object safeLock = Volatile.Read(ref _lock); + + if (safeLock == null) + { + continuation(); + return; + } + + long sequence = Interlocked.Increment(ref _inOrder) - 1; + + try + { + if (_awaitedTask.IsCompleted) + { + Interlocked.Exchange(ref _lock, null); + } + + await _awaitedTask; + } + catch + { + } + finally + { + SpinWait.SpinUntil(() => + { + lock (safeLock) + { + if (Volatile.Read(ref _outOrder) != sequence) + { + return false; + } + + Interlocked.Increment(ref _outOrder); + + continuation(); + + return true; + } + }); + } + } + + public bool IsCompleted => Volatile.Read(ref _lock) == null; + + public T GetResult() => _awaitedTask.GetAwaiter().GetResult(); + + public T Result => _awaitedTask.Result; + + public Task WrappedTask => _awaitedTask; + } + + internal static class StrictlyOrderedTaskExtensions + { + public static StrictlyOrderedAwaitTask EnforceAwaitOrder(this Task task) + { + return new StrictlyOrderedAwaitTask(task); + } + } +} From 197817a7d77a38f6de51003d0faaeb8b7d27e833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 11 Apr 2020 21:21:17 +0200 Subject: [PATCH 40/76] PendingAnswer should also use StrictlyOrderedAwaitTask --- Capnp.Net.Runtime/Rpc/PendingAnswer.cs | 163 ++++++++++++------------- 1 file changed, 79 insertions(+), 84 deletions(-) diff --git a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs index 8692f6f..e4fb99f 100644 --- a/Capnp.Net.Runtime/Rpc/PendingAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/PendingAnswer.cs @@ -1,4 +1,5 @@ -using System; +using Capnp.Util; +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -9,7 +10,7 @@ namespace Capnp.Rpc { readonly CancellationTokenSource? _cts; readonly TaskCompletionSource _cancelCompleter; - readonly Task _answerTask; + readonly StrictlyOrderedAwaitTask _answerTask; public PendingAnswer(Task callTask, CancellationTokenSource? cts) { @@ -23,19 +24,16 @@ namespace Capnp.Rpc _cts = cts; _cancelCompleter = new TaskCompletionSource(); - _answerTask = CancelableAwaitWhenReady(); + _answerTask = CancelableAwaitWhenReady().EnforceAwaitOrder(); - Chain(async t => + TakeCapTableOwnership(); + } + + async void TakeCapTableOwnership() + { + try { - var aorcq = default(AnswerOrCounterquestion); - - try - { - aorcq = await t; - } - catch - { - } + var aorcq = await _answerTask; if (aorcq.Answer != null) { @@ -43,11 +41,35 @@ namespace Capnp.Rpc { foreach (var cap in aorcq.Answer.Caps) { - cap?.AddRef(); + cap.AddRef(); } } } - }); + } + catch + { + } + } + + async void ReleaseCapTableOwnership() + { + try + { + var aorcq = await _answerTask; + if (aorcq.Answer != null) + { + if (aorcq.Answer.Caps != null) + { + foreach (var cap in aorcq.Answer.Caps) + { + cap?.Release(); + } + } + } + } + catch + { + } } public CancellationToken CancellationToken => _cts?.Token ?? CancellationToken.None; @@ -60,105 +82,78 @@ namespace Capnp.Rpc _cancelCompleter.SetCanceled(); } - public void Chain(Action> func) + public void Chain(Action> func) { func(_answerTask); } public void Chain(PromisedAnswer.READER rd, Action> func) { - Chain(t => + async Task EvaluateProxy() { - async Task EvaluateProxy() + var aorcq = await _answerTask; + + if (aorcq.Answer != null) { - var aorcq = await t; + DeserializerState cur = aorcq.Answer; - if (aorcq.Answer != null) + foreach (var op in rd.Transform) { - DeserializerState cur = aorcq.Answer; - - foreach (var op in rd.Transform) + switch (op.which) { - switch (op.which) - { - case PromisedAnswer.Op.WHICH.GetPointerField: - try - { - cur = cur.StructReadPointer(op.GetPointerField); - } - catch (System.Exception) - { - throw new RpcException("Illegal pointer field in transformation operation"); - } - break; - - case PromisedAnswer.Op.WHICH.Noop: - break; - - default: - throw new ArgumentOutOfRangeException("Unknown transformation operation"); - } - } - - switch (cur.Kind) - { - case ObjectKind.Capability: + case PromisedAnswer.Op.WHICH.GetPointerField: try { - return new Proxy(aorcq.Answer.Caps![(int)cur.CapabilityIndex]); + cur = cur.StructReadPointer(op.GetPointerField); } - catch (ArgumentOutOfRangeException) + catch (System.Exception) { - throw new RpcException("Capability index out of range"); + throw new RpcException("Illegal pointer field in transformation operation"); } + break; - case ObjectKind.Nil: - return new Proxy(NullCapability.Instance); + case PromisedAnswer.Op.WHICH.Noop: + break; default: - throw new ArgumentOutOfRangeException("Transformation did not result in a capability"); + throw new ArgumentOutOfRangeException("Unknown transformation operation"); } } - else + + switch (cur.Kind) { - var path = MemberAccessPath.Deserialize(rd); - var cap = new RemoteAnswerCapability(aorcq.Counterquestion!, path); - return new Proxy(cap); + case ObjectKind.Capability: + try + { + return new Proxy(aorcq.Answer.Caps![(int)cur.CapabilityIndex]); + } + catch (ArgumentOutOfRangeException) + { + throw new RpcException("Capability index out of range"); + } + + case ObjectKind.Nil: + return new Proxy(NullCapability.Instance); + + default: + throw new ArgumentOutOfRangeException("Transformation did not result in a capability"); } } + else + { + var path = MemberAccessPath.Deserialize(rd); + var cap = new RemoteAnswerCapability(aorcq.Counterquestion!, path); + return new Proxy(cap); + } + } - func(EvaluateProxy()); - }); + func(EvaluateProxy()); } public void Dispose() { _cts?.Dispose(); - - Chain(async t => - { - AnswerOrCounterquestion aorcq; - - try - { - aorcq = await t; - } - catch - { - return; - } - - if (aorcq.Answer != null) - { - if (aorcq.Answer.Caps != null) - { - foreach (var cap in aorcq.Answer.Caps) - { - cap?.Release(); - } - } - } - }); + ReleaseCapTableOwnership(); } } } \ No newline at end of file From a205b45d151a65fad68192600d00986f41b5e976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 11 Apr 2020 23:57:04 +0200 Subject: [PATCH 41/76] test & fix --- Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs | 70 +++++++ Capnp.Net.Runtime.Tests/ImpatientTests.cs | 191 ++++++++++++++++++ Capnp.Net.Runtime.Tests/Interception.cs | 33 ++- Capnp.Net.Runtime.Tests/TcpRpc.cs | 69 ++++++- .../Rpc/Interception/Interceptor.cs | 3 - Capnp.Net.Runtime/Rpc/Proxy.cs | 2 +- 6 files changed, 361 insertions(+), 7 deletions(-) create mode 100644 Capnp.Net.Runtime.Tests/ImpatientTests.cs diff --git a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs index b399f0a..0986996 100644 --- a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs +++ b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs @@ -1179,7 +1179,77 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(Message.WHICH.Call, _.which); Assert.AreEqual(MessageTarget.WHICH.ImportedCap, _.Call.Target.which); Assert.AreEqual(27u, _.Call.Target.ImportedCap); + + tester.Send(_1 => + { + _1.which = Message.WHICH.Return; + _1.Return.AnswerId = _.Call.QuestionId; + _1.Return.which = Return.WHICH.Results; + _1.Return.Results.CapTable.Init(1); + _1.Return.Results.CapTable[0].which = CapDescriptor.WHICH.ThirdPartyHosted; + _1.Return.Results.CapTable[0].ThirdPartyHosted.VineId = 27; + _1.Return.Results.Content.SetCapability(0); + }); }); } + + [TestMethod] + public void NoneImportBootstrap() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + + tester.Send(_1 => + { + _1.which = Message.WHICH.Return; + _1.Return.AnswerId = _.Bootstrap.QuestionId; + _1.Return.which = Return.WHICH.Results; + _1.Return.Results.CapTable.Init(1); + _1.Return.Results.CapTable[0].which = CapDescriptor.WHICH.None; + }); + }); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Finish, _.which); + }); + + var answer = proxy.Call(1, 2, DynamicSerializerState.CreateForRpc()); + var task = Impatient.MakePipelineAware(answer, _ => _); + Assert.IsTrue(task.IsFaulted); + Assert.IsFalse(tester.IsDismissed); + } + + [TestMethod] + public void UnknownImportBootstrap() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + + tester.Send(_1 => + { + _1.which = Message.WHICH.Return; + _1.Return.AnswerId = _.Bootstrap.QuestionId; + _1.Return.which = Return.WHICH.Results; + _1.Return.Results.CapTable.Init(1); + _1.Return.Results.CapTable[0].which = (CapDescriptor.WHICH)27; + }); + }); + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Unimplemented, _.which); + }); + + Assert.IsFalse(tester.IsDismissed); + } } } diff --git a/Capnp.Net.Runtime.Tests/ImpatientTests.cs b/Capnp.Net.Runtime.Tests/ImpatientTests.cs new file mode 100644 index 0000000..e32c89f --- /dev/null +++ b/Capnp.Net.Runtime.Tests/ImpatientTests.cs @@ -0,0 +1,191 @@ +using Capnp.Net.Runtime.Tests.GenImpls; +using Capnp.Rpc; +using Capnproto_test.Capnp.Test; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Capnp.Net.Runtime.Tests +{ + [TestClass] + [TestCategory("Coverage")] + public class ImpatientTests + { + [TestMethod] + public async Task Unwrap() + { + var impl = new TestInterfaceImpl2(); + Assert.AreEqual(impl, await impl.Unwrap()); + Assert.IsNull(await default(ITestInterface).Unwrap()); + var tcs = new TaskCompletionSource(); + tcs.SetResult(null); + Assert.IsNull(await tcs.Task.Eager(true).Unwrap()); + var excepted = Task.FromException(new InvalidTimeZoneException("So annoying")); + await Assert.ThrowsExceptionAsync(async () => await excepted.Eager(true).Unwrap()); + } + + [TestMethod] + public async Task MaybeTailCall3() + { + bool flag = false; + + SerializerState Fn(int a, int b, int c) + { + Assert.AreEqual(0, a); + Assert.AreEqual(1, b); + Assert.AreEqual(2, c); + flag = true; + return null; + } + + var t = Task.FromResult((0, 1, 2)); + await Impatient.MaybeTailCall(t, Fn); + Assert.IsTrue(flag); + } + + [TestMethod] + public async Task MaybeTailCall4() + { + bool flag = false; + + SerializerState Fn(int a, int b, int c, int d) + { + Assert.AreEqual(0, a); + Assert.AreEqual(1, b); + Assert.AreEqual(2, c); + Assert.AreEqual(3, d); + flag = true; + return null; + } + + var t = Task.FromResult((0, 1, 2, 3)); + await Impatient.MaybeTailCall(t, Fn); + Assert.IsTrue(flag); + } + + [TestMethod] + public async Task MaybeTailCall5() + { + bool flag = false; + + SerializerState Fn(int a, int b, int c, int d, int e) + { + Assert.AreEqual(0, a); + Assert.AreEqual(1, b); + Assert.AreEqual(2, c); + Assert.AreEqual(3, d); + Assert.AreEqual(4, e); + flag = true; + return null; + } + + var t = Task.FromResult((0, 1, 2, 3, 4)); + await Impatient.MaybeTailCall(t, Fn); + Assert.IsTrue(flag); + } + + [TestMethod] + public async Task MaybeTailCall6() + { + bool flag = false; + + SerializerState Fn(int a, int b, int c, int d, int e, int f) + { + Assert.AreEqual(0, a); + Assert.AreEqual(1, b); + Assert.AreEqual(2, c); + Assert.AreEqual(3, d); + Assert.AreEqual(4, e); + Assert.AreEqual(5, f); + flag = true; + return null; + } + + var t = Task.FromResult((0, 1, 2, 3, 4, 5)); + await Impatient.MaybeTailCall(t, Fn); + Assert.IsTrue(flag); + } + + [TestMethod] + public async Task MaybeTailCall7() + { + bool flag = false; + + SerializerState Fn(int a, int b, int c, int d, int e, int f, int g) + { + Assert.AreEqual(0, a); + Assert.AreEqual(1, b); + Assert.AreEqual(2, c); + Assert.AreEqual(3, d); + Assert.AreEqual(4, e); + Assert.AreEqual(5, f); + Assert.AreEqual(6, g); + flag = true; + return null; + } + + var t = Task.FromResult((0, 1, 2, 3, 4, 5, 6)); + await Impatient.MaybeTailCall(t, Fn); + Assert.IsTrue(flag); + } + + class PromisedAnswerMock : IPromisedAnswer + { + readonly TaskCompletionSource _tcs = new TaskCompletionSource(); + public Task WhenReturned => _tcs.Task; + + public bool IsTailCall => false; + + public ConsumedCapability Access(MemberAccessPath access) + { + throw new NotImplementedException(); + } + + public ConsumedCapability Access(MemberAccessPath access, Task proxyTask) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + } + } + + [TestMethod] + public void ObsoleteGetAnswer() + { + var answer = new PromisedAnswerMock(); + Assert.ThrowsException(() => Impatient.GetAnswer(answer.WhenReturned)); + var t = Impatient.MakePipelineAware(answer, _ => _); + Assert.AreEqual(answer, Impatient.GetAnswer(t)); + } + + [TestMethod] + public async Task Access() + { + var answer = new PromisedAnswerMock(); + var cap = Impatient.Access(answer.WhenReturned, new MemberAccessPath(), Task.FromResult(new TestInterfaceImpl2())); + using (var proxy = new BareProxy(cap)) + { + await proxy.WhenResolved; + } + } + + [TestMethod] + public void ObsoletePseudoEager() + { + var task = Task.FromResult(new TestInterfaceImpl2()); + Assert.IsTrue(task.PseudoEager() is Proxy proxy && proxy.WhenResolved.IsCompleted); + } + + [TestMethod] + public void Eager() + { + var task = Task.FromResult(new TestInterfaceImpl2()); + Assert.ThrowsException(() => task.Eager(false)); + Assert.ThrowsException(() => task.Eager()); + } + } +} diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index 0e0e010..4d86f85 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -67,9 +67,8 @@ namespace Capnp.Net.Runtime.Tests using (server) using (client) { - //client.WhenConnected.Wait(); - var counters = new Counters(); + server.Main = policy.Attach(new TestInterfaceImpl(counters)); using (var main = client.GetMain()) { @@ -696,5 +695,35 @@ namespace Capnp.Net.Runtime.Tests } } + [TestMethod] + public void AttachWrongUse() + { + var impl = new TestInterfaceImpl2(); + Assert.ThrowsException(() => default(IInterceptionPolicy).Attach(impl)); + Assert.ThrowsException(() => new MyPolicy("x").Attach(default(ITestInterface))); + } + + [TestMethod] + public void DetachWrongUse() + { + var impl = new TestInterfaceImpl2(); + Assert.ThrowsException(() => default(IInterceptionPolicy).Detach(impl)); + Assert.ThrowsException(() => new MyPolicy("x").Detach(default(ITestInterface))); + } + + [TestMethod] + public void AttachDetach() + { + ConsumedCapability GetCap(object obj) => ((Proxy)obj).ConsumedCap; + + var a = new MyPolicy("a"); + var b = new MyPolicy("b"); + var c = new MyPolicy("c"); + var proxy = Proxy.Share(new TestInterfaceImpl2()); + var attached = a.Attach(b.Attach(c.Attach(proxy))); + Assert.AreEqual(GetCap(attached), GetCap(b.Attach(attached))); + var detached = c.Detach(a.Detach(b.Detach(attached))); + Assert.AreEqual(GetCap(proxy), GetCap(detached)); + } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index af749ba..1782101 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -719,7 +719,7 @@ namespace Capnp.Net.Runtime.Tests } [TestMethod] - public void Server() + public void Server1() { var cbb = new BufferBlock(); var server = new TcpRpcServer(); @@ -808,5 +808,72 @@ namespace Capnp.Net.Runtime.Tests server.Dispose(); } + + [TestMethod] + public void Server2() + { + var server = new TcpRpcServer(); + server.Main = new TestInterfaceImpl2(); + var tracer = new FrameTracing.RpcFrameTracer(Console.Out); + server.OnConnectionChanged += (s, a) => + { + server.Dispose(); + }; + + server.StartAccepting(IPAddress.Any, TcpPort); + + var client1 = new TcpRpcClient("localhost", TcpPort); + Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout)); + } + + [TestMethod] + public void Server3() + { + using (var server = new TcpRpcServer()) + { + server.Main = new TestInterfaceImpl2(); + var tracer = new FrameTracing.RpcFrameTracer(Console.Out); + server.OnConnectionChanged += (s, a) => + { + a.Connection.Close(); + }; + + server.StartAccepting(IPAddress.Any, TcpPort); + + var client1 = new TcpRpcClient("localhost", TcpPort); + Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout)); + } + } + + [TestMethod] + public void Client() + { + using (var server = new TcpRpcServer()) + using (var client = new TcpRpcClient()) + { + Assert.IsFalse(client.IsComputing); + Assert.IsFalse(client.IsWaitingForData); + Assert.AreEqual(0L, client.SendCount); + Assert.AreEqual(0L, client.RecvCount); + Assert.ThrowsException(() => client.GetMain()); + Assert.ThrowsException(() => client.AttachTracer(null)); + Assert.ThrowsException(() => client.InjectMidlayer(null)); + server.StartAccepting(IPAddress.Any, TcpPort); + client.Connect("localhost", TcpPort); + Assert.ThrowsException(() => client.Connect("localhost", TcpPort)); + Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); + Assert.ThrowsException(() => client.AttachTracer(new FrameTracing.RpcFrameTracer(Console.Out, false))); + Assert.ThrowsException(() => client.InjectMidlayer(_ => _)); + Assert.AreEqual(TcpPort, client.RemotePort); + Assert.IsTrue(client.LocalPort != 0); + Assert.AreEqual(0L, client.SendCount); + Assert.AreEqual(0L, client.RecvCount); + Assert.IsTrue(SpinWait.SpinUntil(() => client.IsWaitingForData, MediumNonDbgTimeout)); + ((IConnection)client).Close(); + Assert.IsTrue(SpinWait.SpinUntil(() => client.State == ConnectionState.Down, MediumNonDbgTimeout)); + } + } } } diff --git a/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs b/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs index b951676..ae692fd 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/Interceptor.cs @@ -9,9 +9,6 @@ namespace Capnp.Rpc.Interception /// public static class Interceptor { - static readonly ConditionalWeakTable _interceptMap = - new ConditionalWeakTable(); - /// /// Attach this policy to given capability. /// diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index f82b6e0..48657ff 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -58,7 +58,7 @@ namespace Capnp.Rpc /// /// Underlying low-level capability /// - protected internal ConsumedCapability ConsumedCap => _disposedValue ? + public ConsumedCapability ConsumedCap => _disposedValue ? throw new ObjectDisposedException(nameof(Proxy)) : _consumedCap; /// From 4441ef6c8e4aea3bbc93098243068d5d3612d10c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Mon, 13 Apr 2020 20:22:52 +0200 Subject: [PATCH 42/76] test & fix --- Capnp.Net.Runtime.Tests/Dtbdct.cs | 12 +++ Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs | 1 + Capnp.Net.Runtime.Tests/SerializationTests.cs | 76 ++++++++++++++++++- Capnp.Net.Runtime.Tests/TcpRpc.cs | 5 +- .../TcpRpcAdvancedStuff.cs | 12 +++ Capnp.Net.Runtime.Tests/Testsuite.cs | 35 +++++++++ Capnp.Net.Runtime.Tests/Util/TestBase.cs | 51 ++++++++++++- .../ListOfPrimitivesSerializer.cs | 4 +- Capnp.Net.Runtime/Rpc/CapabilityReflection.cs | 2 +- Capnp.Net.Runtime/Rpc/LazyCapability.cs | 6 -- Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 23 +----- Capnp.Net.Runtime/Rpc/Proxy.cs | 2 +- .../Rpc/RemoteAnswerCapability.cs | 9 +-- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 5 +- Capnp.Net.Runtime/Rpc/TcpRpcServer.cs | 40 +--------- Capnp.Net.Runtime/SerializerState.cs | 10 ++- .../Util/StrictlyOrderedAwaitTask.cs | 6 +- scripts/measure-coverage.ps1 | 2 +- 18 files changed, 206 insertions(+), 95 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/Dtbdct.cs b/Capnp.Net.Runtime.Tests/Dtbdct.cs index 57ae39c..d67860d 100644 --- a/Capnp.Net.Runtime.Tests/Dtbdct.cs +++ b/Capnp.Net.Runtime.Tests/Dtbdct.cs @@ -176,5 +176,17 @@ namespace Capnp.Net.Runtime.Tests { NewDtbdctTestbed().RunTest(Testsuite.ReexportSenderPromise); } + + [TestMethod] + public void CallAfterFinish1() + { + NewDtbdctTestbed().RunTest(Testsuite.CallAfterFinish1); + } + + [TestMethod] + public void CallAfterFinish2() + { + NewDtbdctTestbed().RunTest(Testsuite.CallAfterFinish2); + } } } diff --git a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs index 0986996..0e61fa5 100644 --- a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs +++ b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs @@ -29,6 +29,7 @@ namespace Capnp.Net.Runtime.Tests { var pipe = new Pipe(); _fromEnginePump = new FramePump(pipe.Writer.AsStream()); + _fromEnginePump.AttachTracer(new FrameTracing.RpcFrameTracer(Console.Out, false)); _reader = new BinaryReader(pipe.Reader.AsStream()); } diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs index 64a2835..57874ef 100644 --- a/Capnp.Net.Runtime.Tests/SerializationTests.cs +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -276,7 +276,7 @@ namespace Capnp.Net.Runtime.Tests } [TestMethod] - public void ListOfUShorts() + public void ListOfUShortsWrongUse() { var b = MessageBuilder.Create(); var wrong = b.CreateObject(); @@ -289,6 +289,54 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => list.ListWriteValue(64, (ushort)1)); } + [TestMethod] + public void ListOfUShortsFromSegment() + { + var b = MessageBuilder.Create(); + var list = b.CreateObject>(); + var array = new ushort[] { 1, 2, 3, 4, 5, 6 }; + var segment = new ArraySegment(array, 1, 3); + list.Init(segment); + CollectionAssert.AreEqual(segment.ToArray(), list.ToArray()); + } + + [TestMethod] + public void ListOfUShortsFromDeser() + { + var b = MessageBuilder.Create(); + var list0 = b.CreateObject>(); + var expected = new ushort[] { 2, 3, 4 }; + list0.Init(expected); + var deser = ((DeserializerState)list0).RequireList().CastUShort(); + var list = b.CreateObject>(); + list.Init(deser); + CollectionAssert.AreEqual(expected, list.ToArray()); + } + + [TestMethod] + public void ListOfUShortsFromSer() + { + var b = MessageBuilder.Create(); + var list0 = b.CreateObject>(); + var expected = new ushort[] { 2, 3, 4 }; + list0.Init(expected); + var list = b.CreateObject>(); + list.Init(list0); + CollectionAssert.AreEqual(expected, list.ToArray()); + } + + [TestMethod] + public void ListOfUShortsFromList() + { + var b = MessageBuilder.Create(); + var list0 = b.CreateObject>(); + var expected = new List { 2, 3, 4 }; + list0.Init(expected); + var list = b.CreateObject>(); + list.Init(list0); + CollectionAssert.AreEqual(expected, list.ToArray()); + } + [TestMethod] public void ListOfUInts() { @@ -1093,7 +1141,7 @@ namespace Capnp.Net.Runtime.Tests { var mb = MessageBuilder.Create(); var dss = mb.CreateObject(); - dss.SetStruct(0, 4); + dss.SetStruct(0, 5); var s1 = mb.CreateObject(); s1.SomeText = "foo"; s1.MoreText = "bar"; @@ -1109,7 +1157,8 @@ namespace Capnp.Net.Runtime.Tests s4.SomeText = "1"; var arr = new SomeStruct.WRITER[] { s3, s4 }; dss.LinkObject(2, arr); - Assert.ThrowsException(() => dss.LinkObject(3, new object())); + Assert.ThrowsException(() => dss.LinkObject(3, new object())); + dss.LinkObject(3, new SomeStruct() { SomeText = "corge" }); var t1 = dss.BuildPointer(0).Rewrap(); Assert.AreEqual("foo", t1.SomeText); @@ -1121,7 +1170,8 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(2, l.Count); Assert.AreEqual("0", l[0].SomeText); Assert.AreEqual("1", l[1].SomeText); - Assert.AreEqual(ObjectKind.Nil, dss.BuildPointer(3).Kind); + Assert.AreEqual("corge", dss.BuildPointer(3).Rewrap().SomeText); + Assert.AreEqual(ObjectKind.Nil, dss.BuildPointer(4).Kind); } [TestMethod] @@ -1138,5 +1188,23 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(cap.IsDisposed); dss2.Dispose(); } + + [TestMethod] + public void ProvideCapability() + { + var dss = DynamicSerializerState.CreateForRpc(); + var impl = new TestInterfaceImpl2(); + var p1 = (Proxy)Proxy.Share(impl); + var p2 = (Proxy)Proxy.Share(impl); + Assert.AreEqual(0u, dss.ProvideCapability(p1)); + Assert.AreEqual(0u, dss.ProvideCapability(p2.ConsumedCap)); + Assert.AreEqual(0u, dss.ProvideCapability(CapabilityReflection.CreateSkeleton(impl))); + Assert.IsTrue(p1.IsDisposed); + Assert.IsFalse(p2.IsDisposed); + p2.Dispose(); + Assert.IsFalse(impl.IsDisposed); + dss.Dispose(); + Assert.IsTrue(impl.IsDisposed); + } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index 1782101..0714581 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -823,8 +823,9 @@ namespace Capnp.Net.Runtime.Tests server.StartAccepting(IPAddress.Any, TcpPort); var client1 = new TcpRpcClient("localhost", TcpPort); - Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout)); + Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout), "Did not connect"); + Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout), + $"Connection did not go down: {client1.State}"); } [TestMethod] diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index 1349fd5..3f55e24 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -285,5 +285,17 @@ namespace Capnp.Net.Runtime.Tests { NewLocalhostTcpTestbed().RunTest(Testsuite.NoTailCallMt); } + + [TestMethod] + public void CallAfterFinish1() + { + NewLocalhostTcpTestbed().RunTest(Testsuite.CallAfterFinish1); + } + + [TestMethod] + public void CallAfterFinish2() + { + NewLocalhostTcpTestbed().RunTest(Testsuite.CallAfterFinish2); + } } } diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs index 77e0a59..07719f5 100644 --- a/Capnp.Net.Runtime.Tests/Testsuite.cs +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -40,6 +40,10 @@ namespace Capnp.Net.Runtime.Tests // exception had to be serialized, so we receive // the wrapped version. } + catch (TaskCanceledException) + { + // Also used in some test + } catch (System.Exception exception) { Assert.Fail($"Got wrong kind of exception: {exception}"); @@ -407,7 +411,9 @@ namespace Capnp.Net.Runtime.Tests // Note that this was a bug in previous versions: // Since passing a cap has move semantics, we need to create an explicit copy. var copy = Proxy.Share(cap); + Assert.IsFalse(((Proxy)copy).IsDisposed); var ctask = main.CallFoo(copy, default); + Assert.IsTrue(((Proxy)copy).IsDisposed); testbed.MustComplete(ctask); Assert.AreEqual("bar", ctask.Result); @@ -820,5 +826,34 @@ namespace Capnp.Net.Runtime.Tests testbed.MustComplete(tcsd.Task); } } + + public static void CallAfterFinish1(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl3(); + using (var main = testbed.ConnectMain(impl)) + { + using (var held = main.GetHeld().Eager()) + { + testbed.CloseClient(); + testbed.ExpectPromiseThrows(held.Foo(123, true)); + } + } + } + + public static void CallAfterFinish2(ITestbed testbed) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl3(); + using (var main = testbed.ConnectMain(impl)) + { + using (var cts = new CancellationTokenSource()) + using (var held = main.GetHeld(cts.Token).Eager()) + { + cts.Cancel(); + testbed.ExpectPromiseThrows(held.Foo(123, true)); + } + } + } } } diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 5770c2c..6b089b5 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -19,6 +19,8 @@ namespace Capnp.Net.Runtime.Tests void MustComplete(params Task[] tasks); void MustNotComplete(params Task[] tasks); void FlushCommunication(); + void CloseClient(); + void CloseServer(); long ClientSendCount { get; } } @@ -84,7 +86,13 @@ namespace Capnp.Net.Runtime.Tests { var frame = _frameBuffer.Dequeue(); _recursion = true; - OtherEndpoint.Forward(frame); + try + { + OtherEndpoint.Forward(frame); + } + catch (InvalidOperationException) + { + } _recursion = false; return true; @@ -177,6 +185,16 @@ namespace Capnp.Net.Runtime.Tests { Assert.IsFalse(tasks.Any(t => t.IsCompleted)); } + + void ITestbed.CloseClient() + { + throw new NotSupportedException(); + } + + void ITestbed.CloseServer() + { + throw new NotSupportedException(); + } } protected class DtbdctTestbed : ITestbed, ITestController @@ -231,17 +249,27 @@ namespace Capnp.Net.Runtime.Tests } long ITestbed.ClientSendCount => _enginePair.Channel2SendCount; + + void ITestbed.CloseClient() + { + _enginePair.Endpoint1.Dismiss(); + } + + void ITestbed.CloseServer() + { + _enginePair.Endpoint2.Dismiss(); + } } protected class LocalhostTcpTestbed : ITestbed, ITestController { TcpRpcServer _server; TcpRpcClient _client; + bool _prematurelyClosed; public void RunTest(Action action) { (_server, _client) = SetupClientServerPair(); - //_client.WhenConnected.Wait(MediumNonDbgTimeout); Assert.IsTrue(SpinWait.SpinUntil(() => _server.ConnectionCount > 0, MediumNonDbgTimeout)); var conn = _server.Connections[0]; @@ -250,8 +278,11 @@ namespace Capnp.Net.Runtime.Tests { action(this); - Assert.IsTrue(SpinWait.SpinUntil(() => _client.SendCount == conn.RecvCount, MediumNonDbgTimeout)); - Assert.IsTrue(SpinWait.SpinUntil(() => conn.SendCount == _client.RecvCount, MediumNonDbgTimeout)); + if (!_prematurelyClosed) + { + Assert.IsTrue(SpinWait.SpinUntil(() => _client.SendCount == conn.RecvCount, MediumNonDbgTimeout)); + Assert.IsTrue(SpinWait.SpinUntil(() => conn.SendCount == _client.RecvCount, MediumNonDbgTimeout)); + } } } @@ -293,6 +324,18 @@ namespace Capnp.Net.Runtime.Tests } long ITestbed.ClientSendCount => _client.SendCount; + + void ITestbed.CloseClient() + { + _prematurelyClosed = true; + _client.Dispose(); + } + + void ITestbed.CloseServer() + { + _prematurelyClosed = true; + _server.Dispose(); + } } public static int TcpPort = 49152; diff --git a/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs b/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs index 18477f4..5729e74 100644 --- a/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs +++ b/Capnp.Net.Runtime/ListOfPrimitivesSerializer.cs @@ -31,7 +31,7 @@ namespace Capnp /// /// The list's data /// - public Span Data => MemoryMarshal.Cast(RawData); + public Span Data => MemoryMarshal.Cast(RawData).Slice(0, Count); /// /// Gets or sets the value at given index. @@ -118,7 +118,7 @@ namespace Capnp IEnumerable Enumerate() { - for (int i = 0; i < Data.Length; i++) + for (int i = 0; i < Count; i++) yield return Data[i]; } diff --git a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs index 2512bda..57dfa8b 100644 --- a/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs +++ b/Capnp.Net.Runtime/Rpc/CapabilityReflection.cs @@ -239,7 +239,7 @@ namespace Capnp.Rpc } /// - /// Checks whether a given type qualifies as cpapbility interface. + /// Checks whether a given type qualifies as capability interface. /// /// type to check /// true when is a capability interface diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index bd3f037..5c1f7f7 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -104,12 +104,6 @@ namespace Capnp.Rpc cancellationToken.ThrowIfCancellationRequested(); } - if (cap == null) - { - args.Dispose(); - throw new RpcException("Broken capability"); - } - using var proxy = new Proxy(cap); var call = proxy.Call(interfaceId, methodId, args, default); var whenReturned = call.WhenReturned; diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index c822893..f2e5917 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -237,28 +237,7 @@ namespace Capnp.Rpc /// Access path /// Low-level capability /// The referenced member does not exist or does not resolve to a capability pointer. - public ConsumedCapability Access(MemberAccessPath access) - { - lock (ReentrancyBlocker) - { - if ( StateFlags.HasFlag(State.Returned) && - !StateFlags.HasFlag(State.TailCall)) - { - try - { - return access.Eval(WhenReturned.Result); - } - catch (AggregateException exception) - { - throw exception.InnerException!; - } - } - else - { - return new RemoteAnswerCapability(this, access); - } - } - } + public ConsumedCapability Access(MemberAccessPath access) => new RemoteAnswerCapability(this, access); /// /// Refer to a (possibly nested) member of this question's (possibly future) result and return diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index 48657ff..57f70ce 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -161,7 +161,7 @@ namespace Capnp.Rpc // When called from the Finalizer, we must not throw. // But when reference counting goes wrong, ConsumedCapability.Release() will throw an InvalidOperationException. // The only option here is to suppress that exception. - try { _consumedCap.Release(); } + try { _consumedCap?.Release(); } catch { } } diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index 2a49425..53a759d 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -109,18 +109,13 @@ namespace Capnp.Rpc #if DebugEmbargos Logger.LogDebug("Call by proxy"); #endif - if (_question.StateFlags.HasFlag(PendingQuestion.State.CanceledByDispose)) + if (_question.StateFlags.HasFlag(PendingQuestion.State.CanceledByDispose) || + _question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested)) { args.Dispose(); throw new ObjectDisposedException(nameof(PendingQuestion)); } - if (_question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested)) - { - args.Dispose(); - throw new InvalidOperationException("Finish request was already sent"); - } - _question.DisallowFinish(); ++_pendingCallsOnPromise; var promisedAnswer = base.DoCall(interfaceId, methodId, args); diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 3a8b8ed..83ee8f7 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -438,10 +438,7 @@ namespace Capnp.Rpc try { - lock (_callReturnBlocker) - { - Tx(mb.Frame); - } + Tx(mb.Frame); } catch (RpcException exception) { diff --git a/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs b/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs index a4d4dc0..14fb148 100644 --- a/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs +++ b/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs @@ -110,6 +110,7 @@ namespace Capnp.Rpc } } }); + PumpRunner.Start(); } public ConnectionState State { get; set; } = ConnectionState.Initializing; @@ -191,8 +192,6 @@ namespace Capnp.Rpc OnConnectionChanged?.Invoke(this, new ConnectionEventArgs(connection)); connection.Start(); } - - connection.PumpRunner!.Start(); } } catch (SocketException) @@ -207,38 +206,6 @@ namespace Capnp.Rpc } } - void SafeJoin(Thread? thread) - { - if (thread == null) - { - return; - } - - for (int retry = 0; retry < 5; ++retry) - { - try - { - if (!thread.Join(500)) - { - Logger.LogError($"Unable to join {thread.Name} within timeout"); - } - break; - } - catch (ThreadStateException) - { - // In rare cases it happens that despite thread.Start() was called, the thread did not actually start yet. - Logger.LogDebug("Waiting for thread to start in order to join it"); - Thread.Sleep(100); - } - catch (System.Exception exception) - { - Logger.LogError($"Unable to join {thread.Name}: {exception.Message}"); - break; - } - } - } - - /// /// Stops accepting incoming attempts and closes all existing connections. /// @@ -260,7 +227,7 @@ namespace Capnp.Rpc { connection.Client.Dispose(); connection.Pump?.Dispose(); - SafeJoin(connection.PumpRunner); + connection.PumpRunner?.Join(5000); } _rpcEngine.BootstrapCap = null; @@ -286,7 +253,8 @@ namespace Capnp.Rpc finally { _listener = null; - SafeJoin(_acceptorThread); + if (Thread.CurrentThread != _acceptorThread) + _acceptorThread?.Join(); _acceptorThread = null; } } diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index 39f7f80..293a424 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -1314,7 +1314,7 @@ namespace Capnp /// /// is out of range. /// - /// This state does neither describe a struct, nor a list of pointers + /// Object neither describes a struct, nor a list of pointers, nor a capability /// Another state is already linked to the specified position (sorry, no overwrite allowed) /// public void LinkObject(int slot, T obj) @@ -1346,10 +1346,16 @@ namespace Capnp break; default: - if (Rpc.CapabilityReflection.IsValidCapabilityInterface(typeof(T))) + try { LinkToCapability(slot, ProvideCapability(obj)); } + catch (Exception exception) when ( + exception is Rpc.InvalidCapabilityInterfaceException || + exception is InvalidOperationException) + { + throw new InvalidOperationException("Object neither describes a struct, nor a list of pointers, nor a capability", exception); + } break; } } diff --git a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs index 714ee2f..f5a26eb 100644 --- a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs +++ b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs @@ -10,7 +10,7 @@ namespace Capnp.Util internal class StrictlyOrderedAwaitTask: INotifyCompletion { readonly Task _awaitedTask; - object _lock; + object? _lock; long _inOrder, _outOrder; public StrictlyOrderedAwaitTask(Task awaitedTask) @@ -26,7 +26,7 @@ namespace Capnp.Util public async void OnCompleted(Action continuation) { - object safeLock = Volatile.Read(ref _lock); + object? safeLock = Volatile.Read(ref _lock); if (safeLock == null) { @@ -69,7 +69,7 @@ namespace Capnp.Util } } - public bool IsCompleted => Volatile.Read(ref _lock) == null; + public bool IsCompleted => Volatile.Read(ref _lock) == null || (_awaitedTask.IsCompleted && Volatile.Read(ref _inOrder) == 0); public T GetResult() => _awaitedTask.GetAwaiter().GetResult(); diff --git a/scripts/measure-coverage.ps1 b/scripts/measure-coverage.ps1 index c16ed26..4a7dda5 100644 --- a/scripts/measure-coverage.ps1 +++ b/scripts/measure-coverage.ps1 @@ -20,7 +20,7 @@ If(!(test-path $coverageReportDir)) } & $openCover -target:"$vsTestConsole" ` - -targetArgs:"/inIsolation $runtimeTests /TestCaseFilter:`"TestCategory=Coverage`"" ` + -targetArgs:"/inIsolation $runtimeTests /TestCaseFilter:`"TestCategory=Coverage`" /Framework:.NETCoreApp,Version=v2.1" ` -filter:"+[Capnp.Net.Runtime]Capnp.*" ` -excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" ` -output:"$coverageOutput" ` From 3252ef97f93f188c61c3c0573b23a327db771ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Wed, 15 Apr 2020 08:13:42 +0200 Subject: [PATCH 43/76] fixed deadlock in StrictlyOrderedAwaitTask --- Capnp.Net.Runtime.Tests/LocalRpc.cs | 35 +++++++++- .../Util/StrictlyOrderedAwaitTask.cs | 70 ++++++++++--------- 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/LocalRpc.cs b/Capnp.Net.Runtime.Tests/LocalRpc.cs index 55e693a..7517cd2 100644 --- a/Capnp.Net.Runtime.Tests/LocalRpc.cs +++ b/Capnp.Net.Runtime.Tests/LocalRpc.cs @@ -187,11 +187,44 @@ namespace Capnp.Net.Runtime.Tests var genTask = Task.Run(() => Generator()); var verTask = Verifier(); SpinWait.SpinUntil(() => Volatile.Read(ref counter) >= 100); - tcs.SetResult(impl); + Task.Run(() => tcs.SetResult(impl)); cts.Cancel(); Assert.IsTrue(genTask.Wait(MediumNonDbgTimeout)); Assert.IsTrue(verTask.Wait(MediumNonDbgTimeout)); } } + + [TestMethod] + public void EagerRace2() + { + for (int i = 0; i < 100; i++) + { + var tcs1 = new TaskCompletionSource(); + var tcs2 = new TaskCompletionSource(); + + var t1 = Capnp.Util.StrictlyOrderedTaskExtensions.EnforceAwaitOrder(tcs1.Task); + var t2 = Capnp.Util.StrictlyOrderedTaskExtensions.EnforceAwaitOrder(tcs2.Task); + + async Task Wait1() + { + await t1; + await t2; + } + + async Task Wait2() + { + await t2; + await t1; + } + + var w1 = Wait1(); + var w2 = Wait2(); + + Task.Run(() => tcs1.SetResult(0)); + Task.Run(() => tcs2.SetResult(0)); + + Assert.IsTrue(Task.WaitAll(new Task[] { w1, w2 }, MediumNonDbgTimeout)); + } + } } } diff --git a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs index f5a26eb..5cf1335 100644 --- a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs +++ b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs @@ -7,16 +7,17 @@ using System.Threading.Tasks; namespace Capnp.Util { - internal class StrictlyOrderedAwaitTask: INotifyCompletion + public class StrictlyOrderedAwaitTask: INotifyCompletion { + static readonly Action Capsule = () => throw new InvalidProgramException("Not invocable"); + readonly Task _awaitedTask; - object? _lock; - long _inOrder, _outOrder; + Action? _state; public StrictlyOrderedAwaitTask(Task awaitedTask) { _awaitedTask = awaitedTask; - _lock = new object(); + AwaitInternal(); } public StrictlyOrderedAwaitTask GetAwaiter() @@ -24,25 +25,10 @@ namespace Capnp.Util return this; } - public async void OnCompleted(Action continuation) + async void AwaitInternal() { - object? safeLock = Volatile.Read(ref _lock); - - if (safeLock == null) - { - continuation(); - return; - } - - long sequence = Interlocked.Increment(ref _inOrder) - 1; - try { - if (_awaitedTask.IsCompleted) - { - Interlocked.Exchange(ref _lock, null); - } - await _awaitedTask; } catch @@ -52,24 +38,44 @@ namespace Capnp.Util { SpinWait.SpinUntil(() => { - lock (safeLock) + Action? continuations; + do { - if (Volatile.Read(ref _outOrder) != sequence) - { - return false; - } + continuations = Interlocked.Exchange(ref _state, null); + continuations?.Invoke(); - Interlocked.Increment(ref _outOrder); + } while (continuations != null); - continuation(); - - return true; - } + return Interlocked.CompareExchange(ref _state, Capsule, null) == null; }); } } - public bool IsCompleted => Volatile.Read(ref _lock) == null || (_awaitedTask.IsCompleted && Volatile.Read(ref _inOrder) == 0); + public void OnCompleted(Action continuation) + { + SpinWait.SpinUntil(() => { + Action? cur, next; + cur = Volatile.Read(ref _state); + switch (cur) + { + case null: + next = continuation; + break; + + case Action capsule when capsule == Capsule: + continuation(); + return true; + + case Action action: + next = action + continuation; + break; + } + + return Interlocked.CompareExchange(ref _state, next, cur) == cur; + }); + } + + public bool IsCompleted => _awaitedTask.IsCompleted && _state == Capsule; public T GetResult() => _awaitedTask.GetAwaiter().GetResult(); @@ -78,7 +84,7 @@ namespace Capnp.Util public Task WrappedTask => _awaitedTask; } - internal static class StrictlyOrderedTaskExtensions + public static class StrictlyOrderedTaskExtensions { public static StrictlyOrderedAwaitTask EnforceAwaitOrder(this Task task) { From 8b88b5c5ddc13b18eddc36d4108135c75d93c93d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Wed, 15 Apr 2020 21:52:56 +0200 Subject: [PATCH 44/76] fixed deadlock + blocked thread detection --- Capnp.Net.Runtime.Tests/General.cs | 113 +++++++++++++++++- Capnp.Net.Runtime.Tests/LocalRpc.cs | 2 +- Capnp.Net.Runtime/Assembly.cs | 3 + Capnp.Net.Runtime/Rpc/TcpRpcClient.cs | 10 +- Capnp.Net.Runtime/Rpc/TcpRpcServer.cs | 13 +- .../Util/StrictlyOrderedAwaitTask.cs | 43 +++++-- Capnp.Net.Runtime/Util/ThreadExtensions.cs | 49 ++++++++ 7 files changed, 213 insertions(+), 20 deletions(-) create mode 100644 Capnp.Net.Runtime/Assembly.cs create mode 100644 Capnp.Net.Runtime/Util/ThreadExtensions.cs diff --git a/Capnp.Net.Runtime.Tests/General.cs b/Capnp.Net.Runtime.Tests/General.cs index 0b564f6..686033b 100644 --- a/Capnp.Net.Runtime.Tests/General.cs +++ b/Capnp.Net.Runtime.Tests/General.cs @@ -1,4 +1,5 @@ using Capnp.Rpc; +using Capnp.Util; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; @@ -11,7 +12,7 @@ using System.Threading.Tasks.Dataflow; namespace Capnp.Net.Runtime.Tests { [TestClass] - public class General + public class General: TestBase { [TestMethod] public void AwaitOrderTest() @@ -92,5 +93,115 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(t.IsCompleted); }; } + + [TestMethod] + public void SafeJoinCompletedThread() + { + var thread = new Thread(() => + { + }); + thread.Start(); + thread.SafeJoin(null, 1000); + } + + [TestMethod] + public void SafeJoinBusyThread() + { + var thread = new Thread(() => + { + try + { + while (true) ; + } + catch (ThreadInterruptedException) + { + Console.WriteLine("Interrupted"); + } + catch (ThreadAbortException) + { + Console.WriteLine("Aborted"); + } + }); + thread.Start(); + thread.SafeJoin(null, 1000); + } + + [TestMethod] + public void SafeJoinSleepingThread() + { + var thread = new Thread(() => + { + try + { + Thread.Sleep(Timeout.Infinite); + } + catch (ThreadInterruptedException) + { + Console.WriteLine("Interrupted"); + } + catch (ThreadAbortException) + { + Console.WriteLine("Aborted"); + } + }); + + thread.Start(); + thread.SafeJoin(null, 1000); + } + + [TestMethod] + public void SafeJoinDeadlockedThread() + { + var lk = new object(); + + lock (lk) + { + var thread = new Thread(() => + { + try + { + lock (lk) + { + } + } + catch (ThreadInterruptedException) + { + Console.WriteLine("Interrupted"); + } + catch (ThreadAbortException) + { + Console.WriteLine("Aborted"); + } + }); + + thread.Start(); + thread.SafeJoin(null, 1000); + } + } + + [TestMethod] + public void SafeJoinDefensiveThread() + { + var thread = new Thread(() => + { + for (; ; ) + { + try + { + Thread.Sleep(Timeout.Infinite); + } + catch (ThreadInterruptedException) + { + Console.WriteLine("Interrupted"); + } + catch (ThreadAbortException) + { + Console.WriteLine("Aborted"); + } + } + }); + thread.Start(); + thread.SafeJoin(null, 1000); + } } } diff --git a/Capnp.Net.Runtime.Tests/LocalRpc.cs b/Capnp.Net.Runtime.Tests/LocalRpc.cs index 7517cd2..f77746a 100644 --- a/Capnp.Net.Runtime.Tests/LocalRpc.cs +++ b/Capnp.Net.Runtime.Tests/LocalRpc.cs @@ -195,7 +195,7 @@ namespace Capnp.Net.Runtime.Tests } [TestMethod] - public void EagerRace2() + public void AwaitNoDeadlock() { for (int i = 0; i < 100; i++) { diff --git a/Capnp.Net.Runtime/Assembly.cs b/Capnp.Net.Runtime/Assembly.cs new file mode 100644 index 0000000..114f6be --- /dev/null +++ b/Capnp.Net.Runtime/Assembly.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Capnp.Net.Runtime.Tests")] diff --git a/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs b/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs index 55771ad..f52d702 100644 --- a/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs +++ b/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs @@ -1,4 +1,5 @@ using Capnp.FrameTracing; +using Capnp.Util; using Microsoft.Extensions.Logging; using System; using System.IO; @@ -92,6 +93,10 @@ namespace Capnp.Rpc _pump.Run(); } + catch (ThreadInterruptedException) + { + Logger.LogError($"{Thread.CurrentThread.Name} interrupted at {Environment.StackTrace}"); + } finally { State = ConnectionState.Down; @@ -186,10 +191,7 @@ namespace Capnp.Rpc Logger.LogError(e, "Failure disposing client"); } - if (_pumpThread != null && !_pumpThread.Join(500)) - { - Logger.LogError("Unable to join pump thread within timeout"); - } + _pumpThread?.SafeJoin(Logger); GC.SuppressFinalize(this); } diff --git a/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs b/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs index 14fb148..150ddd5 100644 --- a/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs +++ b/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs @@ -1,4 +1,5 @@ using Capnp.FrameTracing; +using Capnp.Util; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -60,6 +61,8 @@ namespace Capnp.Rpc class Connection: IConnection { + ILogger Logger { get; } = Logging.CreateLogger(); + readonly List _tracers = new List(); readonly TcpRpcServer _server; Stream _stream; @@ -95,6 +98,10 @@ namespace Capnp.Rpc Pump.Run(); } + catch (ThreadInterruptedException) + { + Logger.LogError($"{Thread.CurrentThread.Name} interrupted at {Environment.StackTrace}"); + } finally { OutboundEp.Dismiss(); @@ -199,6 +206,10 @@ namespace Capnp.Rpc // Listener was stopped. Maybe a little bit rude, but this is // our way of shutting down the acceptor thread. } + catch (ThreadInterruptedException) + { + Logger.LogError($"{Thread.CurrentThread.Name} interrupted at {Environment.StackTrace}"); + } catch (System.Exception exception) { // Any other exception might be due to some other problem. @@ -227,7 +238,7 @@ namespace Capnp.Rpc { connection.Client.Dispose(); connection.Pump?.Dispose(); - connection.PumpRunner?.Join(5000); + connection.PumpRunner?.SafeJoin(Logger); } _rpcEngine.BootstrapCap = null; diff --git a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs index 5cf1335..1565aa4 100644 --- a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs +++ b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs @@ -7,17 +7,21 @@ using System.Threading.Tasks; namespace Capnp.Util { - public class StrictlyOrderedAwaitTask: INotifyCompletion + internal class StrictlyOrderedAwaitTask: INotifyCompletion { - static readonly Action Capsule = () => throw new InvalidProgramException("Not invocable"); + class Cover { } + class Seal { } + + static readonly Cover s_cover = new Cover(); + static readonly Seal s_seal = new Seal(); readonly Task _awaitedTask; - Action? _state; + object? _state; public StrictlyOrderedAwaitTask(Task awaitedTask) { _awaitedTask = awaitedTask; - AwaitInternal(); + _state = s_cover; } public StrictlyOrderedAwaitTask GetAwaiter() @@ -41,41 +45,54 @@ namespace Capnp.Util Action? continuations; do { - continuations = Interlocked.Exchange(ref _state, null); + continuations = (Action?)Interlocked.Exchange(ref _state, null); continuations?.Invoke(); } while (continuations != null); - return Interlocked.CompareExchange(ref _state, Capsule, null) == null; + return Interlocked.CompareExchange(ref _state, s_seal, null) == null; }); } } public void OnCompleted(Action continuation) { + bool first = false; + SpinWait.SpinUntil(() => { - Action? cur, next; + object? cur, next; cur = Volatile.Read(ref _state); + first = false; switch (cur) { + case Cover cover: + next = continuation; + first = true; + break; + case null: next = continuation; break; - case Action capsule when capsule == Capsule: - continuation(); - return true; - case Action action: next = action + continuation; break; + + default: + continuation(); + return true; } return Interlocked.CompareExchange(ref _state, next, cur) == cur; }); + + if (first) + { + AwaitInternal(); + } } - public bool IsCompleted => _awaitedTask.IsCompleted && _state == Capsule; + public bool IsCompleted => _awaitedTask.IsCompleted && _state == s_seal; public T GetResult() => _awaitedTask.GetAwaiter().GetResult(); @@ -84,7 +101,7 @@ namespace Capnp.Util public Task WrappedTask => _awaitedTask; } - public static class StrictlyOrderedTaskExtensions + internal static class StrictlyOrderedTaskExtensions { public static StrictlyOrderedAwaitTask EnforceAwaitOrder(this Task task) { diff --git a/Capnp.Net.Runtime/Util/ThreadExtensions.cs b/Capnp.Net.Runtime/Util/ThreadExtensions.cs new file mode 100644 index 0000000..a53da32 --- /dev/null +++ b/Capnp.Net.Runtime/Util/ThreadExtensions.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Threading; + +namespace Capnp.Util +{ + internal static class ThreadExtensions + { + class ThreadExtensionsLoggingContext + { + public ILogger Logger { get; } = Logging.CreateLogger(); + } + + static Lazy LoggingContext = new Lazy( + () => new ThreadExtensionsLoggingContext(), + LazyThreadSafetyMode.PublicationOnly); + + public static void SafeJoin(this Thread thread, ILogger? logger = null, int timeout = 5000) + { + if (!thread.Join(timeout)) + { + logger ??= LoggingContext.Value.Logger; + + string name = thread.Name ?? thread.ManagedThreadId.ToString(); + + try + { + logger.LogError($"Unable to join thread {name}. Thread is in state {thread.ThreadState}."); + thread.Interrupt(); + if (!thread.Join(timeout / 10)) + { + logger.LogError($"Still unable to join thread {name} after Interrupt(). Thread is in state {thread.ThreadState}."); + thread.Abort(); + if (thread.Join(timeout / 10)) + { + logger.LogError($"Still unable to join thread {name} after Abort(). Thread is in state {thread.ThreadState}."); + } + } + } + catch + { + } + } + } + } +} From 5d0f24cdab2bd7924992fe669b4a06fd7fe4fb2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Wed, 15 Apr 2020 22:19:45 +0200 Subject: [PATCH 45/76] prevent false positives due to timeout --- Capnp.Net.Runtime.Tests/General.cs | 15 ++++++++++----- Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs | 2 +- Capnp.Net.Runtime.Tests/Testsuite.cs | 2 +- scripts/measure-coverage.ps1 | 4 ++-- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/General.cs b/Capnp.Net.Runtime.Tests/General.cs index 686033b..3ca548b 100644 --- a/Capnp.Net.Runtime.Tests/General.cs +++ b/Capnp.Net.Runtime.Tests/General.cs @@ -95,16 +95,18 @@ namespace Capnp.Net.Runtime.Tests } [TestMethod] + [TestCategory("Coverage")] public void SafeJoinCompletedThread() { var thread = new Thread(() => { }); thread.Start(); - thread.SafeJoin(null, 1000); + thread.SafeJoin(null, 200); } [TestMethod] + [TestCategory("Coverage")] public void SafeJoinBusyThread() { var thread = new Thread(() => @@ -123,10 +125,11 @@ namespace Capnp.Net.Runtime.Tests } }); thread.Start(); - thread.SafeJoin(null, 1000); + thread.SafeJoin(null, 5); } [TestMethod] + [TestCategory("Coverage")] public void SafeJoinSleepingThread() { var thread = new Thread(() => @@ -146,10 +149,11 @@ namespace Capnp.Net.Runtime.Tests }); thread.Start(); - thread.SafeJoin(null, 1000); + thread.SafeJoin(null, 5); } [TestMethod] + [TestCategory("Coverage")] public void SafeJoinDeadlockedThread() { var lk = new object(); @@ -175,11 +179,12 @@ namespace Capnp.Net.Runtime.Tests }); thread.Start(); - thread.SafeJoin(null, 1000); + thread.SafeJoin(null, 5); } } [TestMethod] + [TestCategory("Coverage")] public void SafeJoinDefensiveThread() { var thread = new Thread(() => @@ -201,7 +206,7 @@ namespace Capnp.Net.Runtime.Tests } }); thread.Start(); - thread.SafeJoin(null, 1000); + thread.SafeJoin(null, 5); } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index 3f55e24..e016ad5 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -263,7 +263,7 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(echoTask.Wait(MediumNonDbgTimeout)); using (var echo = echoTask.Result) { - var list = new Task[1000]; + var list = new Task[200]; for (uint i = 0; i < list.Length; i++) { list[i] = echo.GetCallSequence(i); diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs index 07719f5..c912b11 100644 --- a/Capnp.Net.Runtime.Tests/Testsuite.cs +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -795,7 +795,7 @@ namespace Capnp.Net.Runtime.Tests using (var callee = Proxy.Share(new TestTailCalleeImpl(new Counters()))) { var tasks = ParallelEnumerable - .Range(0, 1000) + .Range(0, 200) .Select(async i => { var r = await main.Foo(i, Proxy.Share(callee)); diff --git a/scripts/measure-coverage.ps1 b/scripts/measure-coverage.ps1 index 4a7dda5..d06dfdb 100644 --- a/scripts/measure-coverage.ps1 +++ b/scripts/measure-coverage.ps1 @@ -20,14 +20,14 @@ If(!(test-path $coverageReportDir)) } & $openCover -target:"$vsTestConsole" ` - -targetArgs:"/inIsolation $runtimeTests /TestCaseFilter:`"TestCategory=Coverage`" /Framework:.NETCoreApp,Version=v2.1" ` + -targetArgs:"/inIsolation $runtimeTests /TestCaseFilter:`"TestCategory=Coverage`" /Framework:.NETCoreApp,Version=v2.1 /logger:trx;LogFileName=runtime.trx" ` -filter:"+[Capnp.Net.Runtime]Capnp.*" ` -excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" ` -output:"$coverageOutput" ` -mergebyhash -register:user -oldStyle & $openCover -target:"$vsTestConsole" ` - -targetArgs:"/inIsolation $generatorTests" ` + -targetArgs:"/inIsolation $generatorTests /logger:trx;LogFileName=generator.trx" ` -filter:"+[CapnpC.CSharp.Generator]CapnpC.CSharp.Generator.* -[CapnpC.CSharp.Generator]CapnpC.CSharp.Generator.Schema.*" ` -excludebyattribute:"System.CodeDom.Compiler.GeneratedCodeAttribute" ` -output:"$coverageOutput" ` From af6dcec8f79586099f3e9f8f829a370aed1b1777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Thu, 16 Apr 2020 07:57:26 +0200 Subject: [PATCH 46/76] test & fix --- Capnp.Net.Runtime.Tests/DeserializationTests.cs | 4 ++++ Capnp.Net.Runtime.Tests/ImpatientTests.cs | 6 ++++++ Capnp.Net.Runtime.Tests/LocalRpc.cs | 17 +++++++++++++++++ Capnp.Net.Runtime/Capnp.Net.Runtime.csproj | 2 +- Capnp.Net.Runtime/DeserializerState.cs | 14 ++++++++++---- 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/DeserializationTests.cs b/Capnp.Net.Runtime.Tests/DeserializationTests.cs index e90269d..e42637d 100644 --- a/Capnp.Net.Runtime.Tests/DeserializationTests.cs +++ b/Capnp.Net.Runtime.Tests/DeserializationTests.cs @@ -842,12 +842,16 @@ namespace Capnp.Net.Runtime.Tests data[0] = p; Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); p.SetFarPointer(0, 0, false); + data[0] = p; Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); p.SetFarPointer(1, 0, false); + data[0] = p; Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); p.SetFarPointer(0, 1, false); + data[0] = p; Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); p.SetFarPointer(0, 0, true); + data[0] = p; Assert.ThrowsException(() => DeserializerState.CreateRoot(wf)); var data2 = new ulong[3]; diff --git a/Capnp.Net.Runtime.Tests/ImpatientTests.cs b/Capnp.Net.Runtime.Tests/ImpatientTests.cs index e32c89f..551c242 100644 --- a/Capnp.Net.Runtime.Tests/ImpatientTests.cs +++ b/Capnp.Net.Runtime.Tests/ImpatientTests.cs @@ -18,6 +18,12 @@ namespace Capnp.Net.Runtime.Tests { var impl = new TestInterfaceImpl2(); Assert.AreEqual(impl, await impl.Unwrap()); + using (var proxy = Proxy.Share(impl)) + using (var reso = ((Proxy)proxy).GetResolvedCapability()) + { + + Assert.AreEqual(((Proxy)proxy).ConsumedCap, ((Proxy)reso).ConsumedCap); + } Assert.IsNull(await default(ITestInterface).Unwrap()); var tcs = new TaskCompletionSource(); tcs.SetResult(null); diff --git a/Capnp.Net.Runtime.Tests/LocalRpc.cs b/Capnp.Net.Runtime.Tests/LocalRpc.cs index f77746a..a618b84 100644 --- a/Capnp.Net.Runtime.Tests/LocalRpc.cs +++ b/Capnp.Net.Runtime.Tests/LocalRpc.cs @@ -226,5 +226,22 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(Task.WaitAll(new Task[] { w1, w2 }, MediumNonDbgTimeout)); } } + + [TestMethod] + public void DisposedProxy() + { + var b = new BareProxy(); + Assert.ThrowsException(() => b.Bind(null)); + var impl = new TestInterfaceImpl2(); + var proxy = Proxy.Share(impl); + var p = (Proxy)proxy; + Assert.ThrowsException(() => p.Bind(p.ConsumedCap)); + Assert.IsFalse(p.IsDisposed); + proxy.Dispose(); + Assert.IsTrue(p.IsDisposed); + Assert.ThrowsException(() => p.ConsumedCap); + var t = proxy.Foo(123, true); + Assert.IsTrue(Assert.ThrowsExceptionAsync(() => t).Wait(MediumNonDbgTimeout)); + } } } diff --git a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj index 6f81750..b7675b9 100644 --- a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj +++ b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj @@ -29,7 +29,7 @@ - DebugFinalizers + diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs index c5e7b71..1aee28e 100644 --- a/Capnp.Net.Runtime/DeserializerState.cs +++ b/Capnp.Net.Runtime/DeserializerState.cs @@ -329,10 +329,13 @@ namespace Capnp case PointerKind.Far: + if (pointer.TargetSegmentIndex >= Segments.Count) + throw new DeserializationException("Error decoding pointer: Invalid target segment index"); + + CurrentSegmentIndex = pointer.TargetSegmentIndex; + if (pointer.IsDoubleFar) { - CurrentSegmentIndex = pointer.TargetSegmentIndex; - if (pointer.LandingPadOffset >= CurrentSegment.Length - 1) throw new DeserializationException("Error decoding double-far pointer: exceeds segment bounds"); @@ -353,9 +356,12 @@ namespace Capnp } else { - CurrentSegmentIndex = pointer.TargetSegmentIndex; Offset = 0; offset = pointer.LandingPadOffset; + + if (pointer.LandingPadOffset >= CurrentSegment.Length) + throw new DeserializationException("Error decoding pointer: exceeds segment bounds"); + pointer = CurrentSegment[pointer.LandingPadOffset]; } continue; @@ -701,7 +707,7 @@ namespace Capnp { foreach (var cap in Caps) { - cap?.Release(); + cap.Release(); } Caps = null; From d2c2f8d65791615832e017ab98b54178265ddf9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Thu, 16 Apr 2020 22:20:42 +0200 Subject: [PATCH 47/76] test & fix --- Capnp.Net.Runtime.Tests/Dtbdct.cs | 6 +++ Capnp.Net.Runtime.Tests/Interception.cs | 38 +++++++++++++++++++ Capnp.Net.Runtime.Tests/LocalRpc.cs | 6 +++ Capnp.Net.Runtime.Tests/Testsuite.cs | 18 +++++++++ Capnp.Net.Runtime/FramePump.cs | 8 +++- .../Rpc/Interception/CallContext.cs | 4 +- 6 files changed, 76 insertions(+), 4 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/Dtbdct.cs b/Capnp.Net.Runtime.Tests/Dtbdct.cs index d67860d..4a4c9c6 100644 --- a/Capnp.Net.Runtime.Tests/Dtbdct.cs +++ b/Capnp.Net.Runtime.Tests/Dtbdct.cs @@ -188,5 +188,11 @@ namespace Capnp.Net.Runtime.Tests { NewDtbdctTestbed().RunTest(Testsuite.CallAfterFinish2); } + + [TestMethod] + public void LegacyAccess() + { + NewDtbdctTestbed().RunTest(Testsuite.LegacyAccess); + } } } diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index 4d86f85..c1c7e50 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -395,6 +395,44 @@ namespace Capnp.Net.Runtime.Tests } } + [TestMethod] + public void InterceptClientSideModifyPipelinedCall() + { + var policy = new MyPolicy("a"); + + (var server, var client) = SetupClientServerPair(); + + using (server) + using (client) + { + var counters = new Counters(); + var impl = new TestMoreStuffImpl(counters); + server.Main = impl; + using (var main = policy.Attach(client.GetMain())) + { + var req = main.GetNull().Eager().GetCallSequence(0); + Assert.IsTrue(policy.Calls.TryReceive(out var ccGetNull)); + Assert.IsTrue(policy.Calls.TryReceive(out var ccGetCallSequence)); + + ccGetNull.ForwardToBob(); + + Assert.IsTrue(policy.Returns.ReceiveAsync().Wait(MediumNonDbgTimeout)); + + ccGetNull.ReturnToAlice(); + + ccGetCallSequence.Bob = Proxy.Share(impl); + ccGetCallSequence.ForwardToBob(); + + Assert.IsTrue(policy.Returns.ReceiveAsync().Wait(MediumNonDbgTimeout)); + + ccGetCallSequence.ReturnToAlice(); + + Assert.IsTrue(req.IsCompleted && !req.IsFaulted && !req.IsCanceled); + Assert.AreEqual(0u, req.Result); + } + } + } + [TestMethod] public void InterfaceAndMethodId() { diff --git a/Capnp.Net.Runtime.Tests/LocalRpc.cs b/Capnp.Net.Runtime.Tests/LocalRpc.cs index a618b84..36ab7e5 100644 --- a/Capnp.Net.Runtime.Tests/LocalRpc.cs +++ b/Capnp.Net.Runtime.Tests/LocalRpc.cs @@ -140,6 +140,12 @@ namespace Capnp.Net.Runtime.Tests NewLocalTestbed().RunTest(Testsuite.Ownership3); } + [TestMethod] + public void LegacyAccess() + { + NewLocalTestbed().RunTest(Testsuite.LegacyAccess); + } + [TestMethod] public void EagerRace() { diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs index c912b11..29dbfd1 100644 --- a/Capnp.Net.Runtime.Tests/Testsuite.cs +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -855,5 +855,23 @@ namespace Capnp.Net.Runtime.Tests } } } + + public static void LegacyAccess(ITestbed testbed) + { + var impl = new TestMoreStuffImpl(new Counters()); + using (var main = testbed.ConnectMain(impl)) + { + var task = main.Echo(new TestCallOrderImpl()); + var answer = Impatient.TryGetAnswer(task); + Assert.IsNotNull(answer); + var cap = answer.Access(new MemberAccessPath(0)); + using (var proxy = (ITestCallOrder)CapabilityReflection.CreateProxy(cap)) + { + var seq = proxy.GetCallSequence(0); + testbed.MustComplete(seq); + Assert.AreEqual(0u, seq.Result); + } + } + } } } diff --git a/Capnp.Net.Runtime/FramePump.cs b/Capnp.Net.Runtime/FramePump.cs index e2ecabc..dad87c3 100644 --- a/Capnp.Net.Runtime/FramePump.cs +++ b/Capnp.Net.Runtime/FramePump.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.IO; +using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; using System.Threading; @@ -160,9 +161,12 @@ namespace Capnp } } } - catch (EndOfStreamException) + catch (Exception exception) when (exception is EndOfStreamException || + exception is IOException ioex && + ioex.InnerException is SocketException sockex && + sockex.SocketErrorCode == SocketError.Interrupted) { - Logger.LogWarning("Encountered End of Stream"); + Logger.LogInformation("Encountered end of stream"); } catch (InvalidDataException e) { diff --git a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs index 3911fae..1caf2b6 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs @@ -27,13 +27,13 @@ namespace Capnp.Rpc.Interception public ConsumedCapability Access(MemberAccessPath access) { - return new LocalAnswerCapability(_futureResult.Task, access); + return _callContext._censorCapability.Policy.Attach(new LocalAnswerCapability(_futureResult.Task, access)); } public ConsumedCapability Access(MemberAccessPath _, Task task) { var proxyTask = task.AsProxyTask(); - return new LocalAnswerCapability(proxyTask); + return _callContext._censorCapability.Policy.Attach(new LocalAnswerCapability(proxyTask)); } public void Dispose() From 69cb5010c5a64d79f7b1f791cf5ae724b7c8dc07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Fri, 17 Apr 2020 07:56:39 +0200 Subject: [PATCH 48/76] test & fix --- .../CapabilityReflectionTests.cs | 30 ++++++++++++++++ Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs | 34 +++++++++++++++++-- Capnp.Net.Runtime.Tests/SerializationTests.cs | 8 ++--- Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 5 ++- Capnp.Net.Runtime/Rpc/RpcEngine.cs | 5 ++- 5 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 Capnp.Net.Runtime.Tests/CapabilityReflectionTests.cs diff --git a/Capnp.Net.Runtime.Tests/CapabilityReflectionTests.cs b/Capnp.Net.Runtime.Tests/CapabilityReflectionTests.cs new file mode 100644 index 0000000..ccc529d --- /dev/null +++ b/Capnp.Net.Runtime.Tests/CapabilityReflectionTests.cs @@ -0,0 +1,30 @@ +using Capnp.Rpc; +using Capnproto_test.Capnp.Test; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Capnp.Net.Runtime.Tests +{ + [TestClass] + [TestCategory("Coverage")] + public class CapabilityReflectionTests + { + [TestMethod] + public void ValidateCapabilityInterface() + { + Assert.ThrowsException(() => CapabilityReflection.ValidateCapabilityInterface(null)); + CapabilityReflection.ValidateCapabilityInterface(typeof(ITestInterface)); + Assert.ThrowsException(() => CapabilityReflection.ValidateCapabilityInterface(typeof(CapabilityReflectionTests))); + } + + [TestMethod] + public void IsValidCapabilityInterface() + { + Assert.ThrowsException(() => CapabilityReflection.IsValidCapabilityInterface(null)); + Assert.IsTrue(CapabilityReflection.IsValidCapabilityInterface(typeof(ITestInterface))); + Assert.IsFalse(CapabilityReflection.IsValidCapabilityInterface(typeof(CapabilityReflectionTests))); + } + } +} diff --git a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs index 0e61fa5..5ec303d 100644 --- a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs +++ b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs @@ -22,14 +22,16 @@ namespace Capnp.Net.Runtime.Tests { readonly FramePump _fromEnginePump; readonly BinaryReader _reader; + readonly FrameTracing.RpcFrameTracer _tracer; public bool Dismissed { get; private set; } public MemStreamEndpoint() { var pipe = new Pipe(); + _tracer = new FrameTracing.RpcFrameTracer(Console.Out, false); _fromEnginePump = new FramePump(pipe.Writer.AsStream()); - _fromEnginePump.AttachTracer(new FrameTracing.RpcFrameTracer(Console.Out, false)); + _fromEnginePump.AttachTracer(_tracer); _reader = new BinaryReader(pipe.Reader.AsStream()); } @@ -45,7 +47,9 @@ namespace Capnp.Net.Runtime.Tests public WireFrame ReadNextFrame() { - return _reader.ReadWireFrame(); + var frame = _reader.ReadWireFrame(); + _tracer.TraceFrame(FrameTracing.FrameDirection.Rx, frame); + return frame; } } @@ -1252,5 +1256,31 @@ namespace Capnp.Net.Runtime.Tests Assert.IsFalse(tester.IsDismissed); } + + [TestMethod] + public void ReturnToWrongSide1() + { + var tester = new RpcEngineTester(); + + var cap = tester.RealEnd.QueryMain(); + var proxy = new BareProxy(cap); + Assert.IsFalse(proxy.WhenResolved.IsCompleted); + uint id = 0; + + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Bootstrap, _.which); + id = _.Bootstrap.QuestionId; + }); + tester.Send(_ => { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.ResultsSentElsewhere; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Finish, _.which); + }); + Assert.IsTrue(proxy.WhenResolved.IsCompleted); + Assert.IsTrue(proxy.WhenResolved.IsFaulted); + tester.ExpectAbort(); + } } } diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs index 57874ef..ad40dc2 100644 --- a/Capnp.Net.Runtime.Tests/SerializationTests.cs +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -723,7 +723,7 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void DynamicSerializerStateSBytes() { - var expected = new sbyte[] { 1, 2, 3 }; + var expected = new List { 1, 2, 3 }; var b = MessageBuilder.Create(); var dss = b.CreateObject(); @@ -735,7 +735,7 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void DynamicSerializerStateShorts() { - var expected = new short[] { 1, 2, 3 }; + var expected = new List { 1, 2, 3 }; var b = MessageBuilder.Create(); var dss = b.CreateObject(); @@ -759,7 +759,7 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void DynamicSerializerStateInts() { - var expected = new int[] { 1, 2, 3 }; + var expected = new List { 1, 2, 3 }; var b = MessageBuilder.Create(); var dss = b.CreateObject(); @@ -783,7 +783,7 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void DynamicSerializerStateLongs() { - var expected = new long[] { 1, 2, 3 }; + var expected = new List { 1, 2, 3 }; var b = MessageBuilder.Create(); var dss = b.CreateObject(); diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index f2e5917..97be61a 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -127,6 +127,7 @@ namespace Capnp.Rpc } const string ReturnDespiteTailCallMessage = "Peer sent actual results despite the question was sent as tail call. This was not expected and is a protocol error."; + const string UnexpectedTailCallReturnMessage = "Peer sent the results of this questions somewhere else. This was not expected and is a protocol error."; internal void OnReturn(DeserializerState results) { @@ -138,6 +139,7 @@ namespace Capnp.Rpc if (StateFlags.HasFlag(State.TailCall)) { _tcs.TrySetException(new RpcException(ReturnDespiteTailCallMessage)); + throw new RpcProtocolErrorException(ReturnDespiteTailCallMessage); } else { @@ -157,7 +159,8 @@ namespace Capnp.Rpc if (!StateFlags.HasFlag(State.TailCall)) { - _tcs.TrySetException(new RpcException("Peer sent the results of this questions somewhere else. This was not expected and is a protocol error.")); + _tcs.TrySetException(new RpcException(UnexpectedTailCallReturnMessage)); + throw new RpcProtocolErrorException(UnexpectedTailCallReturnMessage); } else { diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 83ee8f7..60cc0ef 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -238,8 +238,7 @@ namespace Capnp.Rpc lock (_reentrancyBlocker) { if (!_exportTable.TryGetValue(preliminaryId, out var existing) || - existing.Cap != preliminaryCap || - existing.RefCount == 0) + existing.Cap != preliminaryCap) { // Resolved too late. Capability was already released. return; @@ -579,7 +578,7 @@ namespace Capnp.Rpc { foreach (var cap in inParams.Caps) { - cap?.Release(); + cap.Release(); } pendingAnswer = new PendingAnswer( From aac32335b6afc597bc0af423af0414aca906594e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Fri, 17 Apr 2020 21:44:26 +0200 Subject: [PATCH 49/76] test & fix --- Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs | 65 +++++++++++++++++++++ Capnp.Net.Runtime.Tests/Interception.cs | 2 +- Capnp.Net.Runtime.Tests/Util/TestBase.cs | 8 ++- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs index 5ec303d..1cace55 100644 --- a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs +++ b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs @@ -1282,5 +1282,70 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(proxy.WhenResolved.IsFaulted); tester.ExpectAbort(); } + + [TestMethod] + public void ReturnToWrongSide2() + { + var tester = new RpcEngineTester(); + + tester.Engine.Main = new TestTailCallerImpl(new Counters()); + + tester.Send(_ => { + _.which = Message.WHICH.Bootstrap; + _.Bootstrap.QuestionId = 0; + }); + uint bootstrapId = 0; + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.Results, _.Return.which); + Assert.AreEqual(CapDescriptor.WHICH.SenderHosted, _.Return.Results.CapTable[0].which); + bootstrapId = _.Return.Results.CapTable[0].SenderHosted; + }); + tester.Send(_ => + { + _.which = Message.WHICH.Call; + _.Call.Target.which = MessageTarget.WHICH.ImportedCap; + _.Call.Target.ImportedCap = 0; + _.Call.SendResultsTo.which = Call.sendResultsTo.WHICH.Caller; + _.Call.InterfaceId = new TestTailCaller_Skeleton().InterfaceId; + _.Call.MethodId = 0; + _.Call.QuestionId = 1; + var a = _.Call.Params.Content.Rewrap(); + a.Callee = new TestTailCalleeImpl(new Counters()); + _.Call.Params.CapTable.Init(1); + _.Call.Params.CapTable[0].which = CapDescriptor.WHICH.SenderHosted; + _.Call.Params.CapTable[0].SenderHosted = 0; + }); + uint q = 0; + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Call, _.which); + Assert.AreEqual(Call.sendResultsTo.WHICH.Yourself, _.Call.SendResultsTo.which); + q = _.Call.QuestionId; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Release, _.which); + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Return, _.which); + Assert.AreEqual(Return.WHICH.TakeFromOtherQuestion, _.Return.which); + }); + tester.Send(_ => + { + _.which = Message.WHICH.Return; + _.Return.which = Return.WHICH.Results; + _.Return.AnswerId = q; + var wr = _.Return.Results.Content.Rewrap(); + wr.C = new TestCallOrderImpl(); + wr.I = 0; + wr.T = "test"; + _.Return.Results.CapTable.Init(1); + _.Return.Results.CapTable[0].which = CapDescriptor.WHICH.SenderHosted; + _.Return.Results.CapTable[0].SenderHosted = 1; + }); + tester.Recv(_ => { + Assert.AreEqual(Message.WHICH.Finish, _.which); + }); + tester.ExpectAbort(); + } } } diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index c1c7e50..49aa040 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -400,7 +400,7 @@ namespace Capnp.Net.Runtime.Tests { var policy = new MyPolicy("a"); - (var server, var client) = SetupClientServerPair(); + (var server, var client) = SetupClientServerPair(true); using (server) using (client) diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 6b089b5..c44df31 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -345,10 +345,12 @@ namespace Capnp.Net.Runtime.Tests protected ILogger Logger { get; set; } - protected static TcpRpcClient SetupClient() + protected static TcpRpcClient SetupClient(bool withTracer = false) { var client = new TcpRpcClient(); client.AddBuffering(); + if (withTracer) + client.AttachTracer(new FrameTracing.RpcFrameTracer(Console.Out, false)); client.Connect("localhost", TcpPort); return client; } @@ -379,10 +381,10 @@ namespace Capnp.Net.Runtime.Tests } } - protected static (TcpRpcServer, TcpRpcClient) SetupClientServerPair() + protected static (TcpRpcServer, TcpRpcClient) SetupClientServerPair(bool withClientTracer = false) { var server = SetupServer(); - var client = SetupClient(); + var client = SetupClient(withClientTracer); return (server, client); } From 75823c43b98f85e4ee405da0e65cc14accab3ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 18 Apr 2020 12:40:51 +0200 Subject: [PATCH 50/76] test & fix --- Capnp.Net.Runtime.Tests/Interception.cs | 2 +- Capnp.Net.Runtime.Tests/Mock/test.cs | 188 +++++++++++------- .../Embedded Resources/test.cs | 188 +++++++++++------- CapnpC.CSharp.Generator/CodeGen/GenNames.cs | 20 +- .../CodeGen/GeneratorOptions.cs | 3 - .../CodeGen/InterfaceSnippetGen.cs | 14 +- 6 files changed, 235 insertions(+), 180 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index 49aa040..76421da 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -169,7 +169,7 @@ namespace Capnp.Net.Runtime.Tests var rx = policy.Returns.ReceiveAsync(); // Racing against Bob's answer - Assert.IsTrue(cc.State == InterceptionState.ForwardedToBob || rx.IsCompleted); + Assert.IsTrue(cc.State == InterceptionState.ForwardedToBob || cc.State == InterceptionState.ReturnedFromBob); Assert.IsTrue(rx.Wait(MediumNonDbgTimeout)); var rr = new Capnproto_test.Capnp.Test.TestInterface.Result_Foo.READER(cc.OutArgs); diff --git a/Capnp.Net.Runtime.Tests/Mock/test.cs b/Capnp.Net.Runtime.Tests/Mock/test.cs index 51b4975..1e6dacb 100644 --- a/Capnp.Net.Runtime.Tests/Mock/test.cs +++ b/Capnp.Net.Runtime.Tests/Mock/test.cs @@ -8609,6 +8609,7 @@ namespace Capnproto_test.Capnp.Test Task Call(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8839ed86c9794287UL)] public class DeepNestInterface_Proxy : Proxy, IDeepNestInterface where TQuux : class { public async Task Call(CancellationToken cancellationToken_ = default) @@ -8625,6 +8626,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8839ed86c9794287UL)] public class DeepNestInterface_Skeleton : Skeleton> where TQuux : class { public DeepNestInterface_Skeleton() @@ -8746,6 +8748,7 @@ namespace Capnproto_test.Capnp.Test Task<(TQux, Capnproto_test.Capnp.Test.TestGenerics)> Call(Capnproto_test.Capnp.Test.TestGenerics.Inner2 arg_, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc9e749e8dd54da5cUL)] public class Interface_Proxy : Proxy, IInterface where TQux : class { public Task<(TQux, Capnproto_test.Capnp.Test.TestGenerics)> Call(Capnproto_test.Capnp.Test.TestGenerics.Inner2 arg_, CancellationToken cancellationToken_ = default) @@ -8765,6 +8768,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc9e749e8dd54da5cUL)] public class Interface_Skeleton : Skeleton> where TQux : class { public Interface_Skeleton() @@ -9128,18 +9132,19 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8b9717a3f8d85a9aUL), Proxy(typeof(TestImplicitMethodParams_Proxy)), Skeleton(typeof(TestImplicitMethodParams_Skeleton))] public interface ITestImplicitMethodParams : IDisposable { - Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) + Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class; } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8b9717a3f8d85a9aUL)] public class TestImplicitMethodParams_Proxy : Proxy, ITestImplicitMethodParams { - public Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) + public Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class { var in_ = SerializerState.CreateForRpc.WRITER>(); var arg_ = new Capnproto_test.Capnp.Test.TestImplicitMethodParams.Params_Call() - { Foo = Foo, Bar = Bar }; + { Foo = foo, Bar = bar }; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(10058534285777328794UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -9154,6 +9159,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8b9717a3f8d85a9aUL)] public class TestImplicitMethodParams_Skeleton : Skeleton { public TestImplicitMethodParams_Skeleton() @@ -9261,18 +9267,19 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdf9ccdeb81a704c9UL), Proxy(typeof(TestImplicitMethodParamsInGeneric_Proxy<>)), Skeleton(typeof(TestImplicitMethodParamsInGeneric_Skeleton<>))] public interface ITestImplicitMethodParamsInGeneric : IDisposable where TV : class { - Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) + Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class; } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdf9ccdeb81a704c9UL)] public class TestImplicitMethodParamsInGeneric_Proxy : Proxy, ITestImplicitMethodParamsInGeneric where TV : class { - public Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) + public Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class { var in_ = SerializerState.CreateForRpc.Params_Call.WRITER>(); var arg_ = new Capnproto_test.Capnp.Test.TestImplicitMethodParamsInGeneric.Params_Call() - { Foo = Foo, Bar = Bar }; + { Foo = foo, Bar = bar }; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(16112979978201007305UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -9287,6 +9294,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdf9ccdeb81a704c9UL)] public class TestImplicitMethodParamsInGeneric_Skeleton : Skeleton> where TV : class { public TestImplicitMethodParamsInGeneric_Skeleton() @@ -10824,18 +10832,19 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x88eb12a0e0af92b2UL), Proxy(typeof(TestInterface_Proxy)), Skeleton(typeof(TestInterface_Skeleton))] public interface ITestInterface : IDisposable { - Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default); + Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default); Task Bar(CancellationToken cancellationToken_ = default); - Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default); + Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x88eb12a0e0af92b2UL)] public class TestInterface_Proxy : Proxy, ITestInterface { - public async Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default) + public async Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() - { I = I, J = J }; + { I = i, J = j }; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -10857,11 +10866,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) + public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() - { S = S }; + { S = s }; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -10871,6 +10880,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x88eb12a0e0af92b2UL)] public class TestInterface_Skeleton : Skeleton { public TestInterface_Skeleton() @@ -11259,6 +11269,7 @@ namespace Capnproto_test.Capnp.Test Task Grault(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe4e9bac98670b748UL)] public class TestExtends_Proxy : Proxy, ITestExtends { public async Task Qux(CancellationToken cancellationToken_ = default) @@ -11298,11 +11309,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default) + public async Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() - { I = I, J = J }; + { I = i, J = j }; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -11324,11 +11335,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) + public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() - { S = S }; + { S = s }; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -11338,6 +11349,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe4e9bac98670b748UL)] public class TestExtends_Skeleton : Skeleton { public TestExtends_Skeleton() @@ -11570,6 +11582,7 @@ namespace Capnproto_test.Capnp.Test { } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x98d7e0ef61488783UL)] public class TestExtends2_Proxy : Proxy, ITestExtends2 { public async Task Qux(CancellationToken cancellationToken_ = default) @@ -11609,11 +11622,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default) + public async Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() - { I = I, J = J }; + { I = i, J = j }; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -11635,11 +11648,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) + public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() - { S = S }; + { S = s }; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -11649,6 +11662,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x98d7e0ef61488783UL)] public class TestExtends2_Skeleton : Skeleton { public TestExtends2_Skeleton() @@ -11662,18 +11676,19 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa5a404caa61d4cd0UL), Proxy(typeof(TestPipeline_Proxy)), Skeleton(typeof(TestPipeline_Skeleton))] public interface ITestPipeline : IDisposable { - Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint N, Capnproto_test.Capnp.Test.ITestInterface InCap, CancellationToken cancellationToken_ = default); - Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface Cap, object Obj, IReadOnlyList List, CancellationToken cancellationToken_ = default); - Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint N, BareProxy InCap, CancellationToken cancellationToken_ = default); + Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint n, Capnproto_test.Capnp.Test.ITestInterface inCap, CancellationToken cancellationToken_ = default); + Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_ = default); + Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint n, BareProxy inCap, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa5a404caa61d4cd0UL)] public class TestPipeline_Proxy : Proxy, ITestPipeline { - public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint N, Capnproto_test.Capnp.Test.ITestInterface InCap, CancellationToken cancellationToken_ = default) + public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint n, Capnproto_test.Capnp.Test.ITestInterface inCap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_GetCap() - { N = N, InCap = InCap }; + { N = n, InCap = inCap }; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(11935670180855499984UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -11687,11 +11702,11 @@ namespace Capnproto_test.Capnp.Test ); } - public async Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface Cap, object Obj, IReadOnlyList List, CancellationToken cancellationToken_ = default) + public async Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_TestPointers() - { Cap = Cap, Obj = Obj, List = List }; + { Cap = cap, Obj = obj, List = list }; arg_?.serialize(in_); using (var d_ = await Call(11935670180855499984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -11700,11 +11715,11 @@ namespace Capnproto_test.Capnp.Test } } - public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint N, BareProxy InCap, CancellationToken cancellationToken_ = default) + public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint n, BareProxy inCap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_GetAnyCap() - { N = N, InCap = InCap }; + { N = n, InCap = inCap }; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(11935670180855499984UL, 2, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -11719,6 +11734,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa5a404caa61d4cd0UL)] public class TestPipeline_Skeleton : Skeleton { public TestPipeline_Skeleton() @@ -12334,16 +12350,17 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa0e77035bdff0051UL), Proxy(typeof(TestCallOrder_Proxy)), Skeleton(typeof(TestCallOrder_Skeleton))] public interface ITestCallOrder : IDisposable { - Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default); + Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa0e77035bdff0051UL)] public class TestCallOrder_Proxy : Proxy, ITestCallOrder { - public async Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default) + public async Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestCallOrder.Params_GetCallSequence() - { Expected = Expected }; + { Expected = expected }; arg_?.serialize(in_); using (var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -12353,6 +12370,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa0e77035bdff0051UL)] public class TestCallOrder_Skeleton : Skeleton { public TestCallOrder_Skeleton() @@ -12505,16 +12523,17 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddd699207eb8e23bUL), Proxy(typeof(TestTailCallee_Proxy)), Skeleton(typeof(TestTailCallee_Skeleton))] public interface ITestTailCallee : IDisposable { - Task Foo(int I, string T, CancellationToken cancellationToken_ = default); + Task Foo(int i, string t, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddd699207eb8e23bUL)] public class TestTailCallee_Proxy : Proxy, ITestTailCallee { - public Task Foo(int I, string T, CancellationToken cancellationToken_ = default) + public Task Foo(int i, string t, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestTailCallee.Params_Foo() - { I = I, T = T }; + { I = i, T = t }; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15985132292242203195UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -12529,6 +12548,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddd699207eb8e23bUL)] public class TestTailCallee_Skeleton : Skeleton { public TestTailCallee_Skeleton() @@ -12725,16 +12745,17 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x870bf40110ce3035UL), Proxy(typeof(TestTailCaller_Proxy)), Skeleton(typeof(TestTailCaller_Skeleton))] public interface ITestTailCaller : IDisposable { - Task Foo(int I, Capnproto_test.Capnp.Test.ITestTailCallee Callee, CancellationToken cancellationToken_ = default); + Task Foo(int i, Capnproto_test.Capnp.Test.ITestTailCallee callee, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x870bf40110ce3035UL)] public class TestTailCaller_Proxy : Proxy, ITestTailCaller { - public Task Foo(int I, Capnproto_test.Capnp.Test.ITestTailCallee Callee, CancellationToken cancellationToken_ = default) + public Task Foo(int i, Capnproto_test.Capnp.Test.ITestTailCallee callee, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestTailCaller.Params_Foo() - { I = I, Callee = Callee }; + { I = i, Callee = callee }; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(9731139705278181429UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -12749,6 +12770,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x870bf40110ce3035UL)] public class TestTailCaller_Skeleton : Skeleton { public TestTailCaller_Skeleton() @@ -12857,10 +12879,12 @@ namespace Capnproto_test.Capnp.Test { } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa38e5efe41e53a15UL)] public class TestHandle_Proxy : Proxy, ITestHandle { } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa38e5efe41e53a15UL)] public class TestHandle_Skeleton : Skeleton { public TestHandle_Skeleton() @@ -12874,28 +12898,29 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddc70bf9784133cfUL), Proxy(typeof(TestMoreStuff_Proxy)), Skeleton(typeof(TestMoreStuff_Skeleton))] public interface ITestMoreStuff : Capnproto_test.Capnp.Test.ITestCallOrder { - Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); - Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); - Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); - Task Hold(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); + Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); + Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); + Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); + Task Hold(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); Task CallHeld(CancellationToken cancellationToken_ = default); Task GetHeld(CancellationToken cancellationToken_ = default); - Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder Cap, CancellationToken cancellationToken_ = default); - Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); - Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default); + Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder cap, CancellationToken cancellationToken_ = default); + Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); + Task<(string, string)> MethodWithDefaults(string a, uint b, string c, CancellationToken cancellationToken_ = default); Task GetHandle(CancellationToken cancellationToken_ = default); Task GetNull(CancellationToken cancellationToken_ = default); Task GetEnormousString(CancellationToken cancellationToken_ = default); - Task MethodWithNullDefault(string A, Capnproto_test.Capnp.Test.ITestInterface B, CancellationToken cancellationToken_ = default); + Task MethodWithNullDefault(string a, Capnproto_test.Capnp.Test.ITestInterface b, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddc70bf9784133cfUL)] public class TestMoreStuff_Proxy : Proxy, ITestMoreStuff { - public async Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) + public async Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_CallFoo() - { Cap = Cap }; + { Cap = cap }; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -12904,11 +12929,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) + public async Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_CallFooWhenResolved() - { Cap = Cap }; + { Cap = cap }; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -12917,11 +12942,11 @@ namespace Capnproto_test.Capnp.Test } } - public Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) + public Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_NeverReturn() - { Cap = Cap }; + { Cap = cap }; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 2, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -12935,11 +12960,11 @@ namespace Capnproto_test.Capnp.Test ); } - public async Task Hold(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) + public async Task Hold(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_Hold() - { Cap = Cap }; + { Cap = cap }; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 3, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -12979,11 +13004,11 @@ namespace Capnproto_test.Capnp.Test ); } - public Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder Cap, CancellationToken cancellationToken_ = default) + public Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_Echo() - { Cap = Cap }; + { Cap = cap }; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 6, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -12997,11 +13022,11 @@ namespace Capnproto_test.Capnp.Test ); } - public async Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) + public async Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_ExpectCancel() - { Cap = Cap }; + { Cap = cap }; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 7, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -13010,11 +13035,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default) + public async Task<(string, string)> MethodWithDefaults(string a, uint b, string c, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_MethodWithDefaults() - { A = A, B = B, C = C }; + { A = a, B = b, C = c }; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 8, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -13072,11 +13097,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task MethodWithNullDefault(string A, Capnproto_test.Capnp.Test.ITestInterface B, CancellationToken cancellationToken_ = default) + public async Task MethodWithNullDefault(string a, Capnproto_test.Capnp.Test.ITestInterface b, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_MethodWithNullDefault() - { A = A, B = B }; + { A = a, B = b }; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 12, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -13085,11 +13110,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default) + public async Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestCallOrder.Params_GetCallSequence() - { Expected = Expected }; + { Expected = expected }; arg_?.serialize(in_); using (var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -13099,6 +13124,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddc70bf9784133cfUL)] public class TestMoreStuff_Skeleton : Skeleton { public TestMoreStuff_Skeleton() @@ -14816,12 +14842,13 @@ namespace Capnproto_test.Capnp.Test public interface ITestMembrane : IDisposable { Task MakeThing(CancellationToken cancellationToken_ = default); - Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default); - Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default); - Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, CancellationToken cancellationToken_ = default); + Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default); + Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default); + Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, CancellationToken cancellationToken_ = default); Task WaitForever(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc07d8dcd80a69c0cUL)] public class TestMembrane_Proxy : Proxy, ITestMembrane { public Task MakeThing(CancellationToken cancellationToken_ = default) @@ -14842,11 +14869,11 @@ namespace Capnproto_test.Capnp.Test ); } - public async Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default) + public async Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_CallPassThrough() - { Thing = Thing, TailCall = TailCall }; + { Thing = thing, TailCall = tailCall }; arg_?.serialize(in_); using (var d_ = await Call(13870398341137210380UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -14855,11 +14882,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default) + public async Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_CallIntercept() - { Thing = Thing, TailCall = TailCall }; + { Thing = thing, TailCall = tailCall }; arg_?.serialize(in_); using (var d_ = await Call(13870398341137210380UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -14868,11 +14895,11 @@ namespace Capnproto_test.Capnp.Test } } - public Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, CancellationToken cancellationToken_ = default) + public Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_Loopback() - { Thing = Thing }; + { Thing = thing }; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(13870398341137210380UL, 3, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -14900,6 +14927,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc07d8dcd80a69c0cUL)] public class TestMembrane_Skeleton : Skeleton { public TestMembrane_Skeleton() @@ -14993,6 +15021,7 @@ namespace Capnproto_test.Capnp.Test Task Intercept(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9352e4e41f173917UL)] public class Thing_Proxy : Proxy, IThing { public async Task PassThrough(CancellationToken cancellationToken_ = default) @@ -15022,6 +15051,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9352e4e41f173917UL)] public class Thing_Skeleton : Skeleton { public Thing_Skeleton() @@ -15899,6 +15929,7 @@ namespace Capnproto_test.Capnp.Test Task Return(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9ae342d394247cfcUL)] public class TestKeywordMethods_Proxy : Proxy, ITestKeywordMethods { public async Task Delete(CancellationToken cancellationToken_ = default) @@ -15954,6 +15985,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9ae342d394247cfcUL)] public class TestKeywordMethods_Skeleton : Skeleton { public TestKeywordMethods_Skeleton() @@ -16372,6 +16404,7 @@ namespace Capnproto_test.Capnp.Test Task GetCallerId(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xea72cc77253798cdUL)] public class TestAuthenticatedBootstrap_Proxy : Proxy, ITestAuthenticatedBootstrap where TVatId : class { public Task GetCallerId(CancellationToken cancellationToken_ = default) @@ -16393,6 +16426,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xea72cc77253798cdUL)] public class TestAuthenticatedBootstrap_Skeleton : Skeleton> where TVatId : class { public TestAuthenticatedBootstrap_Skeleton() @@ -17349,16 +17383,17 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd112a69d31ed918bUL), Proxy(typeof(TestNameAnnotationInterface_Proxy)), Skeleton(typeof(TestNameAnnotationInterface_Skeleton))] public interface ITestNameAnnotationInterface : IDisposable { - Task BadlyNamedMethod(byte BadlyNamedParam, CancellationToken cancellationToken_ = default); + Task BadlyNamedMethod(byte badlyNamedParam, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd112a69d31ed918bUL)] public class TestNameAnnotationInterface_Proxy : Proxy, ITestNameAnnotationInterface { - public async Task BadlyNamedMethod(byte BadlyNamedParam, CancellationToken cancellationToken_ = default) + public async Task BadlyNamedMethod(byte badlyNamedParam, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestNameAnnotationInterface.Params_BadlyNamedMethod() - { BadlyNamedParam = BadlyNamedParam }; + { BadlyNamedParam = badlyNamedParam }; arg_?.serialize(in_); using (var d_ = await Call(15065286897585459595UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -17368,6 +17403,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd112a69d31ed918bUL)] public class TestNameAnnotationInterface_Skeleton : Skeleton { public TestNameAnnotationInterface_Skeleton() diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs index 919dabb..ac83045 100644 --- a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs +++ b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.cs @@ -8473,6 +8473,7 @@ namespace Capnproto_test.Capnp.Test Task Call(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8839ed86c9794287UL)] public class DeepNestInterface_Proxy : Proxy, IDeepNestInterface where TQuux : class { public async Task Call(CancellationToken cancellationToken_ = default) @@ -8489,6 +8490,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8839ed86c9794287UL)] public class DeepNestInterface_Skeleton : Skeleton> where TQuux : class { public DeepNestInterface_Skeleton() @@ -8610,6 +8612,7 @@ namespace Capnproto_test.Capnp.Test Task<(TQux, Capnproto_test.Capnp.Test.TestGenerics)> Call(Capnproto_test.Capnp.Test.TestGenerics.Inner2 arg_, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc9e749e8dd54da5cUL)] public class Interface_Proxy : Proxy, IInterface where TQux : class { public Task<(TQux, Capnproto_test.Capnp.Test.TestGenerics)> Call(Capnproto_test.Capnp.Test.TestGenerics.Inner2 arg_, CancellationToken cancellationToken_ = default) @@ -8629,6 +8632,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc9e749e8dd54da5cUL)] public class Interface_Skeleton : Skeleton> where TQux : class { public Interface_Skeleton() @@ -8992,18 +8996,19 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8b9717a3f8d85a9aUL), Proxy(typeof(TestImplicitMethodParams_Proxy)), Skeleton(typeof(TestImplicitMethodParams_Skeleton))] public interface ITestImplicitMethodParams : IDisposable { - Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) + Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class; } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8b9717a3f8d85a9aUL)] public class TestImplicitMethodParams_Proxy : Proxy, ITestImplicitMethodParams { - public Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) + public Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class { var in_ = SerializerState.CreateForRpc.WRITER>(); var arg_ = new Capnproto_test.Capnp.Test.TestImplicitMethodParams.Params_Call() - {Foo = Foo, Bar = Bar}; + {Foo = foo, Bar = bar}; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(10058534285777328794UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -9018,6 +9023,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8b9717a3f8d85a9aUL)] public class TestImplicitMethodParams_Skeleton : Skeleton { public TestImplicitMethodParams_Skeleton() @@ -9125,18 +9131,19 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdf9ccdeb81a704c9UL), Proxy(typeof(TestImplicitMethodParamsInGeneric_Proxy<>)), Skeleton(typeof(TestImplicitMethodParamsInGeneric_Skeleton<>))] public interface ITestImplicitMethodParamsInGeneric : IDisposable where TV : class { - Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) + Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class; } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdf9ccdeb81a704c9UL)] public class TestImplicitMethodParamsInGeneric_Proxy : Proxy, ITestImplicitMethodParamsInGeneric where TV : class { - public Task> Call(TT Foo, TU Bar, CancellationToken cancellationToken_ = default) + public Task> Call(TT foo, TU bar, CancellationToken cancellationToken_ = default) where TT : class where TU : class { var in_ = SerializerState.CreateForRpc.Params_Call.WRITER>(); var arg_ = new Capnproto_test.Capnp.Test.TestImplicitMethodParamsInGeneric.Params_Call() - {Foo = Foo, Bar = Bar}; + {Foo = foo, Bar = bar}; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(16112979978201007305UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -9151,6 +9158,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdf9ccdeb81a704c9UL)] public class TestImplicitMethodParamsInGeneric_Skeleton : Skeleton> where TV : class { public TestImplicitMethodParamsInGeneric_Skeleton() @@ -10040,18 +10048,19 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x88eb12a0e0af92b2UL), Proxy(typeof(TestInterface_Proxy)), Skeleton(typeof(TestInterface_Skeleton))] public interface ITestInterface : IDisposable { - Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default); + Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default); Task Bar(CancellationToken cancellationToken_ = default); - Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default); + Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x88eb12a0e0af92b2UL)] public class TestInterface_Proxy : Proxy, ITestInterface { - public async Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default) + public async Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() - {I = I, J = J}; + {I = i, J = j}; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -10073,11 +10082,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) + public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() - {S = S}; + {S = s}; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -10087,6 +10096,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x88eb12a0e0af92b2UL)] public class TestInterface_Skeleton : Skeleton { public TestInterface_Skeleton() @@ -10475,6 +10485,7 @@ namespace Capnproto_test.Capnp.Test Task Grault(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe4e9bac98670b748UL)] public class TestExtends_Proxy : Proxy, ITestExtends { public async Task Qux(CancellationToken cancellationToken_ = default) @@ -10514,11 +10525,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default) + public async Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() - {I = I, J = J}; + {I = i, J = j}; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -10540,11 +10551,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) + public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() - {S = S}; + {S = s}; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -10554,6 +10565,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe4e9bac98670b748UL)] public class TestExtends_Skeleton : Skeleton { public TestExtends_Skeleton() @@ -10786,6 +10798,7 @@ namespace Capnproto_test.Capnp.Test { } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x98d7e0ef61488783UL)] public class TestExtends2_Proxy : Proxy, ITestExtends2 { public async Task Qux(CancellationToken cancellationToken_ = default) @@ -10825,11 +10838,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task Foo(uint I, bool J, CancellationToken cancellationToken_ = default) + public async Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Foo() - {I = I, J = J}; + {I = i, J = j}; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -10851,11 +10864,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes S, CancellationToken cancellationToken_ = default) + public async Task Baz(Capnproto_test.Capnp.Test.TestAllTypes s, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestInterface.Params_Baz() - {S = S}; + {S = s}; arg_?.serialize(in_); using (var d_ = await Call(9865999890858873522UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -10865,6 +10878,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x98d7e0ef61488783UL)] public class TestExtends2_Skeleton : Skeleton { public TestExtends2_Skeleton() @@ -10878,18 +10892,19 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa5a404caa61d4cd0UL), Proxy(typeof(TestPipeline_Proxy)), Skeleton(typeof(TestPipeline_Skeleton))] public interface ITestPipeline : IDisposable { - Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint N, Capnproto_test.Capnp.Test.ITestInterface InCap, CancellationToken cancellationToken_ = default); - Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface Cap, object Obj, IReadOnlyList List, CancellationToken cancellationToken_ = default); - Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint N, BareProxy InCap, CancellationToken cancellationToken_ = default); + Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint n, Capnproto_test.Capnp.Test.ITestInterface inCap, CancellationToken cancellationToken_ = default); + Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_ = default); + Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint n, BareProxy inCap, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa5a404caa61d4cd0UL)] public class TestPipeline_Proxy : Proxy, ITestPipeline { - public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint N, Capnproto_test.Capnp.Test.ITestInterface InCap, CancellationToken cancellationToken_ = default) + public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.Box)> GetCap(uint n, Capnproto_test.Capnp.Test.ITestInterface inCap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_GetCap() - {N = N, InCap = InCap}; + {N = n, InCap = inCap}; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(11935670180855499984UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -10903,11 +10918,11 @@ namespace Capnproto_test.Capnp.Test ); } - public async Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface Cap, object Obj, IReadOnlyList List, CancellationToken cancellationToken_ = default) + public async Task TestPointers(Capnproto_test.Capnp.Test.ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_TestPointers() - {Cap = Cap, Obj = Obj, List = List}; + {Cap = cap, Obj = obj, List = list}; arg_?.serialize(in_); using (var d_ = await Call(11935670180855499984UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -10916,11 +10931,11 @@ namespace Capnproto_test.Capnp.Test } } - public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint N, BareProxy InCap, CancellationToken cancellationToken_ = default) + public Task<(string, Capnproto_test.Capnp.Test.TestPipeline.AnyBox)> GetAnyCap(uint n, BareProxy inCap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestPipeline.Params_GetAnyCap() - {N = N, InCap = InCap}; + {N = n, InCap = inCap}; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(11935670180855499984UL, 2, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -10935,6 +10950,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa5a404caa61d4cd0UL)] public class TestPipeline_Skeleton : Skeleton { public TestPipeline_Skeleton() @@ -11550,16 +11566,17 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa0e77035bdff0051UL), Proxy(typeof(TestCallOrder_Proxy)), Skeleton(typeof(TestCallOrder_Skeleton))] public interface ITestCallOrder : IDisposable { - Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default); + Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa0e77035bdff0051UL)] public class TestCallOrder_Proxy : Proxy, ITestCallOrder { - public async Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default) + public async Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestCallOrder.Params_GetCallSequence() - {Expected = Expected}; + {Expected = expected}; arg_?.serialize(in_); using (var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -11569,6 +11586,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa0e77035bdff0051UL)] public class TestCallOrder_Skeleton : Skeleton { public TestCallOrder_Skeleton() @@ -11721,16 +11739,17 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddd699207eb8e23bUL), Proxy(typeof(TestTailCallee_Proxy)), Skeleton(typeof(TestTailCallee_Skeleton))] public interface ITestTailCallee : IDisposable { - Task Foo(int I, string T, CancellationToken cancellationToken_ = default); + Task Foo(int i, string t, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddd699207eb8e23bUL)] public class TestTailCallee_Proxy : Proxy, ITestTailCallee { - public Task Foo(int I, string T, CancellationToken cancellationToken_ = default) + public Task Foo(int i, string t, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestTailCallee.Params_Foo() - {I = I, T = T}; + {I = i, T = t}; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15985132292242203195UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -11745,6 +11764,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddd699207eb8e23bUL)] public class TestTailCallee_Skeleton : Skeleton { public TestTailCallee_Skeleton() @@ -11941,16 +11961,17 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x870bf40110ce3035UL), Proxy(typeof(TestTailCaller_Proxy)), Skeleton(typeof(TestTailCaller_Skeleton))] public interface ITestTailCaller : IDisposable { - Task Foo(int I, Capnproto_test.Capnp.Test.ITestTailCallee Callee, CancellationToken cancellationToken_ = default); + Task Foo(int i, Capnproto_test.Capnp.Test.ITestTailCallee callee, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x870bf40110ce3035UL)] public class TestTailCaller_Proxy : Proxy, ITestTailCaller { - public Task Foo(int I, Capnproto_test.Capnp.Test.ITestTailCallee Callee, CancellationToken cancellationToken_ = default) + public Task Foo(int i, Capnproto_test.Capnp.Test.ITestTailCallee callee, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestTailCaller.Params_Foo() - {I = I, Callee = Callee}; + {I = i, Callee = callee}; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(9731139705278181429UL, 0, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -11965,6 +11986,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x870bf40110ce3035UL)] public class TestTailCaller_Skeleton : Skeleton { public TestTailCaller_Skeleton() @@ -12073,10 +12095,12 @@ namespace Capnproto_test.Capnp.Test { } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa38e5efe41e53a15UL)] public class TestHandle_Proxy : Proxy, ITestHandle { } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa38e5efe41e53a15UL)] public class TestHandle_Skeleton : Skeleton { public TestHandle_Skeleton() @@ -12090,28 +12114,29 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddc70bf9784133cfUL), Proxy(typeof(TestMoreStuff_Proxy)), Skeleton(typeof(TestMoreStuff_Skeleton))] public interface ITestMoreStuff : Capnproto_test.Capnp.Test.ITestCallOrder { - Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); - Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); - Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); - Task Hold(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); + Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); + Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); + Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); + Task Hold(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); Task CallHeld(CancellationToken cancellationToken_ = default); Task GetHeld(CancellationToken cancellationToken_ = default); - Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder Cap, CancellationToken cancellationToken_ = default); - Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default); - Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default); + Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder cap, CancellationToken cancellationToken_ = default); + Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default); + Task<(string, string)> MethodWithDefaults(string a, uint b, string c, CancellationToken cancellationToken_ = default); Task GetHandle(CancellationToken cancellationToken_ = default); Task GetNull(CancellationToken cancellationToken_ = default); Task GetEnormousString(CancellationToken cancellationToken_ = default); - Task MethodWithNullDefault(string A, Capnproto_test.Capnp.Test.ITestInterface B, CancellationToken cancellationToken_ = default); + Task MethodWithNullDefault(string a, Capnproto_test.Capnp.Test.ITestInterface b, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddc70bf9784133cfUL)] public class TestMoreStuff_Proxy : Proxy, ITestMoreStuff { - public async Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) + public async Task CallFoo(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_CallFoo() - {Cap = Cap}; + {Cap = cap}; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -12120,11 +12145,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) + public async Task CallFooWhenResolved(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_CallFooWhenResolved() - {Cap = Cap}; + {Cap = cap}; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -12133,11 +12158,11 @@ namespace Capnproto_test.Capnp.Test } } - public Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) + public Task NeverReturn(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_NeverReturn() - {Cap = Cap}; + {Cap = cap}; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 2, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -12151,11 +12176,11 @@ namespace Capnproto_test.Capnp.Test ); } - public async Task Hold(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) + public async Task Hold(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_Hold() - {Cap = Cap}; + {Cap = cap}; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 3, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -12195,11 +12220,11 @@ namespace Capnproto_test.Capnp.Test ); } - public Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder Cap, CancellationToken cancellationToken_ = default) + public Task Echo(Capnproto_test.Capnp.Test.ITestCallOrder cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_Echo() - {Cap = Cap}; + {Cap = cap}; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(15980754968839795663UL, 6, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -12213,11 +12238,11 @@ namespace Capnproto_test.Capnp.Test ); } - public async Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface Cap, CancellationToken cancellationToken_ = default) + public async Task ExpectCancel(Capnproto_test.Capnp.Test.ITestInterface cap, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_ExpectCancel() - {Cap = Cap}; + {Cap = cap}; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 7, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -12226,11 +12251,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default) + public async Task<(string, string)> MethodWithDefaults(string a, uint b, string c, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_MethodWithDefaults() - {A = A, B = B, C = C}; + {A = a, B = b, C = c}; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 8, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -12288,11 +12313,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task MethodWithNullDefault(string A, Capnproto_test.Capnp.Test.ITestInterface B, CancellationToken cancellationToken_ = default) + public async Task MethodWithNullDefault(string a, Capnproto_test.Capnp.Test.ITestInterface b, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMoreStuff.Params_MethodWithNullDefault() - {A = A, B = B}; + {A = a, B = b}; arg_?.serialize(in_); using (var d_ = await Call(15980754968839795663UL, 12, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -12301,11 +12326,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task GetCallSequence(uint Expected, CancellationToken cancellationToken_ = default) + public async Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestCallOrder.Params_GetCallSequence() - {Expected = Expected}; + {Expected = expected}; arg_?.serialize(in_); using (var d_ = await Call(11594359141811814481UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -12315,6 +12340,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xddc70bf9784133cfUL)] public class TestMoreStuff_Skeleton : Skeleton { public TestMoreStuff_Skeleton() @@ -14032,12 +14058,13 @@ namespace Capnproto_test.Capnp.Test public interface ITestMembrane : IDisposable { Task MakeThing(CancellationToken cancellationToken_ = default); - Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default); - Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default); - Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, CancellationToken cancellationToken_ = default); + Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default); + Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default); + Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, CancellationToken cancellationToken_ = default); Task WaitForever(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc07d8dcd80a69c0cUL)] public class TestMembrane_Proxy : Proxy, ITestMembrane { public Task MakeThing(CancellationToken cancellationToken_ = default) @@ -14058,11 +14085,11 @@ namespace Capnproto_test.Capnp.Test ); } - public async Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default) + public async Task CallPassThrough(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_CallPassThrough() - {Thing = Thing, TailCall = TailCall}; + {Thing = thing, TailCall = tailCall}; arg_?.serialize(in_); using (var d_ = await Call(13870398341137210380UL, 1, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -14071,11 +14098,11 @@ namespace Capnproto_test.Capnp.Test } } - public async Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, bool TailCall, CancellationToken cancellationToken_ = default) + public async Task CallIntercept(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, bool tailCall, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_CallIntercept() - {Thing = Thing, TailCall = TailCall}; + {Thing = thing, TailCall = tailCall}; arg_?.serialize(in_); using (var d_ = await Call(13870398341137210380UL, 2, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -14084,11 +14111,11 @@ namespace Capnproto_test.Capnp.Test } } - public Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing Thing, CancellationToken cancellationToken_ = default) + public Task Loopback(Capnproto_test.Capnp.Test.TestMembrane.IThing thing, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestMembrane.Params_Loopback() - {Thing = Thing}; + {Thing = thing}; arg_?.serialize(in_); return Impatient.MakePipelineAware(Call(13870398341137210380UL, 3, in_.Rewrap(), false, cancellationToken_), d_ => { @@ -14116,6 +14143,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc07d8dcd80a69c0cUL)] public class TestMembrane_Skeleton : Skeleton { public TestMembrane_Skeleton() @@ -14209,6 +14237,7 @@ namespace Capnproto_test.Capnp.Test Task Intercept(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9352e4e41f173917UL)] public class Thing_Proxy : Proxy, IThing { public async Task PassThrough(CancellationToken cancellationToken_ = default) @@ -14238,6 +14267,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9352e4e41f173917UL)] public class Thing_Skeleton : Skeleton { public Thing_Skeleton() @@ -15115,6 +15145,7 @@ namespace Capnproto_test.Capnp.Test Task Return(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9ae342d394247cfcUL)] public class TestKeywordMethods_Proxy : Proxy, ITestKeywordMethods { public async Task Delete(CancellationToken cancellationToken_ = default) @@ -15170,6 +15201,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9ae342d394247cfcUL)] public class TestKeywordMethods_Skeleton : Skeleton { public TestKeywordMethods_Skeleton() @@ -15588,6 +15620,7 @@ namespace Capnproto_test.Capnp.Test Task GetCallerId(CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xea72cc77253798cdUL)] public class TestAuthenticatedBootstrap_Proxy : Proxy, ITestAuthenticatedBootstrap where TVatId : class { public Task GetCallerId(CancellationToken cancellationToken_ = default) @@ -15609,6 +15642,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xea72cc77253798cdUL)] public class TestAuthenticatedBootstrap_Skeleton : Skeleton> where TVatId : class { public TestAuthenticatedBootstrap_Skeleton() @@ -16565,16 +16599,17 @@ namespace Capnproto_test.Capnp.Test [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd112a69d31ed918bUL), Proxy(typeof(TestNameAnnotationInterface_Proxy)), Skeleton(typeof(TestNameAnnotationInterface_Skeleton))] public interface ITestNameAnnotationInterface : IDisposable { - Task BadlyNamedMethod(byte BadlyNamedParam, CancellationToken cancellationToken_ = default); + Task BadlyNamedMethod(byte badlyNamedParam, CancellationToken cancellationToken_ = default); } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd112a69d31ed918bUL)] public class TestNameAnnotationInterface_Proxy : Proxy, ITestNameAnnotationInterface { - public async Task BadlyNamedMethod(byte BadlyNamedParam, CancellationToken cancellationToken_ = default) + public async Task BadlyNamedMethod(byte badlyNamedParam, CancellationToken cancellationToken_ = default) { var in_ = SerializerState.CreateForRpc(); var arg_ = new Capnproto_test.Capnp.Test.TestNameAnnotationInterface.Params_BadlyNamedMethod() - {BadlyNamedParam = BadlyNamedParam}; + {BadlyNamedParam = badlyNamedParam}; arg_?.serialize(in_); using (var d_ = await Call(15065286897585459595UL, 0, in_.Rewrap(), false, cancellationToken_).WhenReturned) { @@ -16584,6 +16619,7 @@ namespace Capnproto_test.Capnp.Test } } + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd112a69d31ed918bUL)] public class TestNameAnnotationInterface_Skeleton : Skeleton { public TestNameAnnotationInterface_Skeleton() diff --git a/CapnpC.CSharp.Generator/CodeGen/GenNames.cs b/CapnpC.CSharp.Generator/CodeGen/GenNames.cs index 1c3ac6b..5d3d0de 100644 --- a/CapnpC.CSharp.Generator/CodeGen/GenNames.cs +++ b/CapnpC.CSharp.Generator/CodeGen/GenNames.cs @@ -47,7 +47,6 @@ namespace CapnpC.CSharp.Generator.CodeGen public Name ReaderContextField { get; } public Name ContextParameter { get; } public Name GroupReaderContextArg { get; } - public Name GroupWriterContextArg { get; } public Name UnionDiscriminatorEnum { get; } public Name UnionDiscriminatorProp { get; } public Name UnionDiscriminatorUndefined { get; } @@ -61,14 +60,12 @@ namespace CapnpC.CSharp.Generator.CodeGen public Name ResultLocal { get; } public Name SerializeMethod { get; } public Name ApplyDefaultsMethod { get; } - public Name InstLocalName { get; } public string ParamsStructFormat { get; } public string ResultStructFormat { get; } public string PropertyNamedLikeTypeRenameFormat { get; } public string GenericTypeParameterFormat { get; } public string MemberAccessPathNameFormat { get; } public Name TaskParameter { get; } - public Name EagerMethod { get; } public Name TypeIdField { get; } public string PipeliningExtensionsClassFormat { get; } public string ProxyClassFormat { get; } @@ -91,7 +88,6 @@ namespace CapnpC.CSharp.Generator.CodeGen ReaderContextField = new Name(options.ReaderContextFieldName); ContextParameter = new Name(options.ContextParameterName); GroupReaderContextArg = new Name(options.GroupReaderContextArgName); - GroupWriterContextArg = new Name(options.GroupWriterContextArgName); UnionDiscriminatorEnum = new Name(options.UnionDiscriminatorEnumName); UnionDiscriminatorProp = new Name(options.UnionDiscriminatorPropName); UnionDiscriminatorUndefined = new Name(options.UnionDiscriminatorUndefinedName); @@ -105,14 +101,12 @@ namespace CapnpC.CSharp.Generator.CodeGen DeserializerLocal = new Name(options.DeserializerLocalName); SerializerLocal = new Name(options.SerializerLocalName); ResultLocal = new Name(options.ResultLocalName); - InstLocalName = new Name(options.InstLocalName); ParamsStructFormat = options.ParamsStructFormat; ResultStructFormat = options.ResultStructFormat; PropertyNamedLikeTypeRenameFormat = options.PropertyNamedLikeTypeRenameFormat; GenericTypeParameterFormat = options.GenericTypeParameterFormat; MemberAccessPathNameFormat = options.MemberAccessPathNameFormat; TaskParameter = new Name(options.TaskParameterName); - EagerMethod = new Name(options.EagerMethodName); TypeIdField = new Name(options.TypeIdFieldName); PipeliningExtensionsClassFormat = options.PipeliningExtensionsClassFormat; ProxyClassFormat = options.ProxyClassFormat; @@ -594,7 +588,7 @@ namespace CapnpC.CSharp.Generator.CodeGen } string GetCodeIdentifierUpperCamel(Field field) => field.CsName ?? SyntaxHelpers.MakeUpperCamel(field.Name); - string GetCodeIdentifierLowerCamel(Field field) => field.CsName ?? IdentifierRenamer.ToNonKeyword(SyntaxHelpers.MakeLowerCamel(field.Name)); + public string GetCodeIdentifierLowerCamel(Field field) => field.CsName ?? IdentifierRenamer.ToNonKeyword(SyntaxHelpers.MakeLowerCamel(field.Name)); public Name GetCodeIdentifier(Field field) { @@ -605,13 +599,6 @@ namespace CapnpC.CSharp.Generator.CodeGen var def = field.DeclaringType; - if (def == null) - { - // Method parameters are internally represented with the same class "Field". - // They do not have a declaring type. Anyway, they don't suffer from the field-name-equals-nested-type-name problem. - return new Name(GetCodeIdentifierLowerCamel(field)); - } - var typeNames = new HashSet(def.NestedTypes.Select(t => MakeTypeName(t))); typeNames.Add(MakeTypeName(def)); @@ -647,10 +634,7 @@ namespace CapnpC.CSharp.Generator.CodeGen public Name MakePipeliningSupportExtensionMethodName(IReadOnlyList path) { - if (path.Count == 1 && path[0].Offset == 0) - return EagerMethod; - else - return new Name(string.Join("_", path.Select(f => GetCodeIdentifier(f).ToString()))); + return new Name(string.Join("_", path.Select(f => GetCodeIdentifier(f).ToString()))); } public Name MakePipeliningSupportExtensionClassName(GenFile file) diff --git a/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs b/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs index cd6061f..133cfa4 100644 --- a/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs +++ b/CapnpC.CSharp.Generator/CodeGen/GeneratorOptions.cs @@ -11,7 +11,6 @@ public string ReaderContextFieldName { get; set; } = "ctx"; public string ContextParameterName { get; set; } = "ctx"; public string GroupReaderContextArgName { get; set; } = "ctx"; - public string GroupWriterContextArgName { get; set; } = "ctx"; public string UnionDiscriminatorEnumName { get; set; } = "WHICH"; public string UnionDiscriminatorPropName { get; set; } = "which"; public string UnionDiscriminatorFieldName { get; set; } = "_which"; @@ -28,14 +27,12 @@ public string ParamsStructFormat { get; set; } = "Params_{0}"; public string ResultStructFormat { get; set; } = "Result_{0}"; public string PropertyNamedLikeTypeRenameFormat { get; set; } = "The{0}"; - public string InstLocalName { get; set; } = "inst"; public string GenericTypeParameterFormat { get; set; } = "T{0}"; public string PipeliningExtensionsClassFormat { get; set; } = "PipeliningSupportExtensions_{0}"; public string ProxyClassFormat { get; set; } = "{0}_Proxy"; public string SkeletonClassFormat { get; set; } = "{0}_Skeleton"; public string MemberAccessPathNameFormat { get; set; } = "Path_{0}_{1}_{2}_{3}"; public string TaskParameterName { get; set; } = "task"; - public string EagerMethodName { get; set; } = "Eager"; public string TypeIdFieldName { get; set; } = "typeId"; public string AwaitProxyName { get; set; } = "AwaitProxy"; public bool NullableEnableDefault { get; set; } = false; diff --git a/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs b/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs index d3f2076..398286b 100644 --- a/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs +++ b/CapnpC.CSharp.Generator/CodeGen/InterfaceSnippetGen.cs @@ -61,7 +61,7 @@ namespace CapnpC.CSharp.Generator.CodeGen { foreach (var arg in method.Params) { - list.Add(Parameter(_names.GetCodeIdentifier(arg).Identifier) + list.Add(Parameter(Identifier(_names.GetCodeIdentifierLowerCamel(arg))) .WithType(_names.MakeTypeSyntax(arg.Type, method.DeclaringInterface, TypeUsage.DomainClass, Nullability.NullableRef))); } } @@ -194,8 +194,8 @@ namespace CapnpC.CSharp.Generator.CodeGen yield return AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, - _names.GetCodeIdentifier(field).IdentifierName, - _names.GetCodeIdentifier(methodParam).IdentifierName); + _names.GetCodeIdentifier(methodParam).IdentifierName, + IdentifierName(_names.GetCodeIdentifierLowerCamel(field))); } } @@ -284,6 +284,7 @@ namespace CapnpC.CSharp.Generator.CodeGen public MemberDeclarationSyntax MakeProxy(TypeDefinition type) { var classDecl = ClassDeclaration(_names.MakeTypeName(type, NameUsage.Proxy).Identifier) + .AddAttributeLists(_names.MakeTypeDecorationAttributes(type.Id)) .AddModifiers(Public) .AddBaseListTypes( SimpleBaseType(_names.Type(Nullability.NonNullable)), @@ -480,7 +481,7 @@ namespace CapnpC.CSharp.Generator.CodeGen yield return AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, _names.GetCodeIdentifier(arg).IdentifierName, - IdentifierName(IdentifierRenamer.ToNonKeyword(arg.Name))); + IdentifierName(_names.GetCodeIdentifierLowerCamel(arg))); } } @@ -650,7 +651,7 @@ namespace CapnpC.CSharp.Generator.CodeGen if (method.Results.Count == 1) { lambdaArg = SimpleLambdaExpression( - Parameter(Identifier(method.Results.Single().Name)), + Parameter(Identifier(_names.GetCodeIdentifierLowerCamel(method.Results.Single()))), MakeMaybeTailCallLambdaBody(method)); } else @@ -662,7 +663,7 @@ namespace CapnpC.CSharp.Generator.CodeGen { if (paramList.Count > 0) paramList.Add(Token(SyntaxKind.CommaToken)); - paramList.Add(Parameter(Identifier(arg.Name))); + paramList.Add(Parameter(Identifier(_names.GetCodeIdentifierLowerCamel(arg)))); } lambdaArg = ParenthesizedLambdaExpression( ParameterList( @@ -729,6 +730,7 @@ namespace CapnpC.CSharp.Generator.CodeGen { var name = _names.MakeTypeName(type, NameUsage.Skeleton).Identifier; var classDecl = ClassDeclaration(name) + .AddAttributeLists(_names.MakeTypeDecorationAttributes(type.Id)) .AddModifiers(Public) .AddBaseListTypes( SimpleBaseType( From 62d5a7e9bd207fc4aaa67877a9dea326bed63984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 18 Apr 2020 15:06:52 +0200 Subject: [PATCH 51/76] feature: header text in generated files fixed double-far encoding/decoding bug --- Capnp.Net.Runtime/DeserializerState.cs | 2 +- Capnp.Net.Runtime/Rpc/rpc.cs | 1 + Capnp.Net.Runtime/SerializerState.cs | 2 +- .../CapnpC.CSharp.Generator.Tests.csproj | 4 + CapnpC.CSharp.Generator.Tests/Embedded | Bin 0 -> 3736 bytes .../NullableDisable.capnp.bin | Bin 1720 -> 1664 bytes .../NullableDisable2.capnp.bin | Bin 2112 -> 2008 bytes .../NullableEnable.capnp.bin | Bin 1720 -> 1656 bytes .../NullableEnable2.capnp.bin | Bin 2112 -> 2008 bytes .../Embedded Resources/rpc-csharp.capnp.bin | Bin 66744 -> 66784 bytes .../Embedded Resources/test.capnp.bin | Bin 141680 -> 141704 bytes .../UnitTest1.capnp | 0 .../No Resources/rpc-csharp.capnp | 4 +- .../No Resources/test.capnp | 2 +- .../testdata/annotated-json.binary | Bin 0 -> 544 bytes .../No Resources/testdata/annotated.json | 22 +++ .../No Resources/testdata/binary | Bin 0 -> 2816 bytes .../testdata/errors.capnp.nobuild | 161 +++++++++++++++ .../No Resources/testdata/errors.txt | 60 ++++++ .../No Resources/testdata/flat | Bin 0 -> 2808 bytes .../No Resources/testdata/lists.binary | Bin 0 -> 1096 bytes .../No Resources/testdata/packed | Bin 0 -> 831 bytes .../No Resources/testdata/packedflat | Bin 0 -> 828 bytes .../No Resources/testdata/pretty.json | 88 +++++++++ .../No Resources/testdata/pretty.txt | 187 ++++++++++++++++++ .../No Resources/testdata/segmented | Bin 0 -> 5520 bytes .../No Resources/testdata/segmented-packed | Bin 0 -> 1352 bytes .../No Resources/testdata/short.json | 1 + .../No Resources/testdata/short.txt | 1 + .../CodeGen/CodeGenerator.cs | 9 +- CapnpC.CSharp.Generator/Model/GenFile.cs | 1 + CapnpC.CSharp.Generator/Model/SchemaModel.cs | 16 ++ CapnpC.CSharp.Generator/Model/SourceInfo.cs | 12 ++ .../Model/SupportedAnnotations.cs | 15 ++ include/capnp/c++.capnp | 26 +++ scripts/regen-capnpbin.bat | 3 + 36 files changed, 612 insertions(+), 5 deletions(-) create mode 100644 CapnpC.CSharp.Generator.Tests/Embedded rename CapnpC.CSharp.Generator.Tests/{Embedded Resources => No Resources}/UnitTest1.capnp (100%) create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/annotated-json.binary create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/annotated.json create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/binary create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/errors.capnp.nobuild create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/errors.txt create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/flat create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/lists.binary create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/packed create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/packedflat create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/pretty.json create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/pretty.txt create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/segmented create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/segmented-packed create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/short.json create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/testdata/short.txt create mode 100644 CapnpC.CSharp.Generator/Model/SourceInfo.cs create mode 100644 include/capnp/c++.capnp create mode 100644 scripts/regen-capnpbin.bat diff --git a/Capnp.Net.Runtime/DeserializerState.cs b/Capnp.Net.Runtime/DeserializerState.cs index 1aee28e..eaa24f9 100644 --- a/Capnp.Net.Runtime/DeserializerState.cs +++ b/Capnp.Net.Runtime/DeserializerState.cs @@ -350,7 +350,7 @@ namespace Capnp throw new DeserializationException("Error decoding double-far pointer: not followed by intra-segment pointer"); CurrentSegmentIndex = pointer1.TargetSegmentIndex; - Offset = 0; + Offset = pointer1.LandingPadOffset; pointer = pointer2; offset = -1; } diff --git a/Capnp.Net.Runtime/Rpc/rpc.cs b/Capnp.Net.Runtime/Rpc/rpc.cs index d2d8c5f..c48f8d0 100644 --- a/Capnp.Net.Runtime/Rpc/rpc.cs +++ b/Capnp.Net.Runtime/Rpc/rpc.cs @@ -1,3 +1,4 @@ +#pragma warning disable CS1591 using Capnp; using Capnp.Rpc; using System; diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index 293a424..cb219d1 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -375,7 +375,7 @@ namespace Capnp farPtr2.SetFarPointer(target.SegmentIndex, target.Offset, false); var farSpan = FarSpan(landingPadSlice.SegmentIndex); farSpan[landingPadSlice.Offset] = farPtr2; - targetPtr.Offset = target.Offset; + targetPtr.Offset = 0; farSpan[landingPadSlice.Offset + 1] = targetPtr; } } diff --git a/CapnpC.CSharp.Generator.Tests/CapnpC.CSharp.Generator.Tests.csproj b/CapnpC.CSharp.Generator.Tests/CapnpC.CSharp.Generator.Tests.csproj index 77462b1..86f1a6b 100644 --- a/CapnpC.CSharp.Generator.Tests/CapnpC.CSharp.Generator.Tests.csproj +++ b/CapnpC.CSharp.Generator.Tests/CapnpC.CSharp.Generator.Tests.csproj @@ -30,6 +30,10 @@ + + + + diff --git a/CapnpC.CSharp.Generator.Tests/Embedded b/CapnpC.CSharp.Generator.Tests/Embedded new file mode 100644 index 0000000000000000000000000000000000000000..79d5e7d828d0888f0ecf55605a96c9fff77f35e4 GIT binary patch literal 3736 zcmbVPU5Hgx6yEdWPnpz6G3JYAhMGB!F%=D{ph64`{!9r94RO44iwn)YH}AC?YN)v; z_=Cc{NcB(=i6{z+5lKoW_>Zac5ItwUhy+SO5=7s(_xaA*XV1NpxL}{P*IIk6v-Y?4 zUgut8j2Uaf!&0kh1OKSin0u3rnTllX!-7f3U}R0__a6-ZeJWhP3~|Pw>;ZR~ zxfQD+x7f_H9*XmDRy|I70sb{;ndf})4d4^yyZrXatJ`Z+FA={M4B>)lhWZibYiRP| zFL{>jkeR=@Ojp}`+eW`x_7!np+*P~h{M9;^`%`xDLHHknur-b&{X39ff$&+NKmPv4 zUw`O5`upRsF|P8LpZEy;E%>YuVtM+Ye;-EjzSLxA_T@`*ix#;wx{J|ZzEX~Id2b!-6vp+;_2QVR(9%zN zJ_MP0{5*Q+-=PBocPT%M5x$Qy)N$V)zfabo(LO(i#qOuOJ1Q1S)u>u16)V;uc_cW* zxOd0Ea(~QMeT99H`RN`^$9yG*>d*Y=Vyr0**nC&L9aSp%ig|VGW@sI?p!1U$H+gT2 zv;1Ud9krf1^&#~Q=EL_lBEE^|?yY>ar}$FQoVh2 z#4nw5tqUQ!kho{tv$78@21m#d_Om=J%_JWP0xI>C9~xjNmQR-q4J>f^Kk zGX1*1=~s;FMLbF2{+!m>-w~SoJQvrQ{g$Nu>!kE4d#Z7>5Eq>rTDhzH!G--mR1X(t za~NqIaq;~^Tncf2QQkWD@)ws~vUuTn%^r*=xOnH&$A(e4BX>{u6lKp1?Yw zBkNy@@2B>m`>gfivP%}PmnZK$Gh%-FUN9^6yYiM&wNxD{+a>||e)9LveVG41RE-b@ zZ@d%R!j9lF=5mBV3t-+s{VQotIu*cuF3|S)w3FA9*_cq1Z*gogW zTFLWXPw(vGUNz35-VSQ7kTg33}7 IH@;W@0nr@WBLDyZ literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/NullableDisable.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/NullableDisable.capnp.bin index 14f05c8dbdd594ee40531bef29e1d33599139cd1..0195af509b3a7de4d6d97592213a9e39798e8759 100644 GIT binary patch delta 531 zcmdnN+rX>I00iej1Q@U|2mVy%b`Pfguo0jql`#jN-9wR{BAy1^LDL$%zGd z1x5KK`MN3jC3&eO$@xX8`pzIhXFccOjKrb>J@?eS)S|?a{35-O)Z&t2eZPE#pw#00 z(xT+lV*Sv(%o32Wp_v}oD4?qtCi5~KHsb*@7=duX+hZAG&AhKc;S~hL3z7I$K>i{m zz81seFlMF62bdQG)4+j~^I0S}_pq#BtOrGkA<%A6q|m@3L`VS5holQehSgAi0;6Mc HHk&8_Htm|L diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/NullableDisable2.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/NullableDisable2.capnp.bin index dcc032abdebdc1a9e8df46a9810d832c12bf82e8..5681502377722ce251cc43eb2261de3658b689e1 100644 GIT binary patch delta 493 zcmX>gaD!iq0SJD92ryt_5CqcVObiTbnHd=5fov8aW(4AoOcS-_7zHN_GRup81oC$Q z@lPNY2Vzd30&}2@^yCIMj)@BtBo%=IkAM=oK$;y$!+^%*hm7JAKWK1)M5sP5{Mp{7B!YnlM`9BH+QqfGqNP-r=(7P V$F`4W7tnBCAO^(^*q7oQngF1ZZH52< delta 602 zcmcb?e?UNs0SMR`K_m#UFbD!kaV7?az03>@@?a4L29Pu(^F%E<#;D1L%<`fifqW*Q zyev>c9LUxM(&j)J>B$Lf91|BPNV)87Uy{MN`oMR3XopFqx4_UbYe_ z7X@_XS~N8)fqeUkfx@0{R{BAy1^LDL$%zGd1x5KK`MN3jC3&eO$@xX8`pzIhXFccO zjKrb>J@?eS)S|?a{35-O)Z&t2eZPE#pw#00(xT+lV*SYhOyZL>n0~kk03FQ;gbUst z%MfekeJu&(2LbUyBz_f;zZi+X3CLdr<;w!uS`3q)F}8?RF!T3 diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/NullableEnable.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/NullableEnable.capnp.bin index 4a92c1a303018bc643e701d6f89d43f84b93dd1a..6c81ea600449a1cdd5ab044e6ae23132f685ce7d 100644 GIT binary patch delta 539 zcmdnN`-4Z50SL~42ryt_5Cqcu85tPQSl*?|}a9sn84lNT}xPyC=EdJ)LU0^+McTn@y( zKpVg&O!i>ZkPQX$b^%3Wfi$ua5kNlJh{+2WIT%GJuVj>$^aP4A0WnAqvf9AO4;jTp z{7Q3j5|eULUGqSsUUFhVUcuxLrX%$-K;s#KaOvA)8Dh=6uML6xDj;5f#18`U7b5XN z@{5u9n}GZ!P`)XU{R@bfLHV{oHc0&)bRo_DC)3jnB2pr0{}pWi#`AV delta 576 zcmeytvx8TY0SK;v2ryt_5Cqcu85tOUGBGg71KBJ<4CFFYPSliV44J%;NnZ3Qkb4Oz z{SiougQS7-@<18s$qB3+6Bj5*{RIj>0%A^}1Urz10T#xIx9mi}0=Zd0{1b@Hfmju; z-Gfm>QWwbE1r#+!(`zuflTn^AYVt}(c}Yc}oE9?!Lm-+O-^mXd#bey8^n+3h@{9G8 z6ASVRitQ17t7);exlvGQ^sBUxR`y2#6OV@vDIR wMM!)thRI>fN|O&TF9@cA`zGhHh;43USgaD!iq0SJD92ryt_5CqcVObiTbnHd=5fov8aW(4AoOcS-_7zHKisq}hQq3}{S#$S6MXgNCRiP$CN`Dhs5` zf%H@$Ee|!rgHc0rE|9+qD83X(BO9;)WWeMFKot{#GEzXi5KYA#pbB|LvB``~^0K`^ zIW8aunTBl2Od#KWVxaJ3Mh@}G>zRJm%K)un1j40nk7bB8^S(9&@~eP&0TMq5$X|%W z2gxr+;)8-@36yUNWP<{A8I*4eWP{W%LgIr$KBTfBH7v83Ju@jYC$pq-@;hcLz0};y z5|{kk#LPVBoW$bd)MCfH6wkbp)S|S+c_wKsRO#xt@c=clAj Ve#f?t2jm!DAO^(`*q7oQngE;}Z~p)Q delta 602 zcmcb?e?UNs0SMR`K_m#UFbD!kaV7?az03>@@?a4L29Pu(^F%E<#>mNr%<`fif&5=U zHL^enaUfe4NSgy?q$ek^aZFsGAn6Jecm$LP1k&t48U}nOKV%f2_(4O|7ATPg6m;&?50YxVQX=Lp^AnlVE09DiiWu$<(7fnS6P=!2W{A5NZdD%*! zToBL~YthuK1oG`C1`2z+S?LF*7UUP}Cnpx<6%^%{N|r3o%Ni9 zGZKpm^xRYPQi~Ex@{9CBQj1H9_5Jb{f>Mj~ON)|Ii}fc5Fo{pjVEW-E0CY4X5H5Io zEJLiB_q8OD9|Xh;k@!_W{$eElCLn(ilrIZpYcWiI#%wh?faL=f9q7QSy*Y<9j*+E2 avm|5kIktVFp!hQcS_g_h>ITFHb`1bO*_ToP diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/rpc-csharp.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/rpc-csharp.capnp.bin index 720907783602a0916c0a7c1ade509a2b8890a602..0a66adb1d3dc66dea27ce9a9e4d6ffa2003db42e 100644 GIT binary patch delta 149 zcmdnd$?~9+MUaI72tWi7m#{N1Y}hEc-j1^)_e(?p9@`<` diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/test.capnp.bin index 66c8d13757549b83eaaa4e2e4e1ff90e836ca0da..199c9d32bde29d294b778ab0a2803f43e5362bc7 100644 GIT binary patch delta 892 zcmZWnO=uHQ5Pq{snjecaO4w{8q=|(r1gy!;pZa1Dg`ReMvBY4TlpYMWre1`-wH}n* zHggE{l;$MyptgrXPU5i_ZN2rDLIrbbb1alNoAizKtbB{HcXs49SoXaX?AWCbFk$~qh3BcSkj{-VCLj(W+m458velB@!*zJ3 z&0P}%70K?Pg$KZ6HQMRewI#dV&N##MpApO{y4H&eO=xO#^(1a6JXV<%)w*QYp*1TU zPRSwrNN5U@T}=fu9v(aAqMOW(`e$>(q3O{z>xt-XNp>CD*!6I*FyU39OP&yk9{iC32F69xq9)+>P4~oE9tlJjP(12T-z@TU0<^M8VYWY zskk(z!@QHhCLxD8>{4zyh!cL@(_b07LK00sCtus|_!8oGzpmw93GcFG*ZVC(fWr?$ z6?zV0HK0QWztOo*$hG6wV)Dl7=vO4M6jX64sKbtv!7(9++U|Dn%Tt&@(@2GT&lz)m zJvYuVW2o3PbS=3cIu*&5?|}6?DxHy?|a|d9rn|&_*p-`7-5Xf z)00m!#;-AEFERGUUAzg7dpiRixAGB^?rBEbAU#CBV3jZpDTugkN^2;orFe+1;J&_o z#c!|`2aOIMgESg6(~IjU4%FT}zH@J2F(mY1%D04;XD2V<`;av375{WkaS+g2nFgFu zKz7x)Y$^^cHs-_9xRAbT6ldeJ#c4o0EOh6tFEteh0UaEKB{-OlaA%UE14( z68d;d_1ME^RM6pCl*1k&&3&roZv8iRYdW_}_9mW_{fJN+N49SpDGuIYY)|da<^*iu z{v3y0LJ8|QpxW^eug64aRP$_LpcRvp>&CoXLi`yMdf~aBT~Zumzd(pf_(8~F=pokQ z0($tJ_9H^6pS<)tliRZ&VPGY}aXBI2t5?AZp@hc4e&X9bNTOwCwBaMhyq_*u7nnCW zwoRcMkA1~f>?rQzz?5`*X^Ydv5~68|Xs<+W)ZXUsizU)yZ%2{YCq5Sxw-lES&aFF1 z-XTjhm%CN1)OYHIoyvCYb-hxp;e+zp)y>P=XUzcqp<6!emf?4MVfV5&?Zb!V)x$r3 Sp`KfsX(Xe!PA8KIC;kU7VY8tC diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest1.capnp b/CapnpC.CSharp.Generator.Tests/No Resources/UnitTest1.capnp similarity index 100% rename from CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest1.capnp rename to CapnpC.CSharp.Generator.Tests/No Resources/UnitTest1.capnp diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/rpc-csharp.capnp b/CapnpC.CSharp.Generator.Tests/No Resources/rpc-csharp.capnp index fa0f149..730a740 100644 --- a/CapnpC.CSharp.Generator.Tests/No Resources/rpc-csharp.capnp +++ b/CapnpC.CSharp.Generator.Tests/No Resources/rpc-csharp.capnp @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Christian Köllner and contributors +# Copyright (c) 2020 Christian Köllner and contributors # This is a modified version of rpc.capnp, found in the original distribution # Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors # Licensed under the MIT License: @@ -110,6 +110,8 @@ # network at level 4. And since Cap'n Proto IPC is extremely fast, it may never make sense to # bother implementing any other vat network protocol -- just use the correct container type and get # it for free. +# $$embed +# #pragma warning disable CS1591 using CSharp = import "/csharp.capnp"; $CSharp.namespace("Capnp.Rpc"); diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/test.capnp b/CapnpC.CSharp.Generator.Tests/No Resources/test.capnp index 0a4a507..d68c71c 100644 --- a/CapnpC.CSharp.Generator.Tests/No Resources/test.capnp +++ b/CapnpC.CSharp.Generator.Tests/No Resources/test.capnp @@ -21,7 +21,7 @@ @0xd508eebdc2dc42b8; -using Cxx = import "c++.capnp"; +using Cxx = import "/capnp/c++.capnp"; # Use a namespace likely to cause trouble if the generated code doesn't use fully-qualified # names for stuff in the capnproto namespace. diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/annotated-json.binary b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/annotated-json.binary new file mode 100644 index 0000000000000000000000000000000000000000..6c54755184df36aa9d07ef4ee925a624db789ce5 GIT binary patch literal 544 zcmZuuK~BRk5Zt8YMkOv45+@68NWE}GLMq|`d;pLV*Kv$Y9J%hH;y;|Y@B^O4?7D_j zVwBlg+ncO+LPYccGUjwf@6Z`lbYBrIXN0Vxk6Ml;+#z0q|LFzlo)70mpX9BY4D=Rc zy#hC2jc*rxA>r?`UYAYiC&+gw=t7XRX|6lNk?o!63F3`pIp`2A&tRK4`hE6_Cz(%bIOQ8Z zf~O$QIkAxF`(=%70W3bk0xRyveW&2{IoKQT*@4`zmOA#8*W4$xuSTb1&v5jMF6IG8 Rzq9>e_s`wzH2;U<>krr}I0*m% literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/annotated.json b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/annotated.json new file mode 100644 index 0000000..bb51400 --- /dev/null +++ b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/annotated.json @@ -0,0 +1,22 @@ +{ "names-can_contain!anything Really": "foo", + "flatFoo": 123, + "flatBar": "abc", + "renamed-flatBaz": {"hello": true}, + "flatQux": "cba", + "pfx.foo": "this is a long string in order to force multi-line pretty printing", + "pfx.renamed-bar": 321, + "pfx.baz": {"hello": true}, + "pfx.xfp.qux": "fed", + "union-type": "renamed-bar", + "barMember": 789, + "multiMember": "ghi", + "dependency": {"renamed-foo": "corge"}, + "simpleGroup": {"renamed-grault": "garply"}, + "enums": ["qux", "renamed-bar", "foo", "renamed-baz"], + "innerJson": [123, "hello", {"object": true}], + "testBase64": "ZnJlZA==", + "testHex": "706c756768", + "bUnion": "renamed-bar", + "bValue": 678, + "externalUnion": {"type": "bar", "value": "cba"}, + "unionWithVoid": {"type": "voidValue"} } diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/binary b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/binary new file mode 100644 index 0000000000000000000000000000000000000000..ea39763774b2ed570407a3384a8865fbeaa79213 GIT binary patch literal 2816 zcmds&Ur1AN6vxkWS&HkAuIPW8=7SmHpCql9^$#>me6W{5?5dmphIhN$&20o*hW)W9 z1(Oo7dI`i#kfet)ETUCJ!Lqkly#!@FNCf?r+xOhv#rDvHK7{PRxu4(popUbt+ehzpE+zbwD zd;oSN5v{_*aeh>6qNpzG1xcmuYrwF4W#z9b*N4&@#Y9Iaq&J?aPY$Jt8Rm7*^>vQa zG2A91J+kFr_2uB5twod>%+<*6f$eOK{Jb2;&szwxpUHkE`%5(c9&iWj3a|vM1-U+_ z#x9WSdkx)y{ixInK6UAoJ<+Xsk?Y$PlTnT}f4{{d?N*oD+BpBG;kqJUeEzxrBSW$Z zcDvW~w>+L5mh^DI&kX59A1R>ttAu-Gd3Eh4wgQTx_`Popr^+2f`Eur5cmJHiu@LsL z_|vmU-3#gS*AOWR=TB{~Q%9BqqWPij&q;C%nn@G(v9MWsyT9V$2S=HQuitvi3_5R4j9o4opuy1t7<-%*0nF?ah^uhl!X%niZ4f?|@BY|1 zjLsv^nZqtOHG>|n&xbK1ceAXXwj9s%$2S-3_n4?*;H53<=6{-L1 kh0bLw-#9^p=Q5G%;kjJQ^~6slQH;&)9&2MNS(d8TKa`mRLjV8( literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/errors.capnp.nobuild b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/errors.capnp.nobuild new file mode 100644 index 0000000..a909e97 --- /dev/null +++ b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/errors.capnp.nobuild @@ -0,0 +1,161 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# This file is intended to test that various error cases are detected as errors. The error +# output is matched against a golden file. The file name has the .nobuild extension to make +# sure that a build system which automatically builds .capnp files does not try to build this one. + +# + +@0xccd0890aa4926a9b; +# Can't really test the missing-ID error because the output is intentionally unpredictable. + +const notType :Int32 = 123; +annotation notFieldAnnotation(struct) :Int32; +annotation fieldAnnotation(field) :Int32; + +struct Foo { + dupName @0 :Int32; + dupName @1 :Int32; + dupNumber1 @2 :Int32; + dupNumber2 @2 :Int32; + + missingNumber @4 :Int32; + next @5 :Int32; + + emptyUnion :union {} + emptyGroup :group {} + + singletonUnion :union { + field @6 :Int32; + } + + union { + dupName @7 :Int32; + f8 @8 :Int32; + } + union { + f9 @9 :Int32; + f10 @10 :Int32; + } + + struct wrongTypeStyle {} + WrongFieldStyle @11 :Int32; + under_score @12 :Int32; + + containsStruct :group { + f13 @13 :Int32; + struct CantNestHere {} + } + + retroUnion @16! :union { + f14 @14 :Int32; + f15 @15 :Int32; + } + + missingColonAndEclamation @18 union { + f19 @19 :Int32; + f20 @20 :Int32; + } + + missingExclamation @21 :union { + f22 @22 :Int32; + f23 @23 :Int32; + } + + missingColon @24! union { + f19 @25 :Int32; + f20 @26 :Int32; + } + + unnamedInNamed :union { + f27 @27 :Int32; + f28 @28 :Int32; + union { + # content is ignored + } + } + + listWithoutParam @31 :List; + listWithTooManyParams @32 :List(Int32, Int64); + listAnyPointer @33 :List(AnyPointer); + notAType @34 :notType; + noParams @35 :Foo(Int32); + + defaultOutOfRange @36 :Int16 = 1234567; + defaultOutOfRange2 @37 :UInt16 = -1; + defaultWrongType @38 :Text = 123; + defaultWrongType2 @39 :Text = [123]; + defaultWrongType3 @40 :Text = (foo = 123, bar = 456); + defaultTooBigToBeNegative @41 :Int64 = -0x8000000000000001; + defaultNotConstant @42 :Int32 = .Foo; + defaultConstantNotQualified @43 :Int32 = notType; + + notAnnotation @44 :Int32 $Foo(123); + badAnnotation @45 :Int32 $notFieldAnnotation(123); + notVoidAnnotation @46 :Int32 $fieldAnnotation; + + undefinedImport @17 :import "noshuchfile.capnp".Bar; + undefinedAbsolute @47 : .NoSuch; + undefinedRelative @29 :NoSuch; + undefinedMember @30 :Foo.NoSuch; +} + +struct Bar { + x @3 :Text; + someGroup :group { + defaultMissingFieldName @2 :Bar = (x = "abcd", 456); + defaultNoSuchField @0 :Bar = (nosuchfield = 123); + defaultGroupMismatch @1 :Bar = (someGroup = 123); + } +} + + +using Bar; + +enum DupEnumerants { + dupName @0; + dupName @1; + dupNumber1 @2; + dupNumber2 @2; +} + +const recursive: UInt32 = .recursive; + +struct Generic(T, U) { +} + +struct UseGeneric { + tooFew @0 :Generic(Text); + tooMany @1 :Generic(Text, Data, List(Int32)); + doubleBind @2 :Generic(Text, Data)(Data, Text); + primitiveBinding @3 :Generic(Text, Int32); +} + +const embedBadType :UInt32 = embed "binary"; +const embedNoSuchFile :Data = embed "no-such-file"; + +using Baz = import "nosuchfile-unused.capnp".Baz; +# Check that an import in an unused `using` still reports error. + +interface TestInterface { + foo @0 (a :UInt32 = null); +} diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/errors.txt b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/errors.txt new file mode 100644 index 0000000..ed238e4 --- /dev/null +++ b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/errors.txt @@ -0,0 +1,60 @@ +file:74:30-32: error: As of Cap'n Proto v0.3, it is no longer necessary to assign numbers to unions. However, removing the number will break binary compatibility. If this is an old protocol and you need to retain compatibility, please add an exclamation point after the number to indicate that it is really needed, e.g. `foo @1! :union {`. If this is a new protocol or compatibility doesn't matter, just remove the @n entirely. Sorry for the inconvenience, and thanks for being an early adopter! :) +file:74:30-32: error: As of Cap'n Proto v0.3, the 'union' keyword should be prefixed with a colon for named unions, e.g. `foo :union {`. +file:79:23-25: error: As of Cap'n Proto v0.3, it is no longer necessary to assign numbers to unions. However, removing the number will break binary compatibility. If this is an old protocol and you need to retain compatibility, please add an exclamation point after the number to indicate that it is really needed, e.g. `foo @1! :union {`. If this is a new protocol or compatibility doesn't matter, just remove the @n entirely. Sorry for the inconvenience, and thanks for being an early adopter! :) +file:84:17-19: error: As of Cap'n Proto v0.3, the 'union' keyword should be prefixed with a colon for named unions, e.g. `foo :union {`. +file:132:7-10: error: 'using' declaration without '=' must specify a named declaration from a different scope. +file:37:3-10: error: 'dupName' is already defined in this scope. +file:36:3-10: error: 'dupName' previously defined here. +file:52:5-12: error: 'dupName' is already defined in this scope. +file:36:3-10: error: 'dupName' previously defined here. +file:55:3-8: error: An unnamed union is already defined in this scope. +file:51:3-8: error: Previously defined here. +file:60:10-24: error: Type names must begin with a capital letter. +file:61:3-18: error: Non-type names must begin with a lower-case letter. +file:62:3-14: error: Cap'n Proto declaration names should use camelCase and must not contain underscores. (Code generators may convert names to the appropriate style for the target language.) +file:66:5-27: error: This kind of declaration doesn't belong here. +file:44:3-23: error: Union must have at least two members. +file:45:3-23: error: Group must have at least one member. +file:47: error: Union must have at least two members. +file:92: error: Unions cannot contain unnamed unions. +file:39:15-16: error: Duplicate ordinal number. +file:38:15-16: error: Ordinal @2 originally used here. +file:41:18-19: error: Skipped ordinal @3. Ordinals must be sequential with no holes. +file:69:15-17: error: Union ordinal, if specified, must be greater than no more than one of its member ordinals (i.e. there can only be one field retroactively unionized). +file:116:31-50: error: Import failed: noshuchfile.capnp +file:118:26-32: error: Not defined: NoSuch +file:119:28-34: error: 'Foo' has no member named 'NoSuch' +file:97:25-29: error: 'List' requires exactly one parameter. +file:98:30-48: error: Too many generic parameters. +file:98:30-34: error: 'List' requires exactly one parameter. +file:99:23-39: error: 'List(AnyPointer)' is not supported. +file:100:17-24: error: 'notType' is not a type. +file:101:17-27: error: Declaration does not accept generic parameters. +file:103:34-41: error: Integer value out of range. +file:104:37-38: error: Integer value out of range. +file:105:32-35: error: Type mismatch; expected Text. +file:106:33-38: error: Type mismatch; expected Text. +file:107:33-55: error: Type mismatch; expected Text. +file:108:43-61: error: Integer is too big to be negative. +file:109:35-39: error: '.Foo' does not refer to a constant. +file:110:44-51: error: Constant names must be qualified to avoid confusion. Please replace 'notType' with '.notType', if that's what you intended. +file:117:28-34: error: Not defined: NoSuch +file:112:29-32: error: 'Foo' is not an annotation. +file:113:29-47: error: 'notFieldAnnotation' cannot be applied to this kind of declaration. +file:114:33-48: error: 'fieldAnnotation' requires a value. +file:126:35-46: error: Struct has no field named 'nosuchfield'. +file:127:49-52: error: Type mismatch; expected group. +file:125:52-55: error: Missing field name. +file:136:3-10: error: 'dupName' is already defined in this scope. +file:135:3-10: error: 'dupName' previously defined here. +file:138:15-16: error: Duplicate ordinal number. +file:137:15-16: error: Ordinal @2 originally used here. +file:141:7-16: error: Declaration recursively depends on itself. +file:147:14-27: error: Not enough generic parameters. +file:148:15-47: error: Too many generic parameters. +file:149:18-49: error: Double-application of generic parameters. +file:150:38-43: error: Sorry, only pointer types can be used as generic parameters. +file:153:30-44: error: Embeds can only be used when Text, Data, or a struct is expected. +file:154:37-51: error: Couldn't read file for embed: no-such-file +file:160:23-27: error: Only pointer parameters can declare their default as 'null'. +file:156:20-45: error: Import failed: nosuchfile-unused.capnp diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/flat b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/flat new file mode 100644 index 0000000000000000000000000000000000000000..427fc31bcd157175204f62674277b46d9e518b2b GIT binary patch literal 2808 zcmds&Ur1AN6vxkWS&HkAuIPW8=7SmHpCql9^$#>me6W{5?5dmphIhN$&20o*hW)W9 z1(Oo7dI`i#kfet)ETUCJ!Lqkly#!@FNCf?r+xOhv#rDvHK7{PRxu4(popUa~vz_z1 zL_{fMBwbhV<@nG(<+SOG_s&H{nW6S^V{6)rP}-JH=Z9-XsCr=k62#KocT=6`CY~O` zG7HLF53Pjqd%BW|3a~x_nl)x<%+zSqxEkbm_A}YfOxI}8xD`B${T%QTxEUPQ_yFuk zB3gyRaeh>6qNpzG1xcmuYrwF4W#z9b*N4&@#Y9Iaq&J?aPY$Jt8Rm7*^>vQaF}x-s zJ+kFr_2uY@)*{Lb=4#~Mf$eOKd|r;@^A>{aXR@Ek{u0f<2iyU>0xSV*L9WlKu?yt- zUPCuvKPvTtPhC1?PjqWuP>Gd2FOHkcxzDP-c-v?lY$xY19T$YO=y^k_6fAj*pAx zWwBq79Cj~yU$8gwB-^A&H}KuCkUrgnIr1SlQDhQ@BvL)Ki@Y9>$>o;h2DiP%evB zFTMqxgQLvD*Ka*$2Awx2#x55P(BS9+j6Lp(0A_Xy#8bF$VG_-%HV7ZfcYo|0M(2^| z%wd@LVqDdg7;&D8}Y?kF_zCEKAkrA9dCO;{X5v literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/lists.binary b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/lists.binary new file mode 100644 index 0000000000000000000000000000000000000000..30ae630c0f45e88df949a57ef5f260cee53109c3 GIT binary patch literal 1096 zcmZQzU|{F~VhG@3Pz5sBffz)q1Fvp$^mr`BLgc?jS>*U=(PNNkT!;-#3C@w2_$8J7-X0Tl;#1_ zAU7}pF*6W@01FU<%=qNL2gGFn=>z#&6o~nNSQ5&I*#o1|?E{$$a!*oX6_7-@3#8r% zhzm)n}QR(sQZP($37r1oL!4K!2~>`NeabuYeLyxZMwZX>wM zuosI`FewqMFM*f|lJudB711h0VcEAZzXWALBLeNkPG?ghz3_Vu|NnCyc>d>>Hp6dD}wXgz) z-(%Vx*)_j_vo83t{H|l|WKyob*h1lC7Oyk!nw0}%vtK0<>y7cq9ToSUb;g2&yUAupjodtnshGBfGY6eVvF zHU&e1*ct*(u00qs*|r+?t%f6qf=Z~S_yO8id~*ROI&Uc}22cHvB?8Zj$Hh*%;_AVL z#=gN6#V^ujJtGtJi97dS;6&iw^yCfuFqj*eI2My;V>m9Q;_MSwJSD|bIKC=nb|aXf#5H+C(?W!>Erl+De+|{Xy&rx3MDmp8&cg!Q1L6t+4+K*O3mFE=?UI U+Hq)$ literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/packedflat b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/packedflat new file mode 100644 index 0000000000000000000000000000000000000000..7c304a9e5224fc543bdc3ae04427c82954fec965 GIT binary patch literal 828 zcmZ9JZAep57{|}q-Al8r>)n}QR(sQZP($37r1oL!4K!2~>`NeabuYdQ?{>GF+X(K> zuosI`FewqMFM*f|lJudB711h0VcEAZzXWALBLeNkPG?ghz3_Vu|NnCyc>d?sEA<%m zCg!I`k6`M8>09*SHH?=**Oa~^Yc82({Cs7saokWpd{pu0(NetU^7JdF*22{0HPk5e zsFx~5XDKs5M?eHUA&2-n0wQP#T0#N3L|M^w%7DfwgX1aHEkld~0ig17oT`Q8G5juR zcVyT60?xY7$MU<5wUbG?{$dM-lUbb3ylYktjLiY{q-?2QaQ(M|73Lx{EF@S6`Gf*w zg;r!E+D5dE=rW=Y!TqQjmZ2tSKtX75^g^=1TiI^1K?@sG1%(JuFtwEcG*l_|AlupH z357lGw8sM-<~^+6A2oFWW5$Mgv}REfzb56$PZAba>e$DwH@APTN*H6&8GWxkUlqV5 z0$S@ETEjp}+nG-U+cg$EpOlyE#5g?_-`A{2rCS?AVzTdxOlX$@us%R4NR>Yrs>aV| zQfCOi;qsnsGC~iz;#%xJXV$$tEHCWOfBoU*X>sGk11t3hMk8LZaY~H3h*8@abtN4X zgov?~<9!~dk7oscIOCJ9#pz@DfIn*NX8mrC_VONggND3>0_}w{kju=ZOH+)zMZ^>e z^FnJFIQ{LRu*tU7ux~XSITTbvHN_3kzT%q;IMI1aSuuF(hb$3%UOX;z(iK+^E;RNH zrYLTaF6$YYpikVn{{kn1_ogRr*oVQ~$iy*8oRx4~OvTwJu6Rm}r*M2#%Mx!gFIoTq literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/pretty.json b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/pretty.json new file mode 100644 index 0000000..abf82d6 --- /dev/null +++ b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/pretty.json @@ -0,0 +1,88 @@ +{ "voidField": null, + "boolField": true, + "int8Field": -123, + "int16Field": -12345, + "int32Field": -12345678, + "int64Field": "-123456789012345", + "uInt8Field": 234, + "uInt16Field": 45678, + "uInt32Field": 3456789012, + "uInt64Field": "12345678901234567890", + "float32Field": 1234.5, + "float64Field": -1.23e47, + "textField": "foo", + "dataField": [98, 97, 114], + "structField": { + "voidField": null, + "boolField": true, + "int8Field": -12, + "int16Field": 3456, + "int32Field": -78901234, + "int64Field": "56789012345678", + "uInt8Field": 90, + "uInt16Field": 1234, + "uInt32Field": 56789012, + "uInt64Field": "345678901234567890", + "float32Field": -1.2499999646475857e-10, + "float64Field": 345, + "textField": "baz", + "dataField": [113, 117, 120], + "structField": { + "voidField": null, + "boolField": false, + "int8Field": 0, + "int16Field": 0, + "int32Field": 0, + "int64Field": "0", + "uInt8Field": 0, + "uInt16Field": 0, + "uInt32Field": 0, + "uInt64Field": "0", + "float32Field": 0, + "float64Field": 0, + "textField": "nested", + "structField": {"voidField": null, "boolField": false, "int8Field": 0, "int16Field": 0, "int32Field": 0, "int64Field": "0", "uInt8Field": 0, "uInt16Field": 0, "uInt32Field": 0, "uInt64Field": "0", "float32Field": 0, "float64Field": 0, "textField": "really nested", "enumField": "foo", "interfaceField": null}, + "enumField": "foo", + "interfaceField": null }, + "enumField": "baz", + "interfaceField": null, + "voidList": [null, null, null], + "boolList": [false, true, false, true, true], + "int8List": [12, -34, -128, 127], + "int16List": [1234, -5678, -32768, 32767], + "int32List": [12345678, -90123456, -2147483648, 2147483647], + "int64List": ["123456789012345", "-678901234567890", "-9223372036854775808", "9223372036854775807"], + "uInt8List": [12, 34, 0, 255], + "uInt16List": [1234, 5678, 0, 65535], + "uInt32List": [12345678, 90123456, 0, 4294967295], + "uInt64List": ["123456789012345", "678901234567890", "0", "18446744073709551615"], + "float32List": [0, 1234567, 9.9999999338158125e36, -9.9999999338158125e36, 9.99999991097579e-38, -9.99999991097579e-38], + "float64List": [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], + "textList": ["quux", "corge", "grault"], + "dataList": [[103, 97, 114, 112, 108, 121], [119, 97, 108, 100, 111], [102, 114, 101, 100]], + "structList": [ + {"voidField": null, "boolField": false, "int8Field": 0, "int16Field": 0, "int32Field": 0, "int64Field": "0", "uInt8Field": 0, "uInt16Field": 0, "uInt32Field": 0, "uInt64Field": "0", "float32Field": 0, "float64Field": 0, "textField": "x structlist 1", "enumField": "foo", "interfaceField": null}, + {"voidField": null, "boolField": false, "int8Field": 0, "int16Field": 0, "int32Field": 0, "int64Field": "0", "uInt8Field": 0, "uInt16Field": 0, "uInt32Field": 0, "uInt64Field": "0", "float32Field": 0, "float64Field": 0, "textField": "x structlist 2", "enumField": "foo", "interfaceField": null}, + {"voidField": null, "boolField": false, "int8Field": 0, "int16Field": 0, "int32Field": 0, "int64Field": "0", "uInt8Field": 0, "uInt16Field": 0, "uInt32Field": 0, "uInt64Field": "0", "float32Field": 0, "float64Field": 0, "textField": "x structlist 3", "enumField": "foo", "interfaceField": null} ], + "enumList": ["qux", "bar", "grault"] }, + "enumField": "corge", + "interfaceField": null, + "voidList": [null, null, null, null, null, null], + "boolList": [true, false, false, true], + "int8List": [111, -111], + "int16List": [11111, -11111], + "int32List": [111111111, -111111111], + "int64List": ["1111111111111111111", "-1111111111111111111"], + "uInt8List": [111, 222], + "uInt16List": [33333, 44444], + "uInt32List": [3333333333], + "uInt64List": ["11111111111111111111"], + "float32List": [5555.5, "Infinity", "-Infinity", "NaN"], + "float64List": [7777.75, "Infinity", "-Infinity", "NaN"], + "textList": ["plugh", "xyzzy", "thud"], + "dataList": [[111, 111, 112, 115], [101, 120, 104, 97, 117, 115, 116, 101, 100], [114, 102, 99, 51, 48, 57, 50]], + "structList": [ + {"voidField": null, "boolField": false, "int8Field": 0, "int16Field": 0, "int32Field": 0, "int64Field": "0", "uInt8Field": 0, "uInt16Field": 0, "uInt32Field": 0, "uInt64Field": "0", "float32Field": 0, "float64Field": 0, "textField": "structlist 1", "enumField": "foo", "interfaceField": null}, + {"voidField": null, "boolField": false, "int8Field": 0, "int16Field": 0, "int32Field": 0, "int64Field": "0", "uInt8Field": 0, "uInt16Field": 0, "uInt32Field": 0, "uInt64Field": "0", "float32Field": 0, "float64Field": 0, "textField": "structlist 2", "enumField": "foo", "interfaceField": null}, + {"voidField": null, "boolField": false, "int8Field": 0, "int16Field": 0, "int32Field": 0, "int64Field": "0", "uInt8Field": 0, "uInt16Field": 0, "uInt32Field": 0, "uInt64Field": "0", "float32Field": 0, "float64Field": 0, "textField": "structlist 3", "enumField": "foo", "interfaceField": null} ], + "enumList": ["foo", "garply"] } diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/pretty.txt b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/pretty.txt new file mode 100644 index 0000000..079ff8d --- /dev/null +++ b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/pretty.txt @@ -0,0 +1,187 @@ +( voidField = void, + boolField = true, + int8Field = -123, + int16Field = -12345, + int32Field = -12345678, + int64Field = -123456789012345, + uInt8Field = 234, + uInt16Field = 45678, + uInt32Field = 3456789012, + uInt64Field = 12345678901234567890, + float32Field = 1234.5, + float64Field = -1.23e47, + textField = "foo", + dataField = "bar", + structField = ( + voidField = void, + boolField = true, + int8Field = -12, + int16Field = 3456, + int32Field = -78901234, + int64Field = 56789012345678, + uInt8Field = 90, + uInt16Field = 1234, + uInt32Field = 56789012, + uInt64Field = 345678901234567890, + float32Field = -1.25e-10, + float64Field = 345, + textField = "baz", + dataField = "qux", + structField = ( + voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "nested", + structField = ( + voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "really nested", + enumField = foo, + interfaceField = void ), + enumField = foo, + interfaceField = void ), + enumField = baz, + interfaceField = void, + voidList = [void, void, void], + boolList = [false, true, false, true, true], + int8List = [12, -34, -128, 127], + int16List = [1234, -5678, -32768, 32767], + int32List = [12345678, -90123456, -2147483648, 2147483647], + int64List = [123456789012345, -678901234567890, -9223372036854775808, 9223372036854775807], + uInt8List = [12, 34, 0, 255], + uInt16List = [1234, 5678, 0, 65535], + uInt32List = [12345678, 90123456, 0, 4294967295], + uInt64List = [123456789012345, 678901234567890, 0, 18446744073709551615], + float32List = [0, 1234567, 1e37, -1e37, 1e-37, -1e-37], + float64List = [0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306], + textList = ["quux", "corge", "grault"], + dataList = ["garply", "waldo", "fred"], + structList = [ + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "x structlist 1", + enumField = foo, + interfaceField = void ), + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "x structlist 2", + enumField = foo, + interfaceField = void ), + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "x structlist 3", + enumField = foo, + interfaceField = void ) ], + enumList = [qux, bar, grault] ), + enumField = corge, + interfaceField = void, + voidList = [void, void, void, void, void, void], + boolList = [true, false, false, true], + int8List = [111, -111], + int16List = [11111, -11111], + int32List = [111111111, -111111111], + int64List = [1111111111111111111, -1111111111111111111], + uInt8List = [111, 222], + uInt16List = [33333, 44444], + uInt32List = [3333333333], + uInt64List = [11111111111111111111], + float32List = [5555.5, inf, -inf, nan], + float64List = [7777.75, inf, -inf, nan], + textList = ["plugh", "xyzzy", "thud"], + dataList = ["oops", "exhausted", "rfc3092"], + structList = [ + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "structlist 1", + enumField = foo, + interfaceField = void ), + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "structlist 2", + enumField = foo, + interfaceField = void ), + ( voidField = void, + boolField = false, + int8Field = 0, + int16Field = 0, + int32Field = 0, + int64Field = 0, + uInt8Field = 0, + uInt16Field = 0, + uInt32Field = 0, + uInt64Field = 0, + float32Field = 0, + float64Field = 0, + textField = "structlist 3", + enumField = foo, + interfaceField = void ) ], + enumList = [foo, garply] ) diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/segmented b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/segmented new file mode 100644 index 0000000000000000000000000000000000000000..c2840b426768c0d27fffbed324b0c4893c64c48b GIT binary patch literal 5520 zcmeI0X>3$g6vtl|E7TUS)CEPE7E!TSu@z}u;sj6uu~aQCxRlp2Gc6rE>$B6^q>~!d zRHKj(qJ*G+F)@fFMB)dRG{#spMw5|`ruxN1(GQI=aV5|5d+)sFF^Q=&CfXEFa^C;m z|2_AfbMD-&9X1T3MD!xXQXkI5(T;t-GM;}NukP8E|IPL?wX0C1?v0g?j6GBPR|V_I{_^XE+Ie#@Q_TMMd>_<{&51c37A@I5@%gbs>+PokKMub2yltN}`j6G_ zs{AZhx$OIAU+Xw*v>(`Tme?6@e?30>%<+%uM@%3*c)Q|8#m$Oa6x$Tr74KH;P`p?1 ze#PyI4=FyP7*_0898`Q<(35a1<`n&NRWD4JnVjaCdwxHD|B|1w)e9DF`MoXmZOg08 zhOynqmDfJqRhFxa)zmHdw7fGu|0rWQvd0RN?>tekQn5yHvEq4(7bq@KyjbxP#bt_h zipv#OC|;qsQt?{FR>cj9w+VXEWezz-Vm@1xJjp*{W#sGb%lU#{{tj8dhrFwO_SDby z)&J{ae<+m>?R4|3l3>X5h9ZI@uSG@l`?tCzLuNEO81T|{&fA6JoP1g7{Qe6>kqV>M zsh{IkojPk5!Tv%~_5wn`T2Xk`UDafEM8M(C7lda$<;rv48CiP-d-}t(e%s7MPP{2^G|EboBKDt|L)YV=pQGS&MOri z#qM&oyAC6j;N-v)bv0kETe)ZXC*OSZ*odON_viMthcaP9F-!j|Me(ynl=Zesu~Big zV8U`YF7^$g*k2{u9ZN<+g78<1!Z(RVlBN|+yZklEv;MK8A9l_mVkYBJ zIaslm<8XT10W-RjlNFwLy*R>2cALwuRlZ*9#N+v6FR~5`72> zI$yrjInT*|Kq_TYVh_UKsyy#Z>hK8XuK&L0Uf~UhV7Ez>@#;ild*vene}^c1jcBCd z#S;P!f2SZk@7;;MmnvHK?f4b@t;%!CPb5BQIBfMTY<=#=6CGpwrf9!Q+j$?yCgmdn ze~+l=XU*urBObp^dHig9<&6(L{yycoQzjCxA3yp+(*eeLKzZkVdhm!$2XB|GydTD$ zcg2I+&i#&zo9_jkf-xm_$duS3zc}^}ONqEvh%%R^Vz(mqZ#-&6dIa&mLlk@Nz0Bay zkX)k<-{s@eJ=XMnNdbHAW%_q&-MgQArHqSGE9@BE4zEX4B zcL~zISu`2$ZeHEmxz}i-jBro? E3Es02*Z=?k literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/testdata/segmented-packed b/CapnpC.CSharp.Generator.Tests/No Resources/testdata/segmented-packed new file mode 100644 index 0000000000000000000000000000000000000000..c4a968e2654e699e0dce86ece395e1b3fe783139 GIT binary patch literal 1352 zcmZvcdu&rx9LLZ3wfl{YjqclZxD8zQ0Cf!K9!xgWbm1i+ZbOF;e2i}Ex<_5NuGh75 zNt+qeOe2sGqJ*ISV`30Vh{Qj9q%p>+A&^x5G?RZ!6isZ53HX@T-@R>cL~hRg-E)4A z?>YB#&b^q`sMH{7mC$50Ygh>)yJbUSW$3iiZuA`>203z7Qg~Cp89#_vzO%{c&Yjw3I$o~+E&kDA)4Zz2&v`}*FQyB< zKfm@~@9CJ@Ppu8;632I;4W|v_z`d~_%ZMk-~-^N!Owz+ zz~kUJ_ywi%hr(fd$+h|Y{)k0GSDO0wWbvw!y?-fR*VK>g@3t--NIN~R^gGOSVc1<$ zalxs)eG>&|>B7oa1FQ)ydHcfxE|aL?f`EG@07Xw z{WG9^=-T{ABL*svxs|*|u~J~D65n`WDjFCB6+v&Y0wv0AMgsm&C|*6Tyt$wYTGqX) zhdrQ`Vs#;OxfYxr=z3StVln|*Epz;ucBX$ynldVfuDjOd|D^NVxBtAJG)>DV$7G!^ z{(bRFyC%#=qjYKh_>!rTR?xl@3bYn_{mP_q-0+ad#s&! zK$U|#EwfFzRfQR=o{C0{fvEC@My8_G&7k|CXZ{~(0r_qjXa#MR0BB3Io~AN~mXB}; z^cwjZb9>sP3qZS}YaHRDpogH{u3*EPmq8ChmzoP>Z*j-5gMSFzZfK9WF!@EpX=BW# zJ6^x%?1v|nmn```KCOVH!cMN;^J1RD=oRB(0dY*p@G(>4nY>Ow=B4f xf5bv>SSDuk&(aT#C|8#LB=o4zzsW5^(ObBM{Is}1VT-&oA2cIS Generate() diff --git a/CapnpC.CSharp.Generator/Model/GenFile.cs b/CapnpC.CSharp.Generator/Model/GenFile.cs index ac0c35d..468315e 100644 --- a/CapnpC.CSharp.Generator/Model/GenFile.cs +++ b/CapnpC.CSharp.Generator/Model/GenFile.cs @@ -14,6 +14,7 @@ namespace CapnpC.CSharp.Generator.Model public bool? NullableEnable { get; set; } public bool EmitNullableDirective { get; set; } public bool EmitDomainClassesAndInterfaces { get; set; } + public string HeaderText { get; set; } public SupportedAnnotations.TypeVisibility TypeVisibility { get; set; } public IEnumerable NestedTypes { get => this.GetNestedTypes(); } diff --git a/CapnpC.CSharp.Generator/Model/SchemaModel.cs b/CapnpC.CSharp.Generator/Model/SchemaModel.cs index 8213ffd..2b75e7c 100644 --- a/CapnpC.CSharp.Generator/Model/SchemaModel.cs +++ b/CapnpC.CSharp.Generator/Model/SchemaModel.cs @@ -13,6 +13,7 @@ namespace CapnpC.CSharp.Generator.Model readonly DefinitionManager _typeDefMgr = new DefinitionManager(); readonly Dictionary _id2node = new Dictionary(); + readonly Dictionary _id2sourceInfo = new Dictionary(); public SchemaModel(Schema.CodeGeneratorRequest.Reader request) { @@ -51,6 +52,17 @@ namespace CapnpC.CSharp.Generator.Model _id2node[node.Id] = node; } + foreach (var reader in _request.SourceInfo) + { + var sourceInfo = new SourceInfo() + { + DocComment = reader.DocComment, + MemberDocComments = reader.Members.Select(m => m.DocComment).ToList() + }; + + _id2sourceInfo.Add(reader.Id, sourceInfo); + } + var requestedFiles = _request.RequestedFiles.ToDictionary(req => req.Id); BuildPass1(requestedFiles); BuildPass2(requestedFiles); @@ -96,6 +108,10 @@ namespace CapnpC.CSharp.Generator.Model file.EmitNullableDirective = GetEmitNullableDirective(node) ?? false; file.EmitDomainClassesAndInterfaces = GetEmitDomainClassesAndInterfaces(node) ?? true; file.TypeVisibility = GetTypeVisibility(node) ?? TypeVisibility.Public; + if (_id2sourceInfo.TryGetValue(node.Id, out var sourceInfo)) + { + file.HeaderText = GetHeaderText(sourceInfo); + } return ProcessNodePass1(id, name, state) as GenFile; } diff --git a/CapnpC.CSharp.Generator/Model/SourceInfo.cs b/CapnpC.CSharp.Generator/Model/SourceInfo.cs new file mode 100644 index 0000000..28ac508 --- /dev/null +++ b/CapnpC.CSharp.Generator/Model/SourceInfo.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CapnpC.CSharp.Generator.Model +{ + class SourceInfo + { + public string DocComment { get; set; } + public IReadOnlyList MemberDocComments { get; set; } + } +} diff --git a/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs b/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs index cd78387..5985170 100644 --- a/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs +++ b/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace CapnpC.CSharp.Generator.Model @@ -130,5 +131,19 @@ namespace CapnpC.CSharp.Generator.Model } return null; } + + public static string GetHeaderText(SourceInfo sourceInfo) + { + if (sourceInfo.DocComment == null) + return null; + + var lines = sourceInfo.DocComment + .Split('\n') + .Select(line => line.Trim()) + .SkipWhile(line => !line.Equals("$$embed", StringComparison.OrdinalIgnoreCase)) + .Skip(1); + + return string.Join(Environment.NewLine, lines); + } } } diff --git a/include/capnp/c++.capnp b/include/capnp/c++.capnp new file mode 100644 index 0000000..2bda547 --- /dev/null +++ b/include/capnp/c++.capnp @@ -0,0 +1,26 @@ +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xbdf87d7bb8304e81; +$namespace("capnp::annotations"); + +annotation namespace(file): Text; +annotation name(field, enumerant, struct, enum, interface, method, param, group, union): Text; diff --git a/scripts/regen-capnpbin.bat b/scripts/regen-capnpbin.bat new file mode 100644 index 0000000..aa4d9bb --- /dev/null +++ b/scripts/regen-capnpbin.bat @@ -0,0 +1,3 @@ +@echo off +cd "%~dp0\..\CapnpC.CSharp.Generator.Tests\No Resources" +for /f %%f in ('dir /b "*.capnp"') do capnp compile -o- %%f -I"..\..\include" > "..\Embedded Resources\%%f.bin" \ No newline at end of file From c1e8ed6d655041950a5e70eeae46641ff40f49bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sat, 18 Apr 2020 15:28:12 +0200 Subject: [PATCH 52/76] added missing documentation --- Capnp.Net.Runtime/DynamicSerializerState.cs | 5 +++++ Capnp.Net.Runtime/Rpc/Impatient.cs | 10 ++++++++++ Capnp.Net.Runtime/SerializerState.cs | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/Capnp.Net.Runtime/DynamicSerializerState.cs b/Capnp.Net.Runtime/DynamicSerializerState.cs index d6092c6..dccfd69 100644 --- a/Capnp.Net.Runtime/DynamicSerializerState.cs +++ b/Capnp.Net.Runtime/DynamicSerializerState.cs @@ -89,6 +89,11 @@ namespace Capnp /// The object type was already set to something different public new void SetStruct(ushort dataCount, ushort ptrCount) => base.SetStruct(dataCount, ptrCount); + /// + /// Determines the underyling object to be a capability. + /// + /// Capability table index, or null to encode a null pointer + /// The object type was already set to something different public new void SetCapability(uint? capabilityIndex) => base.SetCapability(capabilityIndex); /// diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index a7be980..1376a3c 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -156,6 +156,16 @@ namespace Capnp.Rpc } } + /// + /// Unwraps given capability. Unwrapping walks the chain of promised capabilities and awaits their resolutions, + /// until we get the finally resolved capability. If it is the capability, the method returns a null reference. + /// If the capability is broken (resolved to exception, dependent answer faulted or cancelled, RPC endpoint closed), + /// it throws an exception. + /// + /// Capability interface + /// capability to unwrap + /// Task returning the eventually resolved capability + /// Capability is broken public static async Task Unwrap(this TInterface cap) where TInterface: class, IDisposable { using var proxy = cap as Proxy; diff --git a/Capnp.Net.Runtime/SerializerState.cs b/Capnp.Net.Runtime/SerializerState.cs index cb219d1..629f940 100644 --- a/Capnp.Net.Runtime/SerializerState.cs +++ b/Capnp.Net.Runtime/SerializerState.cs @@ -497,6 +497,11 @@ namespace Capnp } } + /// + /// Determines the underyling object to be a capability. + /// + /// Capability table index, or null to encode a null pointer + /// The object type was already set to something different protected void SetCapability(uint? capabilityIndex) { if (capabilityIndex.HasValue) From c3cbb123c8c8638ff74326bb94034328e0e9ca9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 19 Apr 2020 16:16:48 +0200 Subject: [PATCH 53/76] refactored codegen to use generated schema fixed issue #45 refactored codegen unit tests fixed appveyor.yml --- Capnp.Net.Runtime.Tests/ImpatientTests.cs | 4 + .../Mock/TestCapImplementations.cs | 2 +- Capnp.Net.Runtime.Tests/SerializationTests.cs | 2 + Capnp.Net.Runtime.Tests/TcpRpc.cs | 2 + Capnp.Net.Runtime.Tests/Util/TestBase.cs | 2 + Capnp.Net.Runtime/CapnpSerializable.cs | 11 + Capnp.Net.Runtime/Rpc/Impatient.cs | 2 +- Capnp.Net.Runtime/Rpc/NoResultsException.cs | 16 + .../Rpc/TailCallNoDataException.cs | 9 - .../CodeGenerator.feature | 3 +- .../CodeGenerator.feature.cs | 15 + .../CodeGeneratorUnitTests.cs | 54 +- .../Embedded Resources/Issue45.capnp.bin | Bin 0 -> 3360 bytes .../Embedded Resources/UnitTest1.capnp.bin | Bin 816 -> 816 bytes .../Embedded Resources/UnitTest10.capnp.bin | Bin 1600 -> 1616 bytes .../Embedded Resources/UnitTest10b.capnp.bin | Bin 0 -> 1040 bytes .../Embedded Resources/UnitTest11.capnp.bin | Bin 2408 -> 2080 bytes .../Embedded Resources/UnitTest11b.capnp.bin | Bin 0 -> 1184 bytes .../Embedded Resources/UnitTest12.capnp.bin | Bin 1392 -> 1504 bytes .../Embedded Resources/UnitTest13.capnp.bin | Bin 1320 -> 1256 bytes .../Embedded Resources/UnitTest14.capnp.bin | Bin 1888 -> 1824 bytes .../Embedded Resources/UnitTest15.capnp.bin | Bin 4728 -> 4240 bytes .../Embedded Resources/UnitTest2.capnp.bin | Bin 2608 -> 2608 bytes .../Embedded Resources/UnitTest20.capnp.bin | Bin 736 -> 736 bytes .../Embedded Resources/UnitTest3.capnp.bin | Bin 848 -> 848 bytes .../Embedded Resources/UnitTest4.capnp.bin | Bin 3600 -> 3304 bytes .../Embedded Resources/UnitTest4b.capnp.bin | Bin 0 -> 3736 bytes .../schema-csharp.capnp.bin | Bin 0 -> 42168 bytes .../No Resources/schema-csharp.capnp | 537 ++ CapnpC.CSharp.Generator/CapnpCompilation.cs | 2 +- .../CodeGen/CommonSnippetGen.cs | 2 +- CapnpC.CSharp.Generator/Model/SchemaModel.cs | 277 +- .../Model/SupportedAnnotations.cs | 36 +- .../Schema/SchemaSerialization.cs | 5782 ++++++++++++----- appveyor.yml | 8 +- 35 files changed, 5098 insertions(+), 1668 deletions(-) create mode 100644 Capnp.Net.Runtime/Rpc/NoResultsException.cs delete mode 100644 Capnp.Net.Runtime/Rpc/TailCallNoDataException.cs create mode 100644 CapnpC.CSharp.Generator.Tests/Embedded Resources/Issue45.capnp.bin create mode 100644 CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest10b.capnp.bin create mode 100644 CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest11b.capnp.bin create mode 100644 CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest4b.capnp.bin create mode 100644 CapnpC.CSharp.Generator.Tests/Embedded Resources/schema-csharp.capnp.bin create mode 100644 CapnpC.CSharp.Generator.Tests/No Resources/schema-csharp.capnp diff --git a/Capnp.Net.Runtime.Tests/ImpatientTests.cs b/Capnp.Net.Runtime.Tests/ImpatientTests.cs index 551c242..a009a43 100644 --- a/Capnp.Net.Runtime.Tests/ImpatientTests.cs +++ b/Capnp.Net.Runtime.Tests/ImpatientTests.cs @@ -162,10 +162,12 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void ObsoleteGetAnswer() { +#pragma warning disable CS0618 var answer = new PromisedAnswerMock(); Assert.ThrowsException(() => Impatient.GetAnswer(answer.WhenReturned)); var t = Impatient.MakePipelineAware(answer, _ => _); Assert.AreEqual(answer, Impatient.GetAnswer(t)); +#pragma warning restore CS0618 } [TestMethod] @@ -182,8 +184,10 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void ObsoletePseudoEager() { +#pragma warning disable CS0618 var task = Task.FromResult(new TestInterfaceImpl2()); Assert.IsTrue(task.PseudoEager() is Proxy proxy && proxy.WhenResolved.IsCompleted); +#pragma warning restore CS0618 } [TestMethod] diff --git a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs index 3c5093e..7f1cac5 100644 --- a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs @@ -718,7 +718,7 @@ namespace Capnp.Net.Runtime.Tests.GenImpls await task2; Assert.Fail("Not a tail call"); } - catch (TailCallNoDataException) + catch (NoResultsException) { } } diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs index ad40dc2..0e53fb1 100644 --- a/Capnp.Net.Runtime.Tests/SerializationTests.cs +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -1198,7 +1198,9 @@ namespace Capnp.Net.Runtime.Tests var p2 = (Proxy)Proxy.Share(impl); Assert.AreEqual(0u, dss.ProvideCapability(p1)); Assert.AreEqual(0u, dss.ProvideCapability(p2.ConsumedCap)); +#pragma warning disable CS0618 // Typ oder Element ist veraltet Assert.AreEqual(0u, dss.ProvideCapability(CapabilityReflection.CreateSkeleton(impl))); +#pragma warning restore CS0618 // Typ oder Element ist veraltet Assert.IsTrue(p1.IsDisposed); Assert.IsFalse(p2.IsDisposed); p2.Dispose(); diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index 0714581..0a99b2e 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -35,6 +35,7 @@ namespace Capnp.Net.Runtime.Tests ExpectingLogOutput = true; Logging.LoggerFactory?.Dispose(); +#pragma warning disable CS0618 // Typ oder Element ist veraltet Logging.LoggerFactory = new LoggerFactory().AddConsole((msg, level) => { if (!ExpectingLogOutput && level != LogLevel.Debug) @@ -43,6 +44,7 @@ namespace Capnp.Net.Runtime.Tests } return true; }); +#pragma warning restore CS0618 // Typ oder Element ist veraltet } int MediumNonDbgTimeout => Debugger.IsAttached ? Timeout.Infinite : 2000; diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index c44df31..2b08763 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -412,7 +412,9 @@ namespace Capnp.Net.Runtime.Tests public void InitConsoleLogging() { Logging.LoggerFactory?.Dispose(); +#pragma warning disable CS0618 // Typ oder Element ist veraltet Logging.LoggerFactory = new LoggerFactory().AddConsole((msg, level) => true); +#pragma warning restore CS0618 // Typ oder Element ist veraltet Logger = Logging.CreateLogger(); if (Thread.CurrentThread.Name == null) Thread.CurrentThread.Name = $"Test Thread {Thread.CurrentThread.ManagedThreadId}"; diff --git a/Capnp.Net.Runtime/CapnpSerializable.cs b/Capnp.Net.Runtime/CapnpSerializable.cs index ec7cb48..91a2d97 100644 --- a/Capnp.Net.Runtime/CapnpSerializable.cs +++ b/Capnp.Net.Runtime/CapnpSerializable.cs @@ -55,11 +55,22 @@ namespace Capnp } } + static object? CreateFromAny(DeserializerState state) + { + switch (state.Kind) + { + case ObjectKind.Capability: return state.RequireCap(); + case ObjectKind.Nil: return null; + default: return state; + } + } + static readonly ConditionalWeakTable> _typeMap = new ConditionalWeakTable>(); static CapnpSerializable() { + _typeMap.Add(typeof(object), CreateFromAny); _typeMap.Add(typeof(string), d => d.RequireList().CastText()); _typeMap.Add(typeof(IReadOnlyList), d => d.RequireList().CastBool()); _typeMap.Add(typeof(IReadOnlyList), d => d.RequireList().CastSByte()); diff --git a/Capnp.Net.Runtime/Rpc/Impatient.cs b/Capnp.Net.Runtime/Rpc/Impatient.cs index 1376a3c..c3a3804 100644 --- a/Capnp.Net.Runtime/Rpc/Impatient.cs +++ b/Capnp.Net.Runtime/Rpc/Impatient.cs @@ -29,7 +29,7 @@ namespace Capnp.Rpc { var result = await promise.WhenReturned; if (promise.IsTailCall) - throw new TailCallNoDataException(); + throw new NoResultsException(); return then(result); } diff --git a/Capnp.Net.Runtime/Rpc/NoResultsException.cs b/Capnp.Net.Runtime/Rpc/NoResultsException.cs new file mode 100644 index 0000000..5bb0269 --- /dev/null +++ b/Capnp.Net.Runtime/Rpc/NoResultsException.cs @@ -0,0 +1,16 @@ +namespace Capnp.Rpc +{ + /// + /// Thrown when a pending question did return, but was not configured to deliver the result back to the sender + /// (typcial for tail calls). + /// + public class NoResultsException: System.Exception + { + /// + /// Creates an instance + /// + public NoResultsException(): base("Pending question did return, but was not configured to deliver the result back to the sender") + { + } + } +} \ No newline at end of file diff --git a/Capnp.Net.Runtime/Rpc/TailCallNoDataException.cs b/Capnp.Net.Runtime/Rpc/TailCallNoDataException.cs deleted file mode 100644 index ef16c27..0000000 --- a/Capnp.Net.Runtime/Rpc/TailCallNoDataException.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Capnp.Rpc -{ - public class TailCallNoDataException: System.Exception - { - public TailCallNoDataException(): base("Because the question was asked as tail call, it won't return data") - { - } - } -} \ No newline at end of file diff --git a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature index 7baa276..2da098b 100644 --- a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature +++ b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature @@ -71,4 +71,5 @@ Examples: | NullableDisable2.capnp.bin | false | true | success | | NullableEnable2.capnp.bin | false | false | errors | | NullableEnable2.capnp.bin | false | true | success | - | rpc-csharp.capnp.bin | true | true | warnings | \ No newline at end of file + | rpc-csharp.capnp.bin | true | true | warnings | + | schema-csharp.capnp.bin | false | false | success | \ No newline at end of file diff --git a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs index 10e1f06..8070e3f 100644 --- a/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs +++ b/CapnpC.CSharp.Generator.Tests/CodeGenerator.feature.cs @@ -662,6 +662,21 @@ this.ValidGeneratorOutput("NullableEnable2.capnp.bin", "false", "true", "success { #line 50 this.ValidGeneratorOutput("rpc-csharp.capnp.bin", "true", "true", "warnings", ((string[])(null))); +#line hidden + } + + [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()] + [Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Valid generator output: Variant 16")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("FeatureTitle", "CodeGenerator")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("VariantName", "Variant 16")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:bin", "schema-csharp.capnp.bin")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:nullablegen", "false")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:nullablesupp", "false")] + [Microsoft.VisualStudio.TestTools.UnitTesting.TestPropertyAttribute("Parameter:outcome", "success")] + public virtual void ValidGeneratorOutput_Variant16() + { +#line 50 +this.ValidGeneratorOutput("schema-csharp.capnp.bin", "false", "false", "success", ((string[])(null))); #line hidden } } diff --git a/CapnpC.CSharp.Generator.Tests/CodeGeneratorUnitTests.cs b/CapnpC.CSharp.Generator.Tests/CodeGeneratorUnitTests.cs index 4ccbd9b..9f71803 100644 --- a/CapnpC.CSharp.Generator.Tests/CodeGeneratorUnitTests.cs +++ b/CapnpC.CSharp.Generator.Tests/CodeGeneratorUnitTests.cs @@ -45,13 +45,13 @@ namespace CapnpC.CSharp.Generator.Tests [TestMethod] public void Test04MutualDependencies() { - LoadAndGenerate("UnitTest4.capnp.bin"); + LoadAndGenerate("UnitTest4.capnp.bin", "UnitTest4b.capnp.bin"); } [TestMethod] public void Test10ImportedNamespaces() { - var (model, codegen, _) = LoadAndGenerate("UnitTest10.capnp.bin"); + var (model, codegen, _) = LoadAndGenerate("UnitTest10.capnp.bin", "UnitTest10b.capnp.bin"); var outerTypeDef = GetGeneratedFile("UnitTest10.capnp", model).NestedTypes.First(); var outerType = Model.Types.FromDefinition(outerTypeDef); var innerType = outerTypeDef.Fields[0].Type; @@ -72,7 +72,7 @@ namespace CapnpC.CSharp.Generator.Tests [TestMethod] public void Test11ImportedConst() { - LoadAndGenerate("UnitTest11.capnp.bin"); + LoadAndGenerate("UnitTest11.capnp.bin", "UnitTest11b.capnp.bin"); } [TestMethod] @@ -147,20 +147,54 @@ namespace CapnpC.CSharp.Generator.Tests LoadAndGenerate("schema-with-offsets.capnp.bin"); } - static (Model.SchemaModel, CodeGen.CodeGenerator, string) LoadAndGenerate(string inputName) + [TestMethod] + public void Issue45() { - var model = Load(inputName); - var codegen = new CodeGen.CodeGenerator(model, new CodeGen.GeneratorOptions()); + var input = CodeGeneratorSteps.LoadResource("Issue45.capnp.bin"); + using (input) + { + var frame = Framing.ReadSegments(input); + var ds = DeserializerState.CreateRoot(frame); + var cgr = CapnpSerializable.Create(ds); + Assert.IsTrue(cgr.Nodes.Count > 0); + } + + } + + static (Model.SchemaModel, CodeGen.CodeGenerator, string) LoadAndGenerate(params string[] inputNames) + { + Model.SchemaModel firstModel = null; + CodeGen.CodeGenerator firstCodeGen = null; + + Model.SchemaModel LocalLoad(string name) + { + var model = Load(name); + firstModel = firstModel ?? model; + return model; + } + + CodeGen.CodeGenerator CreateCodeGen(Model.SchemaModel model) + { + var codegen = new CodeGen.CodeGenerator(model, new CodeGen.GeneratorOptions()); + firstCodeGen = firstCodeGen ?? codegen; + return codegen; + } + + var codes = ( + from name in inputNames + let model = LocalLoad(name) + let codegen = CreateCodeGen(model) + from file in model.FilesToGenerate + select codegen.Transform(file)).ToArray(); - var code = model.FilesToGenerate.Select(f => codegen.Transform(f)).ToArray(); Assert.AreEqual( Util.InlineAssemblyCompiler.CompileSummary.Success, Util.InlineAssemblyCompiler.TryCompileCapnp( Microsoft.CodeAnalysis.NullableContextOptions.Disable, - code), + codes), "Compilation was not successful with no warnings"); - return (model, codegen, code[0]); + return (firstModel, firstCodeGen, codes[0]); } static Model.GenFile GetGeneratedFile(string name, Model.SchemaModel model) @@ -199,7 +233,7 @@ namespace CapnpC.CSharp.Generator.Tests segments = Framing.ReadSegments(input); } var dec = DeserializerState.CreateRoot(segments); - var reader = CodeGeneratorRequest.Reader.Create(dec); + var reader = CodeGeneratorRequest.READER.create(dec); var model = Model.SchemaModel.Create(reader); return model; } diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/Issue45.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/Issue45.capnp.bin new file mode 100644 index 0000000000000000000000000000000000000000..7bc8073c6f9ae632e3a84ff23c0ec7151f1c6fbb GIT binary patch literal 3360 zcmbVOU1%It6h50Yv5FOK)oNdw21F_*HQGKH5K`0BM%pGRO0f^p+0CRG-JRLY?CR!0 z!Jh}Iwn!Cx5Cp450&1m7E9gT7MQEtdO4UNEh)5nJ0euk#!S9ZY+Xl~a=lq|0 z=ltAR5s`Nac*M{ttAM}m5ZTo&vObX-b$5(WDBWTlR6ZB+Eboce0^n8(w^9eGlo$00pHo)Bqx1ub+m2W zb8B+aJbMS?oq=!w_*7omhS&GL0XpVE&(Az$;cdh_0l^$_R&xye@vLD&zw+(DUa$A2 z_iqQ^B{e+F`SYe5J4OD0a0_rY?mgf;TPk5ZXVzaBJGypZj&TdHNaJR`MK(Y+h#C## z;`V`WcixGGqw_CEU(TC6bTsqOdMc5x;C~*wp3B8OYl-{gk>RCZzN?%zdFaWU7i0#` ztq}Pe{AJ+moBRO2T^^!Z=tj{%f61x()xnX5Q>m8Se%IiK!k}I?!EXfW6a;AktDJ%Z zvY4{6A2jzX19t$^*4P)or{IAcOj(%(O+Ri+KiV35QzbR6fVfK;;At%Su|w#GG{%d& zW=}l>`GZ&rJRkiU!1S9A>XEy8YJoS1n+z&d$ z+Vk{=xs{tgKTDqb-}219-!A@i{Ld|*AI2(rwFpQ&zwG(0h!chm3s-v7$4iP#c@1}R zrx&p=2{8}6o$~R(^Ap8XIdDjBC-(dUstTs2BKFaay<-W*C?YNO(YZCMIFIa${JbXW z7%^Yj`56MwIoJuT^9m9Y1Nxm~-k(Th?GR_x%v%BXbqdTE^R2KM1os;P=6+T54RyR{ z2-;_cOP{JwC5Fo1SW&&Gtrr`ppZ06sU-fypt#1dl@Ni(?vj49H);RfsBM9Ryr+(~5 zg&`36`ssbEHKZ-;*GnRSZNT&!2WA~uKQ5la;FuB4U$$R%fT!Oh!1Rl}1HOyPJG+kal|1$AGio$1x5fN_AGYtDTH5r* z#9+Dm->d<1*cM;SZ2D4ef4%SZ{muIpn)i;zBj$eyTfeH^bxK&UO>eyq^g|Huot{g- mOZjayuj&77^W9=S*J8EwHF#ssw=(~uNu9^qWIGUagnt2m|8Q#n literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest1.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest1.capnp.bin index ae47486724106d3236d29bd30325fcb8e2286f47..c417bd7a0abedfa7896ec48973b40752926718f1 100644 GIT binary patch delta 39 ocmdnMwt;QK1SWBnHM0YjX5XI700ojjnxBDTazB&iQPk#X$-tD>BMYoS-4e2{hsoP(Tz&L-YeVKp-&jqWEM7 zMh!tmphOc;fE7rq18GH&PR^YzJr4v6ASVRfD#N0lh3jgPyWH=G5H4bipd&mf|KX5a7!@)!v$Tnm49hT zYSH98rY@i|iOC7f6_TKUVq{=qfY}W;5Nzl{Ci%%97&#_3NPv8d0$|>P3GxCN{0s~e n=S#YRA_Nj8UjQ--O7sw42x4N~D2SvlLJn#OM2O}hh>Yt9dq~f+GdXAwRB}=; z5k&MLcoHvqHHwB@j3*KO1OA2V$p;a?uV-pzc6MjQf|`1Cb#>KO-J_IJtKf*rY8#Y+ zl2VJ{Q?b{vvSP(<=zXf9CVy96E_}Q6b}wu$?D+Cz^3}QZcaGXrGUVirT<5E9-eaL)gYV^(gtsn0*AyyqkzOT@Z&DoOyeA~VE3(qB ztf!txvvpN#!^3ff#+~(ohFkM8fvj_D#_pyT^nEo-t89nNBlWRM_B9dLPaGU{B=?>+ z`-|q&c|P~w1E2AItsnth5OB3ou0KWmScjam8TK^z^Wxf{8!xW4Xb*w&IM9YW z?&JUJe2RV1{IzS0AG%@PHvzMy)Ehr7Fxd^PzaU=VPVkohli)2kun2G7Dc0h d1Q(gVMzz_{I382 diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest10b.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest10b.capnp.bin new file mode 100644 index 0000000000000000000000000000000000000000..a94097595fd717dc9a4def1102d62047005510ac GIT binary patch literal 1040 zcmbVLJ4*vW5T1*PFBGDUc9wz>6D{`#C^i;8YB}Q>Qn(kAYa|FpY}7OcM6?i6S&3K( z27C~~N27&cDfkz((nkE|)+Luq&ccCjXXmlA-_7h15fuO>Vd}vqWf0v01K5WFY-tlq z3Yw_RU87hd)Jl6-#`b-6_oU191~2;vm4GtP2OI-jKS+k>*RBu0?kegYg9=lL^Ze@P zr9b}+j%T0>C}t|-0;#IZU@bWp$ zw*&Sx@U-*(y>hhp!S)c~zmILW|Mk5GIOp;Z!j#f>Oeby299OGJL;r>Du;R<_(?DnS y9BL=kuJ#VbX`5?xPJgDoqhm6rk_Uu literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest11.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest11.capnp.bin index 1d702abb501b8d84ceee9d791605ae3d1828508f..85d58d009d84f1d864e0a2bf834626a3dcbdd27d 100644 GIT binary patch delta 639 zcmZuv%_~Gv6uBOMsmzalNnz~X!<^vdNa1Tk=)rjnSYMR zei5dg13#O~CF~X{m=e;*GOGMP)fkAy9 zZ3gb~h)%5|8cL{|omFTrXzM9UQ#S^0-JB1W4`R)Xh3x3*fh%|CGPEJl(x?vRL%L_)Qs}v)!o{cDKS0=S8sSz4eC<_nkZW@&E`Z z1xftE7tH(T{M!1PVAsP=yMQxl$68}`W%hRe@pm6NUZ|z<+I8dommtuc#3%l8ShuR1 z<6EIbuagDNw|eSisr(2F_8aRiv-;F>b{rew=ePv$D`71zhw&KZ{5kBl z>;snP9%Q?6ud>}^0JB9r+`Rm;oWp*Lxbt>sO5f}aWz-s6e1~6iUq-gIQI7Y2U+Y{r z@|V=D(bsa{OJB?Rk-oMYQ>~42*WS;tEuQwD+>3T!7mfb-*FH?cN?TD|Y5S>fnCt4UpJ0)1CO(0kZmUcm~FtN}=NRAV1){v}?h5mMgzHNksV@s} zF!%(@z^DW}*n4|+W_o4eYz%9-H>uP5$t42wDEt6xIyNhAVS-@v1RHRfnfQ6-aU^_v zdc=H#K!dND7tMV8k@p$a%l8dF*Aa`ME2ZS?$KqG@I|7gSN*y!X(7dm!$XkK+@_m8N ze5iZ;5fbQ~}~Rh8|%|+Wp8r zAK{I7>BO*(@j9aQdhSS#p(BnMn~ZS7e{@j$ZamTcF<;iLX6oST!gJB&{g)`GI5L5S>|(f|bR8wPS;8NHhIEA?`;;O_IQr+;xV2$OE` zPxwD&&1clHKV2_+zhA#@&!gMy&&BswSFv7vkJ>M_E9(7MUD3UBwOCBwqo**_Kl|-& duTjj9Ww-ap{ZCjw{zvJL?>t>Mm||j`t^p|o#}5Di delta 475 zcmaFB{ejDo0SMND2ryt~;04nA85tN_nHU)4p`t)85U_zM5g?0|fsH}o*P%|?|L-5D zPF~32RDfrC+Q;!kG!WG8agjgG44KuyCGY4E2Ab{r#fc#D(&*r9c@gAZ`U>Wb+$AI)D!0 z^~+ZXN-fSWElN%;)}QRaEIxTYi|FKyEcO^O62S1=9L{XWh$i!ZNo6u4v%M^eNuha} zB_XNBC5A?N$%zGd1(SK1lF{@PFv(Az!sIh~0jr24$PObiV2KsE~y1Gx-OCu+(wa!+n#loy=|H@_d0p%@$G&{)7i3u!%p?R4lA*sbBhQ@lyi3NED43mE{p0Aey zDq{q~rEiaAh&A)RHU#pkfOr8CKM2TQh{OlUFGk{T0`iwY`KCbjFCbn9<=X<;AoYuo z_*y`INM%84SY|PMW>RKOW=ZAbe@selskxaYex*4%iAg!BE}2EC$t9U(sX(f`loy=|q~=;LgOG_M&HjyeuHT2*l<<{1=G9 zx;al4tBYJJ+Swm9IgnAFmlbHM7Bd5bDUfCd**h_T#na77KPa^zzgRyxu^_LYD8D3M zHzmI$FSR5&zbIAT86@be=Nz1oSX7|ro|>0hlvt8qq!*G}TvDv>m#+|%TAW{6l$=_u zKY0P8_~adoC(L+&)-wX(g15&q#F}|ugZv)^#0!!5RY3kCB)%5IWHx4{$py>_RCLe< ZX64CWm{){?Le>yyAt+?2>)it^8UW6Fj8Xsq diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest14.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest14.capnp.bin index 0e48988e8e4fb84759ae11ff85d4fe81826a3418..ade11571b9cecdbb57433cd64f10a9167aa9b41a 100644 GIT binary patch delta 515 zcmaFBw}4NR0SF$02ryt_5CqcVObiUR%nS_jKsE~yGXn9|iJJ0^+>;HN(4wR9eI735H7s%NK6f_0W>_8d@3?|;R7gYobW&uT1fpj^Lo(rVqK{_WZ zuyITdU{sJ?3KY2nl-UTRk+rXx+{tJ!3R2$$lwAm<)q(V0APv#~ft7<%a55v4JnvDU z*dw6aMIg-%a___h7QxWG%#x7Q;u1p>z2wA#yaI;JE1CEi>t%rI7=du<+hZAG&AhJ- zf&3~UUVy|80`eCk@j>#7k@%Z{{3TGnDUkgOh?hb6wm>#W{URj37LXrOS&$l*SIQ#NoH9pP%TK@B|kSYGtW6EvA8(3*fB4~ yGp{7IC@nELwU~jS1Y#D{sLgyVL5!1EvMNtL&3aQ76id873<@iZAehX_9u5F;?t3Qy delta 561 zcmZ3$_kd560SI1$2ryt_5CqcVObiT`%nS_jKsE~yGXn9&iJJ0^A(IW6W+tu2!~8SO{9^s&#DctnqWqG4-IV;2ywsB9{GwESXON(? zo^x4QDRAckzPn@aY?bhU%o<6YH@yPQF3ar{^S5A@y!`b9E@f>KsPV~ z;exlvGQ^sBUxNZK2#6OV@vDIRMM!)thRNTUl{P1^1Ta$3NgG&|CtqQ`5ekYIL!gbI N(4ne_CtqL-002k0kCp%c diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest15.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest15.capnp.bin index 2cd9b987ecc036a88629ccbaa34d55a0758fc329..267ea05d21412dcf1be32e5eed2663af6dc6f769 100644 GIT binary patch delta 849 zcmZuwO=uHA6rR~l(r)vkQELn~Y#J>!D%ur2h)5NKC5SBv)}ptxZgtBxwcWI(y?78j z^yKDw@s>s_cu{NgP{D&2ZzUq=JwgSM3Q~|-LHu5AAxdYN{pS1Ld*9BR-Cf;(w>2p+ z!V2GcctjZYsw#xmD1^SQ2qA%OZc>+il8UY^g3mzu;Eo=ZVRu%K)u4QWvJ7n4KrUwE zr*39fJO7A5@ zMyMnY#OIMwgxLa+x3D>0fUD?$-fiDgRN~<|@F4^r11Ev4WGG$Hq(_KXUr)`aeZ6^WBroV&!y0INrB6%CTP<*rxaOAM-q?LR_|*WP#w^wGEck34=lFv<{v7<_ z20wu{@A%OMKaDl#m+SaJ@JmxS&C8b4VD($JRhXiWO^Ng7uvO?Dx9wcNZKkX-bD&^N zn8;;4H8PyD^5^WFYk8dyZ1&2%J~z?!ctum2qi!8L|cZK`49r+Pt-d literal 4728 zcmc&&O=w(I6uy&W`XdG_w*F+}fCX)^GY%NUppW5uQJ&N`aumt>br&51`Duo8%Nnly+P!D{6>DZ?) z-oAD`mKOhf2P4avXBG6B;$gj>Z-dA8F8fzMH~~pX4ff`d`DI`kHb=4EF;K3Il6x4L-TT(Jlc6v6RnCE@4SEbYq=r69^0Xhk~dq>*u zN5^Y3y6XkCrqgx1z8882=e^L?Vbk+ z$=9mo6qNNOzwX>IvF_&#w{`$H!bSr7L787qftvjKr>7@5!=VR(w%!xqsrNJ}^&%Po z6vfT-7WYSWGh(Cq+i@?%eon&M_cQ%K;A^7~>-$-JQA+u2JwGpQ($9;V^m8+aOGJG2 zkGoEXcd`I8EqfnIpHN$$GN~K#u3%l@ee_ZC&LDplDEBY*blb0E{bQ^|0%Dp%db|2{_yWdmphMti{}oAGS7M?F!0W znjFikV|(H~{Wos(!#J=Jq-}{m#T8{VeBf>%>j$qQYTyCkvS!J6iJ$m?t@=3!Ju|OZ zfgpjc^;_?y5g+xJb=dOe_rK!!PDkSZKg^G}SJV!Z1<-$My&w1;!MKq!9=tAiPd^9B zy!T^c8;gs1*O=wNTnbFBNr_TSQU5miGhWMD=V1MO?BzykUnU+r1qS4ML%t7qU!4H% z1LnQ2>X7sO&U0h(4Gdr-=f=dxwqk7ce@ztV2i9-i2Sp(7bm@1{xDP1rd6Az?Pt|5Y^TfBKa>7s&FB$0{A&nbUrS z6{fP_`IV+OuPck@n+TO)_#W!A{@Zq97C%LD*zJ|9VymVe=Ghhdk{99+W*-0V!aSm1 Xx9mJ63o!Hdzx(M)-v2ebAcFrFYTEZb diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest2.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest2.capnp.bin index 5a2eafcc0b95779d73149763083f37b1cf4e79de..e980262b36c2986572e8fca13d2520e69e9f9480 100644 GIT binary patch delta 87 zcmdlWvO#1+0H^59NBQ$5WVXIwfC57x%|2O?QCd)!L%6AH-tqS^8QIB+ociLTAbFS& S10w?un9T^(AwT&WrxgHf4iGE= delta 67 zcmdlWvO#1+0H>fXhj3HZyyNc~pulkQL{5E4O(2gQh;Kg1pD!V^^#x2;adIN3{NxLq K8k0Y8IsgDqjuBV@ diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest20.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest20.capnp.bin index 48f5e96c07e29ed4b7740691d998d795288f8924..92195afae6730c889638b0d71f95df816545ff23 100644 GIT binary patch delta 40 mcmaFB`hayq1e0jJl%w@Cj|CSPkio>i(vu6ABqlFlasUAF^a|Jj delta 18 acmaFB`hayq1k>aKCWDC|I3`bE3IG5`^alt4 diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest3.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest3.capnp.bin index c0a1dae51d34da223a748dbfd981e4e9e939341d..010bfe1e9eec5b9e5ceb81355b726b3017af1a09 100644 GIT binary patch delta 27 jcmcb>c7bif3MP(iz1mCb`$e};-oT_W@dL-?2TTP3rLqgx delta 33 pcmcb>c7bif3MP(5KZ70BwLkVw-oT{6v8`8oX??%w_Q?;J3IO+B4!QsU diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest4.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/UnitTest4.capnp.bin index edcead06ed05aaaaf80654caff95a2119c09bd73..710cca62c17a2dd3999472f3a385d08fe3e475c6 100644 GIT binary patch delta 944 zcmZuwO=uHA6rN3XH@j&1PcvR@SEw5l*I=#Z@%w+^JaMSW~T8+ zvWvm)DtzXqG7EFX&)80#F7in$bFOy8qa6l5 zh8)u#e&Is@x!YT=RHIb#H`OCJ579-BXhIxxxX|`uWuUDbBgJp)%g}sfw8OVeIpSot zn#bp_eP1apev45~wYUFqGifMz0vV-Qz+CRk7>ecGvC}CKj}T46^TJB&1Ln1qUh*F& zXCK^b?zvpYUnK+4bws-0`6<2d;#H=?QCd)ols7wRO`D^saD>!QlFETbss`2t&IZEN zA2?0rAh_TDb^h!gE~WVVm+-HG^?G8_l}N?pBNq+KRCF5D3>42i(Anf zee4kL8U+t7>nS3bCNTKbWbroh5$9e5J@?h0X+3%A?fu&OS28HQYy*jVun@_ruPavz z#;46ZFP3}*$@4!D!H}(t-fE%qMznpO8!&_t-RLpZ!@D|q7fN<}WBA3}R@kf5QU2%_&hdw+BG-JLt553S2SYp=D} zT6^vFv+p*>n6oYTq);$RfL~o;Or_132OQTfx20$^cneLN+4km&KNegn{odhZnxQqV z#!O?e2blJD0pHzB82qi*zqoK{e9`xJVP3%a?)7)xdu!E>u~20X>@0>y6=zrL6QFMa zAuRq_fA^;^z4GUo#bPwU&q9A3Ya_sGfhU3I@>l*XYhq9ABd{|A;y5s4c4{8G7drad zC*R+4>`urs4vIIX4e&ASEJYl?2Ijd1XF)##;#$Cee7dLa$B(}Kkan3+*==pmHfGA% z{W;LT4ElL(;^C>kmvyu+ANXJmcqkt;@YTdGS58e`^+eL?gE-8K*mygz@9(3a3-D+V zxHa|6YTmo=wJ+cO>zmJR2e}Y@%Ay z_x93**TcMp{*FLz1MJF<_8kL1FK@rb_ZKg|aq!$d5QLfszE{RvhW_D30Z;b7Q{{gp zmRj&rd>c<|%z5W8?fd7w20Aak{qc%{auSaWm&!@ku4<(|SWfDjJ4;cmTB8@Yx&72X z?VvYcsP1{ckybo!#r$E6{&=ViWQx_NV&ZMjL`hOk(pqjoMXC;2+pNz!CI)~~>=TP199Q0dp<~f){okRZb9N7=9g#tQ=znd&B z=t8&1@pVqx<2inq{OzC76GJnk8MkV5pq$jAQW`8r12v74y%+Q2bQF52AHBU%wHnu> zdL^zVw3fk~@q!rh;nx@AzZ^r6wCn$O{#^PLeC$u4U)*1DCr|yRdSqUi$7aBcu@j#z z*HxOJY$MWsetc9;u9%&1$}`V})GNnywnVMRgn1UM#)S8BH!$m-J7>E~%9#5w_0O>m zH1+sipkCGW7tc#je_AU0YCYrFS;_Sy{|5-_UrS|Qt!ErN%a2pmcb#aI&f0KXkL#l~ zSKK_U?A_dcHbPmXGH-&u>ka#flH51ES27EBHt%_K0eFhEYwM9;fqbS?zp#F{2KkpAgUj5rOd1oos zzpoe8f2GIDDK5IlEjRmWJ>%F}WmCwxIeN}GG3K4_hFSeYG#nk6y@m7j8vBNxC_j1! zva0z15wz3|)t`U=g!MNR)g$iLSheIdLbG++Zac5ItwUhy+SO5=7s(_xaA*XV1NpxL}{P*IIk6v-Y?4 zUgut8j2Uaf!&0kh1OKSin0u3rnTllX!-7f3U}R0__a6-ZeJWhP3~|Pw>;ZR~ zxfQD+x7f_H9*XmDRy|I70sb{;ndf})4d4^yyZrXatJ`Z+FA={M4B>)lhWZibYiRP| zFL{>jkeR=@Ojp}`+eW`x_7!np+*P~h{M9;^`%`xDLHHknur-b&{X39ff$&+NKmPv4 zUw`O5`upRsF|P8LpZEy;E%>YuVtM+Ye;-EjzSLxA_T@`*ix#;wx{J|ZzEX~Id2b!-6vp+;_2QVR(9%zN zJ_MP0{5*Q+-=PBocPT%M5x$Qy)N$V)zfabo(LO(i#qOuOJ1Q1S)u>u16)V;uc_cW* zxOd0Ea(~QMeT99H`RN`^$9yG*>d*Y=Vyr0**nC&L9aSp%ig|VGW@sI?p!1U$H+gT2 zv;1Ud9krf1^&#~Q=EL_lBEE^|?yY>ar}$FQoVh2 z#4nw5tqUQ!kho{tv$78@21m#d_Om=J%_JWP0xI>C9~xjNmQR-q4J>f^Kk zGX1*1=~s;FMLbF2{+!m>-w~SoJQvrQ{g$Nu>!kE4d#Z7>5Eq>rTDhzH!G--mR1X(t za~NqIaq;~^Tncf2QQkWD@)ws~vUuTn%^r*=xOnH&$A(e4BX>{u6lKp1?Yw zBkNy@@2B>m`>gfivP%}PmnZK$Gh%-FUN9^6yYiM&wNxD{+a>||e)9LveVG41RE-b@ zZ@d%R!j9lF=5mBV3t-+s{VQotIu*cuF3|S)w3FA9*_cq1Z*gogW zTFLWXPw(vGUNz35-VSQ7kTg33}7 IH@;W@0nr@WBLDyZ literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/Embedded Resources/schema-csharp.capnp.bin b/CapnpC.CSharp.Generator.Tests/Embedded Resources/schema-csharp.capnp.bin new file mode 100644 index 0000000000000000000000000000000000000000..4060d87b2acb66c86c8a47b622398027fa010d86 GIT binary patch literal 42168 zcmd^o4U}D1b>5wk1op$iw)nMz>ubrbMq>0V31e&#*VdoyQDs?{WE(5-%G`PH&dinG zy!ZTmG#V8a;Dkl15^z-^oa98PB_=F4RLB5P~9z*2U;cLq@$5#r?Qj;qN#%2rlWD(Zzjap6$IE<(vY{o$&oO>_@m?dw+YL<+6P%F;KVV%H2~? z?nmcY?iRq0Euh>7y>bW9Ps4W}bu5>7AU=FNj3E4`d}f6Iy;tsR^l+;y_pV&IZ$Y>p ze*fu3dmnq-`|f-Cm8gU5HG0lBf$bXXg9q04`Fv)Cf9ZQWFZt-6PuyHt8R zD11e*#{qv5{?qVZ!wBcTj_~`)csci)kFNgVu20IuKG_qe|N6-4uZJ)wRc@X{5x)b!<$b% z8Qhm2w`IBZKI7mAAs_tmSLDLh-oN?EN5Ax;b-(tpJRSyeuEcc-E4gP2@Z1LgymmmG)gU2483lAR$0Qo%c$b`xB9soTN{-pD*-KTP4 zi{IM4{1eOX`@-{iI?MChDaaR=TPpRoZ)GlQ_>;M?#lL=QJo??+uDn;}d7+UN$sv#;)7?kdQ$ ze)V-u-G1JRFMj8-xyoJl+WzpZf_Uq9fBY^<^^!qk=+~}I1@Vo}qla!>w)%6*7fVw8 zhx(3BzpId;U%5LA;xD}T&nExusUJTvSGjv%*T3AO1@V9JvUk7x#Fy{={r=?+rt~m) zasP5R6~sSq$$S6R)%QMjLdPu#e&>!?Ed8GszxS{5@@(rr(Q=PE-zeo+E^P5uj*eS4 zU*zTbN-R={-<{4k_*O1#@hd+6lehktT@QbNcvyTs<~F--+-#JT|Vk;e8Vx)5~wg z`(8YzpE7&^kLke-Z^mQu(am^gc{ZPp;GN}}Ubn-AO%K_EFw3)b7Q z)@8(&dcDz!I!U9h`FGUfskq+RmmHPs!8T&>_PEt{Ikutx8{;~v>@-??q=1X)@spME#6V*-yn#mlFn`yw>@dal}>V)-Ddpu##EHlw~?6R_Lh2e zq~3{J<3I~&yVIv0fQhW8UTgiN>?WOH+J`$6j~un*c!W;M882ojEI zJ*rt!4}S84>@pF{#!p7y25)|!d0=y1wy~TL0Dk*9FHmlqv-aPLh*cH|-+D|rPr5g^ z#Jy~R@AsEI1ow_q&kNbJ~5 zN2Et*y0I0nDLIcfx-CB0Y){&iRx*{;Ws;&?%Cu<&0OPygMZm}BLkQD8`3LaH$60RwJqSLHbRVz3=iol) z;5c3i>yLI2{2}7U@R<87URdAP;IlrCr@>|KSdSx~a>E?+6Yksa3AZ%(yT4Kj!h>vfw8@aHi)!g-kwO`Y?Pqda?RUk0(BT`pLslJ~M8v`K2hm0)60?RyA(9 zf{i}&^;ozlJxcWuCDqyXO^D|UT!E%fS^4G{!B;(MG#!XAMeVZkUh2lv!sfSY4Pm&6 zR-@ZQWTRCDrPuoMi|KBJB|b^PWkHGi($$GTi;lCPt?MQL1rS2Za4I=xSEx` z5Byz;N9yAZO}`r6Z2UF@f?26qHSjw>r3g>EOt3eAr9%B@ny| z=_mA6{xU!7d%uGtj~SfFQfB-&NZ%?D`sY0k?t>1F^p98hYqFN1`w%(C7w1?H>wCz- zaonvwlf}&XsT|xV9o!cj+&L*d45YkAxW|$1^Y>>R+>;LO+#G+~{sP;8EQPKV{B4h1 zFgyQ>IpAIv{J00s?Bc8DfIBbvQ4gHikvGo)w>)^E2hQxooC{~`AID7buX8ej;y89b z9Oo2Gf2eEKm+RySYUtb5u!fR@~U_g?`-F1;afXYR~hKxq5q8ZgLuqQpCsHD;1g~T{&Gni=;58m z5%-A1>mTMP+@HcH9OtM%$HS2v#rq;8`Io+l9kl!yLE*XGY@^M7v4fm2+6qBimSVlc4tQ&>St1)K%%V&&7NlY z&9`(5o1e6A6wQtFH=8R;_w~uNb13L+@#L3x%lLRZ7VXl;ytsu*6KAH6(@qGPQpEp+ z;CP!pZT8T7Nk#C)%V|9Q_}jNlGN0juQib9Fh=;s7n|`_j>6EwTuEz`8y9++)GaDEG zJqSjSz880yM;Mv}1@bsfwvzfCD z=F8LV=Mfnq-uj7GIOfb8<-bq2Pa@3rn*7gl_tGupzfZTEX9)M_@QEMdRAGDR_Unkh z2ambDJ%aNFX`awJE)od73GbM`%3qWJ-$RJ?vF}zN$JX5Qc=7p!^93)3|IJnn2IM$`@>(v)7Li+ty2z=&eeOEiUpB8== z{coQrnY6a{=pbJ6)7K*Xy%o2+wT@SigDA>x1s0`e`sxDL1Ma+ym2Z9#KT7{?a|)Sl zKC=BZgE!yOEo{E_KP$-cEwr3ustNma(n;+t3zSDi`gl?QL5{M&(oY`wdwR^5mq*ix z-nV)hCGv?3Z%jPLxMn-pJ2iqO? zW83rA$85jZD^gyI=%}6U|EkTuC?5-9yA1EP&pqFIh{q@J^uxOdFjo-s<>~bbAddQ* z(yQ9ZZI*Fh!7>PRfBppWq`l|CSNyA;oN%ne+_^cpr4H@_2RG>KXoN#l>Xzr=&T(+B zbZ|?Y9gT4Q{COeLeg0tkh}YLTxTVgHMmVJxt@2elIJS>)uXAwAoE?pD{``4S4vy_3 zT<#Y#-q+b8s&W{w9U9@nTCaMf&CxOPD_$+>nDiC-^}MM;T=9 z@*Eu7$NGjH+_}MDr*QtfS2g!Wr2F*A_7U#q9o+KZbPA_-1%26W;howFS~!qJYm z82B2@ZG<-c#+fqD$}i|z2KH&air{`u>jElBtE1nMz_yUD?sp1}HS&A@TrfplL_pdLfG zT@KFl1j1cN0Ov-K?&}E%qJ7#1`lcrkZiR!Pw-XQ3&5hxO;bYE!vGfGRk=1ghUz84c zD0+h5#xtRN`{1VoUZzQ3cKGS`UX%`anI?T1Vlcj6ln!{ArF>c9!`XXLy6FkNOfeYW zFG@E(!Iv#QoV^#No1Wmy7=!WsqIA;}d|Bhe*?UpC=?T8fF&N)3N;f^hmpwk5y%(jM zp5U)l49541(oIkB*DOAqy%(jMp5XJW!T5ery6G21<7;IUrJG(-RKCF%rGx%^^cm)- zJe!ZBd@XWJ;rb@8A2C16FKQ3d&9VHVd@TP3JpJ@6v4gpT2+UVx|MKPfTI5@Y$J}Lj zVLLa#SNlt5Z};W;T=qg9>1CN#mwi9MINw>iAIJB@?z;s`x9=ze8X4MmG}zr^-qL!&SB<89bC=9aUQu_ z60t{Oncyc#Kj?)g9URZ^u|Br3CFujftGs-7Bi*mB>EL*Nk8qq9)YLr?;M2U+@tokX zG!z8+^M0HUbb*3zu)KUc@2Bn1$X{{w-RtV(JkXUSJEO1peii9{|K8)^?7ScO|FDC* zNI~Q;&-?jscHZy9u0G0r(m(ZzmE!B4-^{`NJ6GR-aB!6OM-*a%Eb8wXF|H8rH zleyIWA<~bhp&(#>*7qd`w^+XHM6HRq)4suuTcOxlT~WF#XPY}Vg%-~4iqc&;GUG`z@mrCa)o zEJwBjiHk*+vn4(5?ht#nYy`7C!pocT?6GCNCNAJ8WCwrD>3fWi5Y)CYVyJA^Rh z4(C(OH;dhWH>+@wKCW#F3is35)*`*hAEbVGoA3E0zyH^xKK6eXeDu=<`X}rcUwCx&HN&GwzKG*u;2q< z?6PP5#&f=WNc@<)9xpy04tU>lunu$NL!S9KZW#NHVV}e`;BYwywv}kz*>O& zcqY9P&l}*YoXp0@A6L#x{n>ddJr!aQ1C48^ZDR<s*enKM&@|m*X>n;iVj%%@w7;81q<>yp!>DhOF7}WMjnkF9c8iy8dSYPetdu z1W!4G-E8>s?NkfF*K0fi`B}i%aUh{kZe#|?au=UZ;OnFoE?J08(h+~(!b951pU+z1 z;UU7iFL!@Y@(%=)@bhxlx6e?z`20NT;A#%eKcD66%?Z+ddCm4xel;DOe?H5%&rBix z03LI!hj6szu$@51KX+59Wm%AK_T~ivd6~^#?nN!=6*t^OcGt#&0CSl+?yY&!jhxkW z-yjn%FUJR^?18|ybCTbDdg&*}sl!r^Q^z((emiOb_``TOepkci_$^kCO8YWWuf`w> zTN`^-_PiFQ6A!26i9b7AtVW661q;i`&*z30&ei6YZ-J-h*KG&Fw(GmO%9XGm!gE+U}Fvi0pg&gGj8&54MBO?u(-h^@POq|C5)6DgIpc zqA_DVFW~7XZ{>cBvfdEDe7$lt(|4A-I_O1sHhbYSFh<*F|qM-e8UWO9{Z zy54i4l&c3NUjI;j6RrcF{6&~|;2~T|eEq{ciTk}U^AqkJ@Cny&->#kG<>~iYlurGO z`Ax@Js2*C4$0K|QksdL!au&K@G#OQQ9MMk!wri2v3!|@oePUcuI^&D-uWO~xA|ku`CumjoEw7A zc3%mf?I!>08G+vKamoKa+y)27bM}NYK1Fa*E_Q=%h4?tPINvWyCq53~Pe1t}`?A@E z9p#(jsWH3QgK$hGjZOS%@w7y)}nbK z*Dooa`Kd=!*0DEsA0*>Rzt(q#d*=^Ch+|6TIDf3ng2DB8C;jY#uk>SyiaQI9;Kj$! zO$ZZiKYYTG$F!ziyXvio--^c^>ml4Ee4)FlrkraT3jCt<7i(Omgoft-eTj`jzPY~b zz)vG?cH&PzdRBRmzwt?-3Fp%@V~IbD(_H=k62C?F@37obL3{Fd7qawxI~blXz4`Wp z>j9UiHQ8gwuP7b&aS43UIV^2O zcCVC$&7Vpttp);T3r`$9hClu2sNWrvWp~$PT-7aR!u#^X?h|D^<;e&xE^9%?F+AV# zJzII=&qw)j`iGJyy!XWR)_{VuzMls3DeyRdd1B+hI(>IG@}wUfSeg0p&+d=abw!R` zgbuz1VCsRiYY<*t_Qr68$LCkmzs+7iUR8+Rd4*?Kj^Z)L>6LtbFMRSjoyiBE&wmy1 z2PIYiyayiPJ_tWAA5>0gzWd<$^Vs_x+(Qnoj=NQOj;9FkNRoPp4?4RSS3}v~BKVeG z{i^J^fPEnwr>q8jE2;yi&%CY;`^5qr5bEHq> z&)LbfvWYFB7?a(kG?v?|S6hpewk)(3FTNbR3}NQ2SyVWZ{&yPPuI`L5SJ4be}Fv~gZ;m5us1gN-Im9)Qh59UP(??uYR@Y#O5=a;nW z%g6lp%*$OlcHc2&r=LH6kL>*}-R_rs%!S9$XTq5sYZcng@JjrlpWpXB?&9s1HdbNyNBQy`Y+`>-{jgU z7v2QMW4hT{p1?wq;nU8ydzJ2o;A1?0$AiAzyYh$&KjVD6@AM!9Df97nIOyBGq<9rq zf{~cR9qPB!%NW2iw zDvSZwbw@F#BiqBqc-WbYLuyWCU`5?-T=3_ogi$+8I$_jo#u09z3LA9+s$flxi`Ccj z(%f(e%5}Fb@$FV+J+G`vj;t+*;hl|cI2Fx=-F95+OeVxGF0A-I+N|N9mn-BVLMQwwH{;ur#8Zqcw>M08%kL} z(^3qC0D<&(dNQd@hU-}1Iw_GYuCjG<`xajWQ;im`53XySVYr|5vwLH47$Ij3*UBG` zLrVT~NfHxWOWK-}+vY>$ZMGVR(f29 zFfLD&(TI|Zi^J7Py;AEUSJkc%$0*gqZLfbluzm-k8}&7v5ZF{CAxUf$?0H%_dt1u2 zuu-qggi~=;$0cKIP1HeSrkVunBp?hJzo(;_a;Y?QOFcZ$XdG&+!JxL1s6J7Phh1e# z35sqcH{%Xb5=NDZn9e2)otgtRDMHr@4T41Bbgn*yx9yDzn?M7O(Vi~(9i4E#HVsu? z|DOLCo#m_X`K<*-=55Hp`RgO_?}04a0s@)n)}mIpCH-O)c-#-V7woL+G03lyL1>ft z8cp0tt;Cq_UJ_@Z9gro63zQp$G<$+Q++Dfl(nuZkby|&f6F1E3xJWfhg=4sjeg;s@ z2B~ebkyJo$pk4A5hMZ&xvTk=0Fds-Wtv9ZgP^XZ)?gI{o+|L^hSxmYyCnKZuj~-My zUGOk#6JCnzs0)SUn+&-y&TZLnIssui=9bMa9q2jBgGg{!*n~sECrM>(h7l1ZKq@aI zDT8w%Z9wX!T09Ze*gt+oB)mtiP;9c1BK63+Nxe;}r8`(z|v%FaZ|a4(VyRH@p*d?W(S)WAz z1N;F?1xJ@;72A+vq}&Hh+IXetN>nG=whTF-vo?PPq#~q=@m<9sST&4k3C!l`1Q@JA z+O;utwHni5e54XL`NJV?B4kc_%(3KL^lfs5{o09sT?2mw*9sp$hZ-h5NNBbhOaNWWC zICy?$q3$`rya0IKH$(jI=9C5Ib=<_)$u3kL(P1D8>YZeKMg^-(t*Y!ebmJ#xFm-nL z8wFBE)B;gavS4-|>9k9#6+i-TY$}tOJ!46sq#^7?7f1yitJufjb?XU!d1hYoE)5|V zmU>b-M2TP4X*C!b4`-l_O_S9ll0^$_5+2qcy5UfadN(tVhC>It(7#Xsry7xoEEoI% zI)I*rDFU?Rdy0COEA18W?MDu+s#<-A^v zp+~L87`rS|*$rdFkE_8{wHaxto0Nv2_YPCr!tKYH`egf3YKFW34`TdEoD?y3GL4B| z3smcb$&tx!oE{F_P~=D&F(ya=_X3K*Zc~vSb;mwNK_R81ajOv~s=N~$=q$;`A&4@J z+N_WgluypRqSg^jl?a3=a}HI(_Hf9ar!u01%#CR@oJuH%?hsB2afGCnA#?`{oX%-e z(IJQ%T#-wyP?QhH%8-v?9JQ0UwN~d1r^mAh>$|kT=6EIyL((=dG}1D*la$*A)w4G3 zj-Y6oYX&SJphm@2rIhTO1)#r)jcetZbZ}F8awI8T0d7*Ug&%&ZW*UQ16NiEQPBVdV zckl;C1T*zUeZ4P?bv|fyq0i?kak+*~rN%(3dIkJ8uy8^ZWF$w~GRAEg%?K#3ub1CA zDUD{W7`5K;+&h2wOGnDh>?jSKEmtaL`Ccc2FcXMaRtEg-NOP}3(mKe|7(Rcym)||o z-e3;%0r(6*sA4NN;cMA+%NB)>(8)W)CY%TPj`@BHYHd3q55E+U(rtoPS zJpmhxYT-!@CdoN!?j&)W<7q{>QD@s(bi?;RCFYn>Q0pejC_iDpxzmBSXvvd4>zJ< z*<9pO3KYY_Trz8kI3Iw|7%i+VO$I_d)I(`OqK|$;N@)U|Z%wK#k;T$BN!GHpj8uhr zge9vkiG0AOYfkU-Pdk_LuC^G`&%f{4Bu|IJ1O|b+G&(IB;uUKWpdw!4t!}oW2{77p)ROtiRP$~7Hoozi zjU~6w1g0r)whk~&2TODQ$X6&oSqGZLWP-jpm9-rXnR*V?t^q5@YbaDajU4e)Nt-0T zRu%$9de#=5n9}~3UIq0=>_$a!?8&ouNY~jMEV$v^1qRk4nU8wbw$&=E`Ri>WjfC;C z$v{^txan!OBw!2!7~2{u*|izjZi3NAYcec3}H8#OhB$$ z6&G&o2kpeZz2FqW=4iKiY>BV;X9alZ58UcgxiQNE6;Zk)j7~<)k~r1GHOx31M#vO5 z*JB`{V5V~nr$bc>M8)GbNU4pABhU8JzLE0RKN5Qe`@IH_PM!Lj0>=^Nd`jCo&wTI1 z!*iEoc)+_*yfRx4$DR%``(%oC5eV;sD6-@LXE@yXW{v7cFFd!*dY;9z7SAB&?~GSP zjo@UN3SSVTjIU})Fy8@&m6Al$fe-nG6~u~YGs^!u+d?pNE+dI6(WzAgq95g%b%&Z8 zq?+W?22h2>5@Bq;1c$*xY5=inL|AzFQ!NzY5H-Rmj0xV>3z<|9H6A@6UVM4Lbu;ln z{^9u;HOgR8=4_0j#-Ii3PgSY>%I+A3s1Q~~cTz#Dc~F$pL;Kx+_TTSu-k$YSW`81n zxL;&)pM9ZYe4dV1K;B%7c+%Ca@K1w4{uVy#4>WH07?@SUPlB;tE9$XM{KC;2ChdO$%>lK2^!V)DMbdy{Y0xt*-_ay zABB-7u5>%p>dN7bVnN6H2g_2*bT{8LpieqtgE1clHKAISdD^pTY?gNB6;axrOq#kp zv6`GTmDOgm1R@noVa zs~oWrk0&kgtG8TVBOP8tKF4onNEc9jJKRvds=T2riZEJ{bTDB#eL z`(Ox9pzpO)IVT0B;!lKtP)Jh2YHy#d%ON{ciPh=0sO`F3lol`%m%Qa5I?pvWSccYl z;A@q9Hn$2*WjlO+WccGyW^OR#IdwtrxzHswxkV6*v@_O;STkqBJ2@&EhGEm~4pp(e zqm)5rDpQYEGXYlD&^Qf2~VRlY-p6rs(y@S6Qx_@5QI^h=o$EC939JD z0r|G2T1{xo1ugq~U`py-enVh*h7{PHV2wk2(PL-!P>JE_H`~1{;bbd*(xa|AAJI^a z$GQ_>n+a^lwYZrB`m*Wd5KPKw0LHQ%vm4Mvbp=nvh>-lLJ=AN_qIpYPWZIf9sr$Z`pNDLwP{V6@@xg8p+G@%J=WZD4U4917m(tHgU@m-cRxB2 z&e5eS%?U{vQ-Un`u*zZ?isv?rmi$Cle}hF+7-oEdrVeX2*`jjR zOxbXg%xRObNSBrxMmR1n;OW^95ecZcMC4A=EjbSTzEF)HK>1TG~NEklq>Mp&US81=oPJI3!?2Eh@F&i2dOW>+zey zJ;kF8oC>Ye`V2`N>FBv1`10|6Bia~BtMv}6v)P9baQul5Md2#ipRp-LBQ0euL|qgf zif5)lS$@47XU`t!Xr4`ls3zsOarXJt>Y?6TT4Eu8o>cM$@2BespHX^Dv6Ns+_>br+foVbY+gqEmXv<)k=4?H>T^zdD>}62YLPVSf4}LQ^@xW`mMhyMlF>lC>UGa zJS*%4gpz!QvxP>_#ss_6<}b8E3GKmy0GGf;ki?|49Xy{w5{$yzMtC8q3L4mbvD2C~ zNpchxP@S(N@lk5CZ2o37+QT0`OIuJnqXoR7(wdRsFSVnf9J3iYn;Rq!xBaQ@K!0%G z_0(p>(gCBgi|B;{Wl?F<{Z83nAVZ1CTe$4U#0Mwb*B~Re9t)xN-*>d z9*Ti6fz~hDM=IQlP+<<-jMpMjem%(yTaep*!WS+Avr}v|{iY4Bd8=!W|kC4$$qvRP%SL z(C%CI3o1w*Z>FJ-TXdYNOVB_#C&4D}_8PIF;wVgrk7jPF1yFwYd*!6ibO~^g)JUOCAotXl-sk(=7vB6;i|qn#ny($Pw%(=p=>_WEPnsO7q>p6vPs* z{GP36-k=5{Qyk@;vq?LKV19poLr@&;UOdmb1O8T=ZR{fBv&`%q@3nju@4pWJG<@D4 z`3%M{TaWdbXH4r_#3YmHo2fuZHES4_fpM&cz-6EnPiE-U&UJJqLEYS@Z7O-z-*5=} zy2?QiE@U($3CP*$?^(6fy4I4Fm?=|7D0fWPM-FI_rKsC!=++_@0yw7>?(6b&7vOpl z+z}A&b5pkm5j$gvYic@nYucqzZ@YO^)KZe>sH3P+NDY*N5=7=xO%`>QEL_7H5%QoK zcd)hxl2T)wY|hf&UoH)8nLY%gN0l}fKyr;j`oV@4Pdqq7UbgY08K0J2=`X*j+giJ-82r3Fma4+T+kyVviGBqZWN{Zll1LC29IT-6_XN~Zdv})Ud zWKEkRh7%yIrJ}4H-W*})TW5s~Q-UFqMnsDW_pErfBBL{$x1)W)8`3wU=~J+R$SJT< zsZP}*FnjFQxv3prl6`1pyfhu!29Ird#Y+axLup5JJ%X_U0)FAHa0ryA@(eVAYb^qIXiJy`tl{Pv*WoF z&tr(+2R+VoJ6~fG&5sJRtI^NrRCrUaB&&{3mDmY7G6-1-HR2piVGnYJls3c{d3DstP=8G58? ztF)$7GS!GJ&aD12#GEUtag*eN*)E-qpijYeG?OWD?UEYzMB?fOHrk@cXPoXL7A>

2E{}k{#8^4Hvl>JKm#RrSP{y zO+D~55!=!kU%@3<5O83Cbl5`qW71kDZBLNAVs8>tHkYj+;ci_gSv^bO*gn{;sxtT? z?F@=RP1+l`=p@?xgAbSqVQ!t7YT$DNDbJ9KFf4JU1}x;YsM*U`G|*CbJDQHdjaSJM zzvn0dYPO?(&MZ&n5E)Q%OGa0ClL^*njEbF75c;GFTZhT2MPl11nlEj)YKF6BAUwsh zW@Gp&Vj72JU z>AE{MphszNNINybxpASr(-rM(-!d=u;8M=BU<`I=td65*ZYM`67_tr9%pBfciV}Ki zm%PUJkPjEzJmb?tpK@Z#n(xaZw_s6`L=jUObw7VT8eS`6&SoLZGkO9NoBlZRh|@^I z$~(5tVenpBYU_cJ&z2tsS)zOcf?%WGrp7_7)Y7 zKG~!l=IYCqzamDha8X2CI9BEhSFk1IhYTP0;5v;87K`!WM(r?9Lh1&cu_`{EG3y}Y z9Hd$dy#2QUF9&d0q#Yr)bNMh1 z8PX{qWU~y*SM;?s)j&~tcny#&)5ky`-1=Ht4>DEX%I`zn1D$Gz*c(9jkOJA3xkN%$ zR?E_m>nl~DV^Gkbo~izZbvX4n+86PP_rdhLNv_u)z=O}~#Gax&xxT_FwON*hKT-^C QApL%l<+bo!k<0o20879StpET3 literal 0 HcmV?d00001 diff --git a/CapnpC.CSharp.Generator.Tests/No Resources/schema-csharp.capnp b/CapnpC.CSharp.Generator.Tests/No Resources/schema-csharp.capnp new file mode 100644 index 0000000..05a6edc --- /dev/null +++ b/CapnpC.CSharp.Generator.Tests/No Resources/schema-csharp.capnp @@ -0,0 +1,537 @@ +# Copyright (c) 2020 Christian Köllner and contributors +# This is a modified version of schema.capnp, found in the original distribution +# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors +# Licensed under the MIT License: +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +@0xa93fc509624c72d9; +# $$embed +# #pragma warning disable CS1591 + +using CSharp = import "/csharp.capnp"; +$CSharp.namespace("CapnpC.CSharp.Generator.Schema"); +$CSharp.nullableEnable(false); +$CSharp.emitNullableDirective(false); +$CSharp.emitDomainClassesAndInterfaces(true); +$CSharp.typeVisibility(public); + +using Id = UInt64; +# The globally-unique ID of a file, type, or annotation. + +struct Node { + id @0 :Id; + + displayName @1 :Text; + # Name to present to humans to identify this Node. You should not attempt to parse this. Its + # format could change. It is not guaranteed to be unique. + # + # (On Zooko's triangle, this is the node's nickname.) + + displayNamePrefixLength @2 :UInt32; + # If you want a shorter version of `displayName` (just naming this node, without its surrounding + # scope), chop off this many characters from the beginning of `displayName`. + + scopeId @3 :Id; + # ID of the lexical parent node. Typically, the scope node will have a NestedNode pointing back + # at this node, but robust code should avoid relying on this (and, in fact, group nodes are not + # listed in the outer struct's nestedNodes, since they are listed in the fields). `scopeId` is + # zero if the node has no parent, which is normally only the case with files, but should be + # allowed for any kind of node (in order to make runtime type generation easier). + + parameters @32 :List(Parameter); + # If this node is parameterized (generic), the list of parameters. Empty for non-generic types. + + isGeneric @33 :Bool; + # True if this node is generic, meaning that it or one of its parent scopes has a non-empty + # `parameters`. + + struct Parameter { + # Information about one of the node's parameters. + + name @0 :Text; + } + + nestedNodes @4 :List(NestedNode); + # List of nodes nested within this node, along with the names under which they were declared. + + struct NestedNode { + name @0 :Text; + # Unqualified symbol name. Unlike Node.displayName, this *can* be used programmatically. + # + # (On Zooko's triangle, this is the node's petname according to its parent scope.) + + id @1 :Id; + # ID of the nested node. Typically, the target node's scopeId points back to this node, but + # robust code should avoid relying on this. + } + + annotations @5 :List(Annotation); + # Annotations applied to this node. + + union { + # Info specific to each kind of node. + + file @6 :Void; + + struct :group { + dataWordCount @7 :UInt16; + # Size of the data section, in words. + + pointerCount @8 :UInt16; + # Size of the pointer section, in pointers (which are one word each). + + preferredListEncoding @9 :ElementSize; + # The preferred element size to use when encoding a list of this struct. If this is anything + # other than `inlineComposite` then the struct is one word or less in size and is a candidate + # for list packing optimization. + + isGroup @10 :Bool; + # If true, then this "struct" node is actually not an independent node, but merely represents + # some named union or group within a particular parent struct. This node's scopeId refers + # to the parent struct, which may itself be a union/group in yet another struct. + # + # All group nodes share the same dataWordCount and pointerCount as the top-level + # struct, and their fields live in the same ordinal and offset spaces as all other fields in + # the struct. + # + # Note that a named union is considered a special kind of group -- in fact, a named union + # is exactly equivalent to a group that contains nothing but an unnamed union. + + discriminantCount @11 :UInt16; + # Number of fields in this struct which are members of an anonymous union, and thus may + # overlap. If this is non-zero, then a 16-bit discriminant is present indicating which + # of the overlapping fields is active. This can never be 1 -- if it is non-zero, it must be + # two or more. + # + # Note that the fields of an unnamed union are considered fields of the scope containing the + # union -- an unnamed union is not its own group. So, a top-level struct may contain a + # non-zero discriminant count. Named unions, on the other hand, are equivalent to groups + # containing unnamed unions. So, a named union has its own independent schema node, with + # `isGroup` = true. + + discriminantOffset @12 :UInt32; + # If `discriminantCount` is non-zero, this is the offset of the union discriminant, in + # multiples of 16 bits. + + fields @13 :List(Field); + # Fields defined within this scope (either the struct's top-level fields, or the fields of + # a particular group; see `isGroup`). + # + # The fields are sorted by ordinal number, but note that because groups share the same + # ordinal space, the field's index in this list is not necessarily exactly its ordinal. + # On the other hand, the field's position in this list does remain the same even as the + # protocol evolves, since it is not possible to insert or remove an earlier ordinal. + # Therefore, for most use cases, if you want to identify a field by number, it may make the + # most sense to use the field's index in this list rather than its ordinal. + } + + enum :group { + enumerants@14 :List(Enumerant); + # Enumerants ordered by numeric value (ordinal). + } + + interface :group { + methods @15 :List(Method); + # Methods ordered by ordinal. + + superclasses @31 :List(Superclass); + # Superclasses of this interface. + } + + const :group { + type @16 :Type; + value @17 :Value; + } + + annotation :group { + type @18 :Type; + + targetsFile @19 :Bool; + targetsConst @20 :Bool; + targetsEnum @21 :Bool; + targetsEnumerant @22 :Bool; + targetsStruct @23 :Bool; + targetsField @24 :Bool; + targetsUnion @25 :Bool; + targetsGroup @26 :Bool; + targetsInterface @27 :Bool; + targetsMethod @28 :Bool; + targetsParam @29 :Bool; + targetsAnnotation @30 :Bool; + } + } + + struct SourceInfo { + # Additional information about a node which is not needed at runtime, but may be useful for + # documentation or debugging purposes. This is kept in a separate struct to make sure it + # doesn't accidentally get included in contexts where it is not needed. The + # `CodeGeneratorRequest` includes this information in a separate array. + + id @0 :Id; + # ID of the Node which this info describes. + + docComment @1 :Text; + # The top-level doc comment for the Node. + + members @2 :List(Member); + # Information about each member -- i.e. fields (for structs), enumerants (for enums), or + # methods (for interfaces). + # + # This list is the same length and order as the corresponding list in the Node, i.e. + # Node.struct.fields, Node.enum.enumerants, or Node.interface.methods. + + struct Member { + docComment @0 :Text; + # Doc comment on the member. + } + + # TODO(someday): Record location of the declaration in the original source code. + } +} + +struct Field { + # Schema for a field of a struct. + + name @0 :Text; + + codeOrder @1 :UInt16; + # Indicates where this member appeared in the code, relative to other members. + # Code ordering may have semantic relevance -- programmers tend to place related fields + # together. So, using code ordering makes sense in human-readable formats where ordering is + # otherwise irrelevant, like JSON. The values of codeOrder are tightly-packed, so the maximum + # value is count(members) - 1. Fields that are members of a union are only ordered relative to + # the other members of that union, so the maximum value there is count(union.members). + + annotations @2 :List(Annotation); + + const noDiscriminant :UInt16 = 0xffff; + + discriminantValue @3 :UInt16 = Field.noDiscriminant; + # If the field is in a union, this is the value which the union's discriminant should take when + # the field is active. If the field is not in a union, this is 0xffff. + + union { + slot :group { + # A regular, non-group, non-fixed-list field. + + offset @4 :UInt32; + # Offset, in units of the field's size, from the beginning of the section in which the field + # resides. E.g. for a UInt32 field, multiply this by 4 to get the byte offset from the + # beginning of the data section. + + type @5 :Type; + defaultValue @6 :Value; + + hadExplicitDefault @10 :Bool; + # Whether the default value was specified explicitly. Non-explicit default values are always + # zero or empty values. Usually, whether the default value was explicit shouldn't matter. + # The main use case for this flag is for structs representing method parameters: + # explicitly-defaulted parameters may be allowed to be omitted when calling the method. + } + + group :group { + # A group. + + typeId @7 :Id; + # The ID of the group's node. + } + } + + ordinal :union { + implicit @8 :Void; + explicit @9 :UInt16; + # The original ordinal number given to the field. You probably should NOT use this; if you need + # a numeric identifier for a field, use its position within the field array for its scope. + # The ordinal is given here mainly just so that the original schema text can be reproduced given + # the compiled version -- i.e. so that `capnp compile -ocapnp` can do its job. + } +} + +struct Enumerant { + # Schema for member of an enum. + + name @0 :Text; + + codeOrder @1 :UInt16; + # Specifies order in which the enumerants were declared in the code. + # Like Struct.Field.codeOrder. + + annotations @2 :List(Annotation); +} + +struct Superclass { + id @0 :Id; + brand @1 :Brand; +} + +struct Method { + # Schema for method of an interface. + + name @0 :Text; + + codeOrder @1 :UInt16; + # Specifies order in which the methods were declared in the code. + # Like Struct.Field.codeOrder. + + implicitParameters @7 :List(Node.Parameter); + # The parameters listed in [] (typically, type / generic parameters), whose bindings are intended + # to be inferred rather than specified explicitly, although not all languages support this. + + paramStructType @2 :Id; + # ID of the parameter struct type. If a named parameter list was specified in the method + # declaration (rather than a single struct parameter type) then a corresponding struct type is + # auto-generated. Such an auto-generated type will not be listed in the interface's + # `nestedNodes` and its `scopeId` will be zero -- it is completely detached from the namespace. + # (Awkwardly, it does of course inherit generic parameters from the method's scope, which makes + # this a situation where you can't just climb the scope chain to find where a particular + # generic parameter was introduced. Making the `scopeId` zero was a mistake.) + + paramBrand @5 :Brand; + # Brand of param struct type. + + resultStructType @3 :Id; + # ID of the return struct type; similar to `paramStructType`. + + resultBrand @6 :Brand; + # Brand of result struct type. + + annotations @4 :List(Annotation); +} + +struct Type { + # Represents a type expression. + + union { + # The ordinals intentionally match those of Value. + + void @0 :Void; + bool @1 :Void; + int8 @2 :Void; + int16 @3 :Void; + int32 @4 :Void; + int64 @5 :Void; + uint8 @6 :Void; + uint16 @7 :Void; + uint32 @8 :Void; + uint64 @9 :Void; + float32 @10 :Void; + float64 @11 :Void; + text @12 :Void; + data @13 :Void; + + list :group { + elementType @14 :Type; + } + + enum :group { + typeId @15 :Id; + brand @21 :Brand; + } + struct :group { + typeId @16 :Id; + brand @22 :Brand; + } + interface :group { + typeId @17 :Id; + brand @23 :Brand; + } + + anyPointer :union { + unconstrained :union { + # A regular AnyPointer. + # + # The name "unconstrained" means as opposed to constraining it to match a type parameter. + # In retrospect this name is probably a poor choice given that it may still be constrained + # to be a struct, list, or capability. + + anyKind @18 :Void; # truly AnyPointer + struct @25 :Void; # AnyStruct + list @26 :Void; # AnyList + capability @27 :Void; # Capability + } + + parameter :group { + # This is actually a reference to a type parameter defined within this scope. + + scopeId @19 :Id; + # ID of the generic type whose parameter we're referencing. This should be a parent of the + # current scope. + + parameterIndex @20 :UInt16; + # Index of the parameter within the generic type's parameter list. + } + + implicitMethodParameter :group { + # This is actually a reference to an implicit (generic) parameter of a method. The only + # legal context for this type to appear is inside Method.paramBrand or Method.resultBrand. + + parameterIndex @24 :UInt16; + } + } + } +} + +struct Brand { + # Specifies bindings for parameters of generics. Since these bindings turn a generic into a + # non-generic, we call it the "brand". + + scopes @0 :List(Scope); + # For each of the target type and each of its parent scopes, a parameterization may be included + # in this list. If no parameterization is included for a particular relevant scope, then either + # that scope has no parameters or all parameters should be considered to be `AnyPointer`. + + struct Scope { + scopeId @0 :Id; + # ID of the scope to which these params apply. + + union { + bind @1 :List(Binding); + # List of parameter bindings. + + inherit @2 :Void; + # The place where this Brand appears is actually within this scope or a sub-scope, + # and the bindings for this scope should be inherited from the reference point. + } + } + + struct Binding { + union { + unbound @0 :Void; + type @1 :Type; + + # TODO(someday): Allow non-type parameters? Unsure if useful. + } + } +} + +struct Value { + # Represents a value, e.g. a field default value, constant value, or annotation value. + + union { + # The ordinals intentionally match those of Type. + + void @0 :Void; + bool @1 :Bool; + int8 @2 :Int8; + int16 @3 :Int16; + int32 @4 :Int32; + int64 @5 :Int64; + uint8 @6 :UInt8; + uint16 @7 :UInt16; + uint32 @8 :UInt32; + uint64 @9 :UInt64; + float32 @10 :Float32; + float64 @11 :Float64; + text @12 :Text; + data @13 :Data; + + list @14 :AnyPointer; + + enum @15 :UInt16; + struct @16 :AnyPointer; + + interface @17 :Void; + # The only interface value that can be represented statically is "null", whose methods always + # throw exceptions. + + anyPointer @18 :AnyPointer; + } +} + +struct Annotation { + # Describes an annotation applied to a declaration. Note AnnotationNode describes the + # annotation's declaration, while this describes a use of the annotation. + + id @0 :Id; + # ID of the annotation node. + + brand @2 :Brand; + # Brand of the annotation. + # + # Note that the annotation itself is not allowed to be parameterized, but its scope might be. + + value @1 :Value; +} + +enum ElementSize { + # Possible element sizes for encoded lists. These correspond exactly to the possible values of + # the 3-bit element size component of a list pointer. + + empty @0; # aka "void", but that's a keyword. + bit @1; + byte @2; + twoBytes @3; + fourBytes @4; + eightBytes @5; + pointer @6; + inlineComposite @7; +} + +struct CapnpVersion { + major @0 :UInt16; + minor @1 :UInt8; + micro @2 :UInt8; +} + +struct CodeGeneratorRequest { + capnpVersion @2 :CapnpVersion; + # Version of the `capnp` executable. Generally, code generators should ignore this, but the code + # generators that ship with `capnp` itself will print a warning if this mismatches since that + # probably indicates something is misconfigured. + # + # The first version of 'capnp' to set this was 0.6.0. So, if it's missing, the compiler version + # is older than that. + + nodes @0 :List(Node); + # All nodes parsed by the compiler, including for the files on the command line and their + # imports. + + sourceInfo @3 :List(Node.SourceInfo); + # Information about the original source code for each node, where available. This array may be + # omitted or may be missing some nodes if no info is available for them. + + requestedFiles @1 :List(RequestedFile); + # Files which were listed on the command line. + + struct RequestedFile { + id @0 :Id; + # ID of the file. + + filename @1 :Text; + # Name of the file as it appeared on the command-line (minus the src-prefix). You may use + # this to decide where to write the output. + + imports @2 :List(Import); + # List of all imported paths seen in this file. + + struct Import { + id @0 :Id; + # ID of the imported file. + + name @1 :Text; + # Name which *this* file used to refer to the foreign file. This may be a relative name. + # This information is provided because it might be useful for code generation, e.g. to + # generate #include directives in C++. We don't put this in Node.file because this + # information is only meaningful at compile time anyway. + # + # (On Zooko's triangle, this is the import's petname according to the importing file.) + } + } +} diff --git a/CapnpC.CSharp.Generator/CapnpCompilation.cs b/CapnpC.CSharp.Generator/CapnpCompilation.cs index 2bbf913..bfef9c5 100644 --- a/CapnpC.CSharp.Generator/CapnpCompilation.cs +++ b/CapnpC.CSharp.Generator/CapnpCompilation.cs @@ -40,7 +40,7 @@ namespace CapnpC.CSharp.Generator { var segments = Framing.ReadSegments(input); var dec = DeserializerState.CreateRoot(segments); - var reader = Schema.CodeGeneratorRequest.Reader.Create(dec); + var reader = Schema.CodeGeneratorRequest.READER.create(dec); var model = Model.SchemaModel.Create(reader); var codeGen = new CodeGen.CodeGenerator(model, options ?? new CodeGen.GeneratorOptions()); return new GenerationResult(codeGen.Generate()); diff --git a/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs b/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs index 2c6a172..64c1f48 100644 --- a/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs +++ b/CapnpC.CSharp.Generator/CodeGen/CommonSnippetGen.cs @@ -40,7 +40,7 @@ namespace CapnpC.CSharp.Generator.CodeGen EqualsValueClause( LiteralExpression( SyntaxKind.NumericLiteralExpression, - Literal(Schema.Field.Reader.NoDiscriminant)))); + Literal(SchemaModel.NoDiscriminant)))); whichEnum = whichEnum.AddMembers(ndecl); diff --git a/CapnpC.CSharp.Generator/Model/SchemaModel.cs b/CapnpC.CSharp.Generator/Model/SchemaModel.cs index 2b75e7c..3262f8f 100644 --- a/CapnpC.CSharp.Generator/Model/SchemaModel.cs +++ b/CapnpC.CSharp.Generator/Model/SchemaModel.cs @@ -8,21 +8,23 @@ namespace CapnpC.CSharp.Generator.Model { class SchemaModel { - readonly Schema.CodeGeneratorRequest.Reader _request; + public const ushort NoDiscriminant = 65535; + + readonly Schema.CodeGeneratorRequest.READER _request; readonly List _generatedFiles = new List(); readonly DefinitionManager _typeDefMgr = new DefinitionManager(); - readonly Dictionary _id2node = new Dictionary(); + readonly Dictionary _id2node = new Dictionary(); readonly Dictionary _id2sourceInfo = new Dictionary(); - public SchemaModel(Schema.CodeGeneratorRequest.Reader request) + public SchemaModel(Schema.CodeGeneratorRequest.READER request) { _request = request; } public IReadOnlyList FilesToGenerate => _generatedFiles; - Schema.Node.Reader? IdToNode(ulong id, bool mustExist) + Schema.Node.READER? IdToNode(ulong id, bool mustExist) { if (_id2node.TryGetValue(id, out var node)) return node; @@ -31,9 +33,9 @@ namespace CapnpC.CSharp.Generator.Model return null; } - Schema.Node.Reader IdToNode(ulong id) + Schema.Node.READER IdToNode(ulong id) { - return (Schema.Node.Reader)IdToNode(id, true); + return (Schema.Node.READER)IdToNode(id, true); } void Build() @@ -76,13 +78,13 @@ namespace CapnpC.CSharp.Generator.Model public IHasNestedDefinitions parent; } - void BuildPass1(Dictionary requestedFiles) + void BuildPass1(Dictionary requestedFiles) { Pass1State state = new Pass1State() { unprocessedNodes = new HashSet(_id2node.Keys) }; - foreach (var node in _id2node.Values.Where(n => n.IsFile)) + foreach (var node in _id2node.Values.Where(n => n.which == Schema.Node.WHICH.File)) { GenFile file; bool isGenerated = requestedFiles.TryGetValue(node.Id, out var req); @@ -118,7 +120,7 @@ namespace CapnpC.CSharp.Generator.Model IDefinition ProcessNodePass1(ulong id, string name, Pass1State state) { bool mustExist = state.parent == null || (state.parent as IDefinition).IsGenerated; - if (!(IdToNode(id, mustExist) is Schema.Node.Reader node)) + if (!(IdToNode(id, mustExist) is Schema.Node.READER node)) return null; if (!state.unprocessedNodes.Remove(id)) return null; @@ -175,18 +177,18 @@ namespace CapnpC.CSharp.Generator.Model { ProcessNodePass1(nested.Id, nested.Name, state); } - if (processFields && node.Fields != null) - foreach (var field in node.Fields.Where(f => f.IsGroup)) + if (processFields && node.Struct.Fields != null) + foreach (var field in node.Struct.Fields.Where(f => f.which == Schema.Field.WHICH.Group)) { - var group = IdToNode(field.Group_TypeId); - if (!group.IsStruct || !group.Struct_IsGroup) + var group = IdToNode(field.Group.TypeId); + if (group.which != Schema.Node.WHICH.Struct || !group.Struct.IsGroup) { throw new InvalidSchemaException($"Expected node with id {group.StrId()} to be a struct definition"); } - ProcessNodePass1(field.Group_TypeId, field.Name, state); + ProcessNodePass1(field.Group.TypeId, field.Name, state); } - if (processInterfaceMethods && node.Interface_Methods != null) - foreach (var method in node.Interface_Methods) + if (processInterfaceMethods && node.Interface.Methods != null) + foreach (var method in node.Interface.Methods) { var pnode = IdToNode(method.ParamStructType); if (pnode.ScopeId == 0) ProcessNodePass1(pnode.Id, null, state); // Anonymous generated type @@ -204,7 +206,7 @@ namespace CapnpC.CSharp.Generator.Model public HashSet processedNodes; } - void BuildPass2(Dictionary requestedFiles) + void BuildPass2(Dictionary requestedFiles) { var state = new Pass2State() { processedNodes = new HashSet() }; foreach (var file in _typeDefMgr.Files) @@ -214,7 +216,7 @@ namespace CapnpC.CSharp.Generator.Model } } - void ProcessNestedNodes(IEnumerable nestedNodes, Pass2State state, bool mustExist) + void ProcessNestedNodes(IEnumerable nestedNodes, Pass2State state, bool mustExist) { foreach (var nestedNode in nestedNodes) { @@ -222,16 +224,16 @@ namespace CapnpC.CSharp.Generator.Model } } - void ProcessBrand(Schema.Brand.Reader brandReader, Type type, Pass2State state) + void ProcessBrand(Schema.Brand.READER brandReader, Type type, Pass2State state) { foreach (var scopeReader in brandReader.Scopes) { var whatToBind = ProcessTypeDef(scopeReader.ScopeId, state); int index = 0; - switch (0) + switch (scopeReader.which) { - case 0 when scopeReader.IsBind: + case Schema.Brand.Scope.WHICH.Bind: foreach (var bindingReader in scopeReader.Bind) { var typeParameter = new GenericParameter() @@ -240,20 +242,20 @@ namespace CapnpC.CSharp.Generator.Model Index = index++ }; - switch (0) + switch (bindingReader.which) { - case 0 when bindingReader.IsType: + case Schema.Brand.Binding.WHICH.Type: type.BindGenericParameter(typeParameter, ProcessType(bindingReader.Type, state)); break; - case 0 when bindingReader.IsUnbound: + case Schema.Brand.Binding.WHICH.Unbound: type.BindGenericParameter(typeParameter, Types.FromParameter(typeParameter)); break; } } break; - case 0 when scopeReader.IsInherit: + case Schema.Brand.Scope.WHICH.Inherit: for (index = 0; index < type.DeclaringType.Definition.GenericParameters.Count; index++) { var typeParameter = new GenericParameter() @@ -269,45 +271,44 @@ namespace CapnpC.CSharp.Generator.Model } } - Type ProcessType(Schema.Type.Reader typeReader, Pass2State state) + Type ProcessType(Schema.Type.READER typeReader, Pass2State state) { Type result; - switch (0) + switch (typeReader.which) { - case 0 when typeReader.IsAnyPointer: - switch (0) + case Schema.Type.WHICH.AnyPointer: + switch (typeReader.AnyPointer.which) { - case 0 when typeReader.AnyPointer_IsParameter: + case Schema.Type.anyPointer.WHICH.Parameter: return Types.FromParameter( new GenericParameter() { - DeclaringEntity = ProcessTypeDef(typeReader.AnyPointer_Parameter_ScopeId, state), - Index = typeReader.AnyPointer_Parameter_ParameterIndex + DeclaringEntity = ProcessTypeDef(typeReader.AnyPointer.Parameter.ScopeId, state), + Index = typeReader.AnyPointer.Parameter.ParameterIndex }); - case 0 when typeReader.AnyPointer_IsImplicitMethodParameter: + case Schema.Type.anyPointer.WHICH.ImplicitMethodParameter: return Types.FromParameter( new GenericParameter() { DeclaringEntity = state.currentMethod ?? throw new InvalidOperationException("current method not set"), - Index = typeReader.AnyPointer_ImplicitMethodParameter_ParameterIndex + Index = typeReader.AnyPointer.ImplicitMethodParameter.ParameterIndex }); - case 0 when typeReader.AnyPointer_IsUnconstrained: - - switch (0) + case Schema.Type.anyPointer.WHICH.Unconstrained: + switch (typeReader.AnyPointer.Unconstrained.which) { - case 0 when typeReader.AnyPointer_Unconstrained_IsAnyKind: + case Schema.Type.anyPointer.unconstrained.WHICH.AnyKind: return Types.AnyPointer; - case 0 when typeReader.AnyPointer_Unconstrained_IsCapability: + case Schema.Type.anyPointer.unconstrained.WHICH.Capability: return Types.CapabilityPointer; - case 0 when typeReader.AnyPointer_Unconstrained_IsList: + case Schema.Type.anyPointer.unconstrained.WHICH.List: return Types.ListPointer; - case 0 when typeReader.AnyPointer_Unconstrained_IsStruct: + case Schema.Type.anyPointer.unconstrained.WHICH.Struct: return Types.StructPointer; default: @@ -318,62 +319,62 @@ namespace CapnpC.CSharp.Generator.Model throw new NotImplementedException(); } - case 0 when typeReader.IsBool: + case Schema.Type.WHICH.Bool: return Types.Bool; - case 0 when typeReader.IsData: + case Schema.Type.WHICH.Data: return Types.Data; - case 0 when typeReader.IsFloat64: + case Schema.Type.WHICH.Float64: return Types.F64; - case 0 when typeReader.IsEnum: - return Types.FromDefinition(ProcessTypeDef(typeReader.Enum_TypeId, state, TypeTag.Enum)); + case Schema.Type.WHICH.Enum: + return Types.FromDefinition(ProcessTypeDef(typeReader.Enum.TypeId, state, TypeTag.Enum)); - case 0 when typeReader.IsFloat32: + case Schema.Type.WHICH.Float32: return Types.F32; - case 0 when typeReader.IsInt16: + case Schema.Type.WHICH.Int16: return Types.S16; - case 0 when typeReader.IsInt32: + case Schema.Type.WHICH.Int32: return Types.S32; - case 0 when typeReader.IsInt64: + case Schema.Type.WHICH.Int64: return Types.S64; - case 0 when typeReader.IsInt8: + case Schema.Type.WHICH.Int8: return Types.S8; - case 0 when typeReader.IsInterface: - result = Types.FromDefinition(ProcessTypeDef(typeReader.Interface_TypeId, state, TypeTag.Interface)); - ProcessBrand(typeReader.Interface_Brand, result, state); + case Schema.Type.WHICH.Interface: + result = Types.FromDefinition(ProcessTypeDef(typeReader.Interface.TypeId, state, TypeTag.Interface)); + ProcessBrand(typeReader.Interface.Brand, result, state); return result; - case 0 when typeReader.IsList: - return Types.List(ProcessType(typeReader.List_ElementType, state)); + case Schema.Type.WHICH.List: + return Types.List(ProcessType(typeReader.List.ElementType, state)); - case 0 when typeReader.IsStruct: - result = Types.FromDefinition(ProcessTypeDef(typeReader.Struct_TypeId, state, TypeTag.Struct)); - ProcessBrand(typeReader.Struct_Brand, result, state); + case Schema.Type.WHICH.Struct: + result = Types.FromDefinition(ProcessTypeDef(typeReader.Struct.TypeId, state, TypeTag.Struct)); + ProcessBrand(typeReader.Struct.Brand, result, state); return result; - case 0 when typeReader.IsText: + case Schema.Type.WHICH.Text: return Types.Text; - case 0 when typeReader.IsUInt16: + case Schema.Type.WHICH.Uint16: return Types.U16; - case 0 when typeReader.IsUInt32: + case Schema.Type.WHICH.Uint32: return Types.U32; - case 0 when typeReader.IsUInt64: + case Schema.Type.WHICH.Uint64: return Types.U64; - case 0 when typeReader.IsUInt8: + case Schema.Type.WHICH.Uint8: return Types.U8; - case 0 when typeReader.IsVoid: + case Schema.Type.WHICH.Void: return Types.Void; default: @@ -381,103 +382,103 @@ namespace CapnpC.CSharp.Generator.Model } } - Value ProcessValue(Schema.Value.Reader valueReader) + Value ProcessValue(Schema.Value.READER valueReader) { var value = new Value(); - switch (0) + switch (valueReader.which) { - case 0 when valueReader.IsAnyPointer: + case Schema.Value.WHICH.AnyPointer: value.ScalarValue = valueReader.AnyPointer; value.Type = Types.AnyPointer; break; - case 0 when valueReader.IsBool: + case Schema.Value.WHICH.Bool: value.ScalarValue = valueReader.Bool; value.Type = Types.Bool; break; - case 0 when valueReader.IsData: - value.Items.AddRange(valueReader.Data.CastByte().Select(Value.Scalar)); + case Schema.Value.WHICH.Data: + value.Items.AddRange(valueReader.Data.Select(Value.Scalar)); value.Type = Types.Data; break; - case 0 when valueReader.IsEnum: + case Schema.Value.WHICH.Enum: value.ScalarValue = valueReader.Enum; value.Type = Types.AnyEnum; break; - case 0 when valueReader.IsFloat32: + case Schema.Value.WHICH.Float32: value.ScalarValue = valueReader.Float32; value.Type = Types.F32; break; - case 0 when valueReader.IsFloat64: + case Schema.Value.WHICH.Float64: value.ScalarValue = valueReader.Float64; value.Type = Types.F64; break; - case 0 when valueReader.IsInt16: + case Schema.Value.WHICH.Int16: value.ScalarValue = valueReader.Int16; value.Type = Types.S16; break; - case 0 when valueReader.IsInt32: + case Schema.Value.WHICH.Int32: value.ScalarValue = valueReader.Int32; value.Type = Types.S32; break; - case 0 when valueReader.IsInt64: + case Schema.Value.WHICH.Int64: value.ScalarValue = valueReader.Int64; value.Type = Types.S64; break; - case 0 when valueReader.IsInt8: + case Schema.Value.WHICH.Int8: value.ScalarValue = valueReader.Int8; value.Type = Types.S8; break; - case 0 when valueReader.IsInterface: + case Schema.Value.WHICH.Interface: value.ScalarValue = null; value.Type = Types.CapabilityPointer; break; - case 0 when valueReader.IsList: + case Schema.Value.WHICH.List: value.RawValue = valueReader.List; value.Type = Types.ListPointer; break; - case 0 when valueReader.IsStruct: + case Schema.Value.WHICH.Struct: value.RawValue = valueReader.Struct; value.Type = Types.StructPointer; break; - case 0 when valueReader.IsText: + case Schema.Value.WHICH.Text: value.ScalarValue = valueReader.Text; value.Type = Types.Text; break; - case 0 when valueReader.IsUInt16: - value.ScalarValue = valueReader.UInt16; + case Schema.Value.WHICH.Uint16: + value.ScalarValue = valueReader.Uint16; value.Type = Types.U16; break; - case 0 when valueReader.IsUInt32: - value.ScalarValue = valueReader.UInt32; + case Schema.Value.WHICH.Uint32: + value.ScalarValue = valueReader.Uint32; value.Type = Types.U32; break; - case 0 when valueReader.IsUInt64: - value.ScalarValue = valueReader.UInt64; + case Schema.Value.WHICH.Uint64: + value.ScalarValue = valueReader.Uint64; value.Type = Types.U64; break; - case 0 when valueReader.IsUInt8: - value.ScalarValue = valueReader.UInt8; + case Schema.Value.WHICH.Uint8: + value.ScalarValue = valueReader.Uint8; value.Type = Types.U8; break; - case 0 when valueReader.IsVoid: + case Schema.Value.WHICH.Void: value.Type = Types.Void; break; @@ -488,14 +489,14 @@ namespace CapnpC.CSharp.Generator.Model return value; } - void ProcessFields(Schema.Node.Reader reader, TypeDefinition declaringType, List fields, Pass2State state) + void ProcessFields(Schema.Node.READER reader, TypeDefinition declaringType, List fields, Pass2State state) { - if (reader.Fields == null) + if (reader.Struct.Fields == null) { return; } - foreach (var fieldReader in reader.Fields) + foreach (var fieldReader in reader.Struct.Fields) { var field = new Field() { @@ -505,25 +506,25 @@ namespace CapnpC.CSharp.Generator.Model CodeOrder = fieldReader.CodeOrder }; - if (fieldReader.DiscriminantValue != Schema.Field.Reader.NoDiscriminant) + if (fieldReader.DiscriminantValue != NoDiscriminant) { field.DiscValue = fieldReader.DiscriminantValue; } - switch (0) + switch (fieldReader.which) { - case 0 when fieldReader.IsGroup: - var def = ProcessTypeDef(fieldReader.Group_TypeId, state, TypeTag.Group); + case Schema.Field.WHICH.Group: + var def = ProcessTypeDef(fieldReader.Group.TypeId, state, TypeTag.Group); field.Type = Types.FromDefinition(def); def.CsName = field.CsName; // Type definitions for unions are artificially generated. // Transfer the C# name of the using field. break; - case 0 when fieldReader.IsSlot: - field.DefaultValue = ProcessValue(fieldReader.Slot_DefaultValue); - field.DefaultValueIsExplicit = fieldReader.Slot_HadExplicitDefault; - field.Offset = fieldReader.Slot_Offset; - field.Type = ProcessType(fieldReader.Slot_Type, state); + case Schema.Field.WHICH.Slot: + field.DefaultValue = ProcessValue(fieldReader.Slot.DefaultValue); + field.DefaultValueIsExplicit = fieldReader.Slot.HadExplicitDefault; + field.Offset = fieldReader.Slot.Offset; + field.Type = ProcessType(fieldReader.Slot.Type, state); field.DefaultValue.Type = field.Type; break; @@ -537,7 +538,7 @@ namespace CapnpC.CSharp.Generator.Model } } - TypeDefinition ProcessInterfaceOrStructTail(TypeDefinition def, Schema.Node.Reader reader, Pass2State state) + TypeDefinition ProcessInterfaceOrStructTail(TypeDefinition def, Schema.Node.READER reader, Pass2State state) { def.IsGeneric = reader.IsGeneric; @@ -553,9 +554,9 @@ namespace CapnpC.CSharp.Generator.Model ProcessFields(reader, def, def.Fields, state); - if (reader.IsInterface) + if (reader.which == Schema.Node.WHICH.Interface) { - foreach (var methodReader in reader.Interface_Methods) + foreach (var methodReader in reader.Interface.Methods) { var method = new Method() { @@ -608,22 +609,22 @@ namespace CapnpC.CSharp.Generator.Model return def; } - TypeDefinition ProcessStruct(Schema.Node.Reader structReader, TypeDefinition def, Pass2State state) + TypeDefinition ProcessStruct(Schema.Node.READER structReader, TypeDefinition def, Pass2State state) { - def.StructDataWordCount = structReader.Struct_DataWordCount; - def.StructPointerCount = structReader.Struct_PointerCount; + def.StructDataWordCount = structReader.Struct.DataWordCount; + def.StructPointerCount = structReader.Struct.PointerCount; - if (structReader.Struct_DiscriminantCount > 0) + if (structReader.Struct.DiscriminantCount > 0) { def.UnionInfo = new TypeDefinition.DiscriminationInfo( - structReader.Struct_DiscriminantCount, - 16u * structReader.Struct_DiscriminantOffset); + structReader.Struct.DiscriminantCount, + 16u * structReader.Struct.DiscriminantOffset); } return ProcessInterfaceOrStructTail(def, structReader, state); } - TypeDefinition ProcessParameterList(Schema.Node.Reader reader, Schema.Brand.Reader brandReader, List list, Pass2State state) + TypeDefinition ProcessParameterList(Schema.Node.READER reader, Schema.Brand.READER brandReader, List list, Pass2State state) { //# If a named parameter list was specified in the method //# declaration (rather than a single struct parameter type) then a corresponding struct type is @@ -633,7 +634,7 @@ namespace CapnpC.CSharp.Generator.Model //# this a situation where you can't just climb the scope chain to find where a particular //# generic parameter was introduced. Making the `scopeId` zero was a mistake.) - if (!reader.IsStruct) + if (reader.which != Schema.Node.WHICH.Struct) { throw new InvalidSchemaException("Expected a struct"); } @@ -657,9 +658,9 @@ namespace CapnpC.CSharp.Generator.Model } } - TypeDefinition ProcessInterface(Schema.Node.Reader ifaceReader, TypeDefinition def, Pass2State state) + TypeDefinition ProcessInterface(Schema.Node.READER ifaceReader, TypeDefinition def, Pass2State state) { - foreach (var superClassReader in ifaceReader.Interface_Superclasses) + foreach (var superClassReader in ifaceReader.Interface.Superclasses) { var superClass = Types.FromDefinition(ProcessTypeDef(superClassReader.Id, state, TypeTag.Interface)); ProcessBrand(superClassReader.Brand, superClass, state); @@ -669,9 +670,9 @@ namespace CapnpC.CSharp.Generator.Model return ProcessInterfaceOrStructTail(def, ifaceReader, state); } - TypeDefinition ProcessEnum(Schema.Node.Reader enumReader, TypeDefinition def, Pass2State state) + TypeDefinition ProcessEnum(Schema.Node.READER enumReader, TypeDefinition def, Pass2State state) { - foreach (var fieldReader in enumReader.Enumerants) + foreach (var fieldReader in enumReader.Enum.Enumerants) { var field = new Enumerant() { @@ -681,20 +682,15 @@ namespace CapnpC.CSharp.Generator.Model CodeOrder = fieldReader.CodeOrder }; - if (fieldReader.Ordinal_IsExplicit) - { - field.Ordinal = fieldReader.Ordinal_Explicit; - } - def.Enumerants.Add(field); } return def; } - Constant ProcessConst(Schema.Node.Reader constReader, Constant @const, Pass2State state) + Constant ProcessConst(Schema.Node.READER constReader, Constant @const, Pass2State state) { - var value = ProcessValue(constReader.Const_Value); - value.Type = ProcessType(constReader.Const_Type, state); + var value = ProcessValue(constReader.Const.Value); + value.Type = ProcessType(constReader.Const.Type, state); @const.Value = value; return @const; } @@ -712,7 +708,7 @@ namespace CapnpC.CSharp.Generator.Model IDefinition ProcessNode(ulong id, Pass2State state, bool mustExist, TypeTag tag = default) { - if (!(IdToNode(id, mustExist) is Schema.Node.Reader node)) return null; + if (!(IdToNode(id, mustExist) is Schema.Node.READER node)) return null; var kind = node.GetKind(); if (tag == TypeTag.Unknown) tag = kind.GetTypeTag(); var def = _typeDefMgr.GetExistingDef(id, tag); @@ -737,7 +733,7 @@ namespace CapnpC.CSharp.Generator.Model } } - public static SchemaModel Create(Schema.CodeGeneratorRequest.Reader request) + public static SchemaModel Create(Schema.CodeGeneratorRequest.READER request) { var model = new SchemaModel(request); model.Build(); @@ -759,22 +755,24 @@ namespace CapnpC.CSharp.Generator.Model public static class SchemaExtensions { - public static string StrId(this Schema.Node.Reader node) + public static string StrId(this Schema.Node.READER node) => $"0x{node.Id:X}"; public static string StrId(this ulong nodeId) => $"0x{nodeId:X}"; - public static NodeKind GetKind(this Schema.Node.Reader node) + public static NodeKind GetKind(this Schema.Node.READER node) { - if (node.IsStruct) - return node.Struct_IsGroup ? NodeKind.Group : NodeKind.Struct; - if (node.IsInterface) return NodeKind.Interface; - if (node.IsEnum) return NodeKind.Enum; - if (node.IsConst) return NodeKind.Const; - if (node.IsAnnotation) return NodeKind.Annotation; - if (node.IsFile) return NodeKind.File; - return NodeKind.Unknown; + switch (node.which) + { + case Schema.Node.WHICH.Struct: return node.Struct.IsGroup ? NodeKind.Group : NodeKind.Struct; + case Schema.Node.WHICH.Interface: return NodeKind.Interface; + case Schema.Node.WHICH.Enum: return NodeKind.Enum; + case Schema.Node.WHICH.Const: return NodeKind.Const; + case Schema.Node.WHICH.Annotation: return NodeKind.Annotation; + case Schema.Node.WHICH.File: return NodeKind.File; + default: return NodeKind.Unknown; + } } internal static TypeTag GetTypeTag(this NodeKind kind) @@ -789,7 +787,6 @@ namespace CapnpC.CSharp.Generator.Model } } - internal static TypeTag GetTypeTag(this Schema.Node.Reader node) - => node.GetKind().GetTypeTag(); + internal static TypeTag GetTypeTag(this Schema.Node.READER node) => node.GetKind().GetTypeTag(); } } diff --git a/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs b/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs index 5985170..feb3980 100644 --- a/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs +++ b/CapnpC.CSharp.Generator/Model/SupportedAnnotations.cs @@ -31,7 +31,7 @@ namespace CapnpC.CSharp.Generator.Model Internal = 1 } - public static string[] GetNamespaceAnnotation(Schema.Node.Reader fileNode) + public static string[] GetNamespaceAnnotation(Schema.Node.READER fileNode) { foreach (var annotation in fileNode.Annotations) { @@ -48,7 +48,7 @@ namespace CapnpC.CSharp.Generator.Model return null; } - public static string GetCsName(Schema.Field.Reader node) + public static string GetCsName(Schema.Field.READER node) { foreach (var annotation in node.Annotations) { @@ -60,7 +60,7 @@ namespace CapnpC.CSharp.Generator.Model return null; } - public static string GetCsName(Schema.Node.Reader node) + public static string GetCsName(Schema.Enumerant.READER node) { foreach (var annotation in node.Annotations) { @@ -72,7 +72,7 @@ namespace CapnpC.CSharp.Generator.Model return null; } - public static string GetCsName(Schema.Method.Reader node) + public static string GetCsName(Schema.Node.READER node) { foreach (var annotation in node.Annotations) { @@ -84,11 +84,23 @@ namespace CapnpC.CSharp.Generator.Model return null; } - public static bool? GetNullableEnable(Schema.Node.Reader node) + public static string GetCsName(Schema.Method.READER node) { foreach (var annotation in node.Annotations) { - if (annotation.Id == AnnotationIds.Cs.NullableEnable && annotation.Value.IsBool) + if (annotation.Id == AnnotationIds.Cs.Name) + { + return annotation.Value.Text; + } + } + return null; + } + + public static bool? GetNullableEnable(Schema.Node.READER node) + { + foreach (var annotation in node.Annotations) + { + if (annotation.Id == AnnotationIds.Cs.NullableEnable && annotation.Value.which == Schema.Value.WHICH.Bool) { return annotation.Value.Bool; } @@ -96,11 +108,11 @@ namespace CapnpC.CSharp.Generator.Model return null; } - public static bool? GetEmitNullableDirective(Schema.Node.Reader node) + public static bool? GetEmitNullableDirective(Schema.Node.READER node) { foreach (var annotation in node.Annotations) { - if (annotation.Id == AnnotationIds.Cs.EmitNullableDirective && annotation.Value.IsBool) + if (annotation.Id == AnnotationIds.Cs.EmitNullableDirective && annotation.Value.which == Schema.Value.WHICH.Bool) { return annotation.Value.Bool; } @@ -108,11 +120,11 @@ namespace CapnpC.CSharp.Generator.Model return null; } - public static bool? GetEmitDomainClassesAndInterfaces(Schema.Node.Reader node) + public static bool? GetEmitDomainClassesAndInterfaces(Schema.Node.READER node) { foreach (var annotation in node.Annotations) { - if (annotation.Id == AnnotationIds.Cs.EmitDomainClassesAndInterfaces && annotation.Value.IsBool) + if (annotation.Id == AnnotationIds.Cs.EmitDomainClassesAndInterfaces && annotation.Value.which == Schema.Value.WHICH.Bool) { return annotation.Value.Bool; } @@ -120,11 +132,11 @@ namespace CapnpC.CSharp.Generator.Model return null; } - public static TypeVisibility? GetTypeVisibility(Schema.Node.Reader node) + public static TypeVisibility? GetTypeVisibility(Schema.Node.READER node) { foreach (var annotation in node.Annotations) { - if (annotation.Id == AnnotationIds.Cs.TypeVisibility && annotation.Value.IsEnum) + if (annotation.Id == AnnotationIds.Cs.TypeVisibility && annotation.Value.which == Schema.Value.WHICH.Enum) { return (TypeVisibility)annotation.Value.Enum; } diff --git a/CapnpC.CSharp.Generator/Schema/SchemaSerialization.cs b/CapnpC.CSharp.Generator/Schema/SchemaSerialization.cs index 0655f7d..81729b4 100644 --- a/CapnpC.CSharp.Generator/Schema/SchemaSerialization.cs +++ b/CapnpC.CSharp.Generator/Schema/SchemaSerialization.cs @@ -1,1575 +1,4381 @@ -using Capnp; +#pragma warning disable CS1591 +using Capnp; +using Capnp.Rpc; +using System; +using System.CodeDom.Compiler; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; namespace CapnpC.CSharp.Generator.Schema { - namespace Superclass + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe682ab4cf923a417UL)] + public class Node : ICapnpSerializable { - public struct Reader + public const UInt64 typeId = 0xe682ab4cf923a417UL; + public enum WHICH : ushort { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public ulong Id => State.ReadDataULong(0); - public Brand.Reader Brand => State.ReadStruct(0, Schema.Brand.Reader.Create); + File = 0, + Struct = 1, + Enum = 2, + Interface = 3, + Const = 4, + Annotation = 5, + undefined = 65535 } - public class Writer: SerializerState + void ICapnpSerializable.Deserialize(DeserializerState arg_) { - public Writer() + var reader = READER.create(arg_); + switch (reader.which) { - SetStruct(1, 1); + case WHICH.File: + which = reader.which; + break; + case WHICH.Struct: + Struct = CapnpSerializable.Create(reader.Struct); + break; + case WHICH.Enum: + Enum = CapnpSerializable.Create(reader.Enum); + break; + case WHICH.Interface: + Interface = CapnpSerializable.Create(reader.Interface); + break; + case WHICH.Const: + Const = CapnpSerializable.Create(reader.Const); + break; + case WHICH.Annotation: + Annotation = CapnpSerializable.Create(reader.Annotation); + break; + } + + Id = reader.Id; + DisplayName = reader.DisplayName; + DisplayNamePrefixLength = reader.DisplayNamePrefixLength; + ScopeId = reader.ScopeId; + NestedNodes = reader.NestedNodes?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + Annotations = reader.Annotations?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + Parameters = reader.Parameters?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + IsGeneric = reader.IsGeneric; + applyDefaults(); + } + + private WHICH _which = WHICH.undefined; + private object _content; + public WHICH which + { + get => _which; + set + { + if (value == _which) + return; + _which = value; + switch (value) + { + case WHICH.File: + break; + case WHICH.Struct: + _content = null; + break; + case WHICH.Enum: + _content = null; + break; + case WHICH.Interface: + _content = null; + break; + case WHICH.Const: + _content = null; + break; + case WHICH.Annotation: + _content = null; + break; + } + } + } + + public void serialize(WRITER writer) + { + writer.which = which; + switch (which) + { + case WHICH.File: + break; + case WHICH.Struct: + Struct?.serialize(writer.Struct); + break; + case WHICH.Enum: + Enum?.serialize(writer.Enum); + break; + case WHICH.Interface: + Interface?.serialize(writer.Interface); + break; + case WHICH.Const: + Const?.serialize(writer.Const); + break; + case WHICH.Annotation: + Annotation?.serialize(writer.Annotation); + break; + } + + writer.Id = Id; + writer.DisplayName = DisplayName; + writer.DisplayNamePrefixLength = DisplayNamePrefixLength; + writer.ScopeId = ScopeId; + writer.NestedNodes.Init(NestedNodes, (_s1, _v1) => _v1?.serialize(_s1)); + writer.Annotations.Init(Annotations, (_s1, _v1) => _v1?.serialize(_s1)); + writer.Parameters.Init(Parameters, (_s1, _v1) => _v1?.serialize(_s1)); + writer.IsGeneric = IsGeneric; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong Id + { + get; + set; + } + + public string DisplayName + { + get; + set; + } + + public uint DisplayNamePrefixLength + { + get; + set; + } + + public ulong ScopeId + { + get; + set; + } + + public IReadOnlyList NestedNodes + { + get; + set; + } + + public IReadOnlyList Annotations + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Node.@struct Struct + { + get => _which == WHICH.Struct ? (CapnpC.CSharp.Generator.Schema.Node.@struct)_content : null; + set + { + _which = WHICH.Struct; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Node.@enum Enum + { + get => _which == WHICH.Enum ? (CapnpC.CSharp.Generator.Schema.Node.@enum)_content : null; + set + { + _which = WHICH.Enum; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Node.@interface Interface + { + get => _which == WHICH.Interface ? (CapnpC.CSharp.Generator.Schema.Node.@interface)_content : null; + set + { + _which = WHICH.Interface; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Node.@const Const + { + get => _which == WHICH.Const ? (CapnpC.CSharp.Generator.Schema.Node.@const)_content : null; + set + { + _which = WHICH.Const; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Node.annotation Annotation + { + get => _which == WHICH.Annotation ? (CapnpC.CSharp.Generator.Schema.Node.annotation)_content : null; + set + { + _which = WHICH.Annotation; + _content = value; + } + } + + public IReadOnlyList Parameters + { + get; + set; + } + + public bool IsGeneric + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public WHICH which => (WHICH)ctx.ReadDataUShort(96U, (ushort)0); + public ulong Id => ctx.ReadDataULong(0UL, 0UL); + public string DisplayName => ctx.ReadText(0, null); + public uint DisplayNamePrefixLength => ctx.ReadDataUInt(64UL, 0U); + public ulong ScopeId => ctx.ReadDataULong(128UL, 0UL); + public IReadOnlyList NestedNodes => ctx.ReadList(1).Cast(CapnpC.CSharp.Generator.Schema.Node.NestedNode.READER.create); + public IReadOnlyList Annotations => ctx.ReadList(2).Cast(CapnpC.CSharp.Generator.Schema.Annotation.READER.create); + public @struct.READER Struct => which == WHICH.Struct ? new @struct.READER(ctx) : default; + public @enum.READER Enum => which == WHICH.Enum ? new @enum.READER(ctx) : default; + public @interface.READER Interface => which == WHICH.Interface ? new @interface.READER(ctx) : default; + public @const.READER Const => which == WHICH.Const ? new @const.READER(ctx) : default; + public annotation.READER Annotation => which == WHICH.Annotation ? new annotation.READER(ctx) : default; + public IReadOnlyList Parameters => ctx.ReadList(5).Cast(CapnpC.CSharp.Generator.Schema.Node.Parameter.READER.create); + public bool IsGeneric => ctx.ReadDataBool(288UL, false); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(5, 6); + } + + public WHICH which + { + get => (WHICH)this.ReadDataUShort(96U, (ushort)0); + set => this.WriteData(96U, (ushort)value, (ushort)0); } public ulong Id { - get => this.ReadDataULong(0); - set => this.WriteData(0, value); - } - - public Brand.Writer Brand - { - get => BuildPointer(0); - set => Link(0, value); - } - } - } - - namespace Method - { - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public string Name => State.ReadText(0); - public ushort CodeOrder => State.ReadDataUShort(0); - public IReadOnlyList ImplicitParameters => State.ReadListOfStructs(4, Node.Parameter.Reader.Create); - public ulong ParamStructType => State.ReadDataULong(64); - public Brand.Reader ParamBrand => State.ReadStruct(2, Brand.Reader.Create); - public ulong ResultStructType => State.ReadDataULong(128); - public Brand.Reader ResultBrand => State.ReadStruct(3, Brand.Reader.Create); - public IReadOnlyList Annotations => State.ReadListOfStructs(1, Annotation.Reader.Create); - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(5, 3); - } - - public string Name - { - get => ReadText(0); - set => WriteText(0, value); - } - - public ushort CodeOrder - { - get => this.ReadDataUShort(0); - set => this.WriteData(0, value); - } - - public ListOfStructsSerializer ImplicitParameters - { - get => BuildPointer>(4); - set => Link(4, value); - } - - public ref ulong ParamStructType => ref this.RefData(8); - - public Brand.Writer ParamBrand - { - get => BuildPointer(2); - set => Link(2, value); - } - - public ulong ResultStructType - { - get => this.ReadDataULong(128); - set => this.WriteData(128, value); - } - - public Brand.Writer ResultBrand - { - get => BuildPointer(3); - set => Link(3, value); - } - - public ListOfStructsSerializer Annotations - { - get => BuildPointer>(1); - set => Link(1, value); - } - } - } - - namespace Type - { - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public ushort Tag => State.ReadDataUShort(0); - public bool IsVoid => Tag == 0; - public bool IsBool => Tag == 1; - public bool IsInt8 => Tag == 2; - public bool IsInt16 => Tag == 3; - public bool IsInt32 => Tag == 4; - public bool IsInt64 => Tag == 5; - public bool IsUInt8 => Tag == 6; - public bool IsUInt16 => Tag == 7; - public bool IsUInt32 => Tag == 8; - public bool IsUInt64 => Tag == 9; - public bool IsFloat32 => Tag == 10; - public bool IsFloat64 => Tag == 11; - public bool IsText => Tag == 12; - public bool IsData => Tag == 13; - public bool IsList => Tag == 14; - public Reader List_ElementType => IsList ? State.ReadStruct(0, Create) : default; - public bool IsEnum => Tag == 15; - public ulong Enum_TypeId => IsEnum ? State.ReadDataULong(64) : 0; - public Brand.Reader Enum_Brand => IsEnum ? State.ReadStruct(0, Brand.Reader.Create) : default; - public bool IsStruct => Tag == 16; - public ulong Struct_TypeId => IsStruct ? State.ReadDataULong(64) : 0; - public Brand.Reader Struct_Brand => IsStruct ? State.ReadStruct(0, Brand.Reader.Create) : default; - public bool IsInterface => Tag == 17; - public ulong Interface_TypeId => IsInterface ? State.ReadDataULong(64) : 0; - public Brand.Reader Interface_Brand => IsInterface ? State.ReadStruct(0, Brand.Reader.Create) : default; - public bool IsAnyPointer => Tag == 18; - public ushort AnyPointer_Tag => IsAnyPointer ? State.ReadDataUShort(64) : default; - public bool AnyPointer_IsUnconstrained => IsAnyPointer && AnyPointer_Tag == 0; - public ushort AnyPointer_Unconstrained_Tag => AnyPointer_IsUnconstrained ? State.ReadDataUShort(80) : (ushort)0; - public bool AnyPointer_Unconstrained_IsAnyKind => AnyPointer_IsUnconstrained && AnyPointer_Unconstrained_Tag == 0; - public bool AnyPointer_Unconstrained_IsStruct => AnyPointer_IsUnconstrained && AnyPointer_Unconstrained_Tag == 1; - public bool AnyPointer_Unconstrained_IsList => AnyPointer_IsUnconstrained && AnyPointer_Unconstrained_Tag == 2; - public bool AnyPointer_Unconstrained_IsCapability => AnyPointer_IsUnconstrained && AnyPointer_Unconstrained_Tag == 3; - public bool AnyPointer_IsParameter => IsAnyPointer && AnyPointer_Tag == 1; - public ulong AnyPointer_Parameter_ScopeId => AnyPointer_IsParameter ? State.ReadDataULong(128) : 0; - public ushort AnyPointer_Parameter_ParameterIndex => AnyPointer_IsParameter ? State.ReadDataUShort(80) : (ushort)0; - public bool AnyPointer_IsImplicitMethodParameter => AnyPointer_Tag == 2; - public ushort AnyPointer_ImplicitMethodParameter_ParameterIndex => AnyPointer_IsImplicitMethodParameter ? State.ReadDataUShort(80) : default; - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(3, 1); - } - - public ref ushort Tag => ref this.RefData(0); - - public bool IsVoid - { - get => Tag == 0; - set => Tag = 0; - } - - public bool IsBool - { - get => Tag == 1; - set => Tag = 1; - } - - public bool IsInt8 - { - get => Tag == 2; - set => Tag = 2; - } - - public bool IsInt16 - { - get => Tag == 3; - set => Tag = 3; - } - - public bool IsInt32 - { - get => Tag == 4; - set => Tag = 4; - } - - public bool IsInt64 - { - get => Tag == 5; - set => Tag = 5; - } - - public bool IsUInt8 - { - get => Tag == 6; - set => Tag = 6; - } - - public bool IsUInt16 - { - get => Tag == 7; - set => Tag = 7; - } - - public bool IsUInt32 - { - get => Tag == 8; - set => Tag = 8; - } - - public bool IsUInt64 - { - get => Tag == 9; - set => Tag = 9; - } - - public bool IsFloat32 - { - get => Tag == 10; - set => Tag = 10; - } - - public bool IsFloat64 - { - get => Tag == 11; - set => Tag = 11; - } - - public bool IsText - { - get => Tag == 12; - set => Tag = 12; - } - - public bool IsData - { - get => Tag == 13; - set => Tag = 13; - } - - public bool IsList - { - get => Tag == 14; - set => Tag = 14; - } - - public Writer List_ElementType - { - get => IsList ? BuildPointer(0) : default; - set { Link(0, value); } - } - - public bool IsEnum - { - get => Tag == 15; - set => Tag = 15; - } - - public ulong Enum_TypeId - { - get => IsEnum ? this.ReadDataULong(64) : 0; - set { this.WriteData(64, value); } - } - - public Brand.Writer Enum_Brand - { - get => IsEnum ? BuildPointer(0) : default; - set => Link(0, value); - } - - public bool IsStruct - { - get => Tag == 16; - set => Tag = 16; - } - - public ulong Struct_TypeId - { - get => IsStruct ? this.ReadDataULong(64) : 0; - set => this.WriteData(64, value); - } - - public Brand.Writer Struct_Brand - { - get => IsStruct ? BuildPointer(0) : default; - set => Link(0, value); - } - - public bool IsInterface - { - get => Tag == 17; - set => Tag = 17; - } - - public ulong Interface_TypeId - { - get => IsStruct ? this.ReadDataULong(64) : 0; - set => this.WriteData(64, value); - } - - public Brand.Writer Interface_Brand - { - get => IsStruct ? BuildPointer(0) : default; - set => Link(0, value); - } - - public bool IsAnyPointer - { - get => Tag == 18; - set => Tag = 18; - } - - public ushort AnyPointer_Tag - { - get => IsAnyPointer ? this.ReadDataUShort(64) : default; - set => this.WriteData(64, value); - } - - public bool AnyPointer_IsUnconstrained - { - get => IsAnyPointer && AnyPointer_Tag == 0; - set => AnyPointer_Tag = 0; - } - - public ushort AnyPointer_Unconstrained_Tag - { - get => AnyPointer_IsUnconstrained ? this.ReadDataUShort(80) : (ushort)0; - set => this.WriteData(80, value); - } - - public bool AnyPointer_Unconstrained_IsAnyKind - { - get => AnyPointer_IsUnconstrained && AnyPointer_Unconstrained_Tag == 0; - set => AnyPointer_Unconstrained_Tag = 0; - } - - public bool AnyPointer_Unconstrained_IsStruct - { - get => AnyPointer_IsUnconstrained && AnyPointer_Unconstrained_Tag == 1; - set => AnyPointer_Unconstrained_Tag = 1; - } - - public bool AnyPointer_Unconstrained_IsList - { - get => AnyPointer_IsUnconstrained && AnyPointer_Unconstrained_Tag == 2; - set => AnyPointer_Unconstrained_Tag = 2; - } - - public bool AnyPointer_Unconstrained_IsCapability - { - get => AnyPointer_IsUnconstrained && AnyPointer_Unconstrained_Tag == 3; - set => AnyPointer_Unconstrained_Tag = 3; - } - - public bool AnyPointer_IsParameter - { - get => IsAnyPointer && AnyPointer_Tag == 1; - set => AnyPointer_Tag = 1; - } - - public ulong AnyPointer_Parameter_ScopeId - { - get => AnyPointer_IsParameter ? this.ReadDataULong(128) : 0; - set => this.WriteData(128, value); - } - - public ushort AnyPointer_Parameter_ParameterIndex - { - get => AnyPointer_IsParameter ? this.ReadDataUShort(80) : (ushort)0; - set => this.WriteData(80, value); - } - - public bool AnyPointer_IsImplicitMethodParameter - { - get => AnyPointer_Tag == 2; - set => AnyPointer_Tag = 2; - } - - public ushort AnyPointer_ImplicitMethodParameter_ParameterIndex - { - get => AnyPointer_IsImplicitMethodParameter ? this.ReadDataUShort(80) : default; - set => this.WriteData(80, value); - } - } - } - - namespace Brand - { - namespace Scope - { - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public ulong ScopeId => State.ReadDataULong(0); - public ushort Tag => State.ReadDataUShort(64); - public bool IsBind => Tag == 0; - public IReadOnlyList Bind => IsBind ? State.ReadListOfStructs(0, Binding.Reader.Create) : null; - public bool IsInherit => Tag == 1; - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(2, 1); - } - - public ulong ScopeId - { - get => this.ReadDataULong(0); - set => this.WriteData(0, value); - } - - public ushort Tag - { - get => this.ReadDataUShort(64); - set => this.WriteData(64, value); - } - - public bool IsBind - { - get => Tag == 0; - set => Tag = 0; - } - - public ListOfStructsSerializer Bind - { - get => IsBind ? BuildPointer>(0) : default; - set => Link(0, value); - } - - public bool IsInherit - { - get => Tag == 1; - set => Tag = 1; - } - } - - namespace Binding - { - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public ushort Tag => State.ReadDataUShort(0); - public bool IsUnbound => Tag == 0; - public bool IsType => Tag == 1; - public Type.Reader Type => IsType ? State.ReadStruct(0, Schema.Type.Reader.Create) : default; - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(1, 1); - } - - public ushort Tag - { - get => this.ReadDataUShort(0); - set => this.WriteData(0, value); - } - - public bool IsUnbound - { - get => Tag == 0; - set => Tag = 0; - } - - public bool IsType - { - get => Tag == 1; - set => Tag = 1; - } - - public Type.Writer Type - { - get => IsType ? BuildPointer(0) : default; - set => Link(0, value); - } - } - } - } - - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public IReadOnlyList Scopes => State.ReadListOfStructs(0, Scope.Reader.Create); - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(0, 1); - } - - public ListOfStructsSerializer Scopes - { - get => BuildPointer>(0); - set => Link(0, value); - } - } - } - - namespace Value - { - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public ushort Tag => State.ReadDataUShort(0); - public bool IsVoid => Tag == 0; - public bool IsBool => Tag == 1; - public bool Bool => IsBool ? State.ReadDataBool(16) : default; - public bool IsInt8 => Tag == 2; - public sbyte Int8 => IsInt8 ? State.ReadDataSByte(16) : default; - public bool IsInt16 => Tag == 3; - public short Int16 => IsInt16 ? State.ReadDataShort(16) : default; - public bool IsInt32 => Tag == 4; - public int Int32 => IsInt32 ? State.ReadDataInt(32) : default; - public bool IsInt64 => Tag == 5; - public long Int64 => IsInt64 ? State.ReadDataLong(64) : default; - public bool IsUInt8 => Tag == 6; - public byte UInt8 => IsUInt8 ? State.ReadDataByte(16) : default; - public bool IsUInt16 => Tag == 7; - public ushort UInt16 => IsUInt16 ? State.ReadDataUShort(16) : default; - public bool IsUInt32 => Tag == 8; - public uint UInt32 => IsUInt32 ? State.ReadDataUInt(32) : default; - public bool IsUInt64 => Tag == 9; - public ulong UInt64 => IsUInt64 ? State.ReadDataULong(64) : default; - public bool IsFloat32 => Tag == 10; - public float Float32 => IsFloat32 ? State.ReadDataFloat(32) : default; - public bool IsFloat64 => Tag == 11; - public double Float64 => IsFloat64 ? State.ReadDataDouble(64) : default; - public bool IsText => Tag == 12; - public string Text => IsText ? State.ReadText(0) : default; - public bool IsData => Tag == 13; - public ListDeserializer Data => IsData ? State.ReadList(0) : default; - public bool IsList => Tag == 14; - public DeserializerState List => IsList ? State.StructReadPointer(0) : default; - public bool IsEnum => Tag == 15; - public ushort Enum => IsEnum ? State.ReadDataUShort(16) : default; - public bool IsStruct => Tag == 16; - public DeserializerState Struct => IsStruct ? State.StructReadPointer(0) : default; - public bool IsInterface => Tag == 17; - public bool IsAnyPointer => Tag == 18; - public DeserializerState AnyPointer => IsAnyPointer ? State.StructReadPointer(0) : default; - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(2, 1); - } - - public ushort Tag - { - get => this.ReadDataUShort(0); - set => this.WriteData(0, value); - } - - public bool IsVoid - { - get => Tag == 0; - set => Tag = 0; - } - - public bool IsBool - { - get => Tag == 1; - set => Tag = 1; - } - - public bool Bool - { - get => IsBool ? this.ReadDataBool(16) : default; - set => this.WriteData(16, value); - } - - public bool IsInt8 - { - get => Tag == 2; - set => Tag = 2; - } - - public sbyte Int8 - { - get => IsInt8 ? this.ReadDataSByte(16) : default; - set => this.WriteData(16, value); - } - - public bool IsInt16 - { - get => Tag == 3; - set => Tag = 3; - } - - public short Int16 - { - get => IsInt16 ? this.ReadDataShort(16) : default; - set => this.WriteData(16, value); - } - - public bool IsInt32 - { - get => Tag == 4; - set => Tag = 4; - } - - public int Int32 - { - get => IsInt32 ? this.ReadDataInt(32) : default; - set => this.WriteData(32, value); - } - - public bool IsInt64 - { - get => Tag == 5; - set => Tag = 5; - } - - public long Int64 - { - get => IsInt64 ? this.ReadDataLong(64) : default; - set => this.WriteData(64, value); - } - - public bool IsUInt8 - { - get => Tag == 6; - set => Tag = 6; - } - - public byte UInt8 - { - get => IsUInt8 ? this.ReadDataByte(16) : default; - set => this.WriteData(16, value); - } - - public bool IsUInt16 - { - get => Tag == 7; - set => Tag = 7; - } - - public ushort UInt16 - { - get => IsUInt16 ? this.ReadDataUShort(16) : default; - set => this.WriteData(16, value); - } - - public bool IsUInt32 - { - get => Tag == 8; - set => Tag = 8; - } - - public uint UInt32 - { - get => IsUInt32 ? this.ReadDataUInt(32) : default; - set => this.WriteData(32, value); - } - - public bool IsUInt64 - { - get => Tag == 9; - set => Tag = 9; - } - - public ulong UInt64 - { - get => IsUInt64 ? this.ReadDataULong(64) : default; - set => this.WriteData(64, value); - } - - public bool IsFloat32 - { - get => Tag == 10; - set => Tag = 10; - } - - public float Float32 - { - get => IsFloat32 ? this.ReadDataFloat(32) : default; - set => this.WriteData(32, value); - } - - public bool IsFloat64 - { - get => Tag == 11; - set => Tag = 11; - } - - public double Float64 - { - get => IsFloat64 ? this.ReadDataDouble(64) : default; - set => this.WriteData(64, value); - } - - public bool IsText - { - get => Tag == 12; - set => Tag = 12; - } - - public string Text - { - get => IsText ? ReadText(0) : default; - set => WriteText(0, value); - } - - public bool IsData - { - get => Tag == 13; - set => Tag = 13; - } - - public SerializerState Data - { - get => IsData ? BuildPointer(0) : default; - set => Link(0, value); - } - - public bool IsList - { - get => Tag == 14; - set => Tag = 14; - } - - public SerializerState List - { - get => IsList ? BuildPointer(0) : default; - set => Link(0, value); - } - - public bool IsEnum - { - get => Tag == 15; - set => Tag = 15; - } - - public ushort Enum - { - get => IsEnum ? this.ReadDataUShort(16) : default; - set => this.WriteData(16, value); - } - - public bool IsStruct - { - get => Tag == 16; - set => Tag = 16; - } - - public SerializerState Struct - { - get => IsStruct ? BuildPointer(0) : default; - set => Link(0, value); - } - - public bool IsInterface - { - get => Tag == 17; - set => Tag = 17; - } - - public bool IsAnyPointer - { - get => Tag == 18; - set => Tag = 18; - } - - public SerializerState AnyPointer - { - get => IsAnyPointer ? BuildPointer(0) : default; - set => Link(0, value); - } - } - } - - namespace Annotation - { - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public ulong Id => State.ReadDataULong(0); - public Brand.Reader Brand => State.ReadStruct(1, Schema.Brand.Reader.Create); - public Value.Reader Value => State.ReadStruct(0, Schema.Value.Reader.Create); - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(1, 2); - } - - public ref ulong Id => ref this.RefData(0); - - public Brand.Writer Brand - { - get => BuildPointer(1); - set => Link(1, value); - } - - public Value.Writer Value - { - get => BuildPointer(0); - set => Link(0, value); - } - } - } - - public enum ElementSize: ushort - { - Empty = 0, - Bit = 1, - Byte = 2, - TwoBytes = 3, - FourBytes = 4, - EightBytes = 5, - Pointer = 6, - InlineComposite = 7 - } - - namespace Field - { - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public string Name => State.ReadText(0); - public ushort CodeOrder => State.ReadDataUShort(0); - public IReadOnlyList Annotations => State.ReadListOfStructs(1, Annotation.Reader.Create); - public ushort DiscriminantValue => State.ReadDataUShort(16, 65535); - public ushort Tag => State.ReadDataUShort(64); - public bool IsSlot => Tag == 0; - public uint Slot_Offset => IsSlot ? State.ReadDataUInt(32) : default; - public Type.Reader Slot_Type => IsSlot ? State.ReadStruct(2, Type.Reader.Create) : default; - public Value.Reader Slot_DefaultValue => IsSlot ? State.ReadStruct(3, Value.Reader.Create) : default; - public bool Slot_HadExplicitDefault => IsSlot ? State.ReadDataBool(128) : default; - public bool IsGroup => Tag == 1; - public ulong Group_TypeId => IsGroup ? State.ReadDataULong(128) : default; - public ushort Ordinal_Tag => State.ReadDataUShort(80); - public bool Ordinal_IsImplicit => Ordinal_Tag == 0; - public bool Ordinal_IsExplicit => Ordinal_Tag == 1; - public ushort Ordinal_Explicit => Ordinal_IsExplicit ? State.ReadDataUShort(96) : default; - - public const ushort NoDiscriminant = 0xffff; - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(3, 3); - } - - public string Name - { - get => ReadText(0); - set => WriteText(0, value); - } - - public ref ushort CodeOrder => ref this.RefData(0); - - public ListOfStructsSerializer Annotations - { - get => BuildPointer>(1); - set => Link(1, value); - } - - public ushort DiscriminantValue - { - get => this.ReadDataUShort(16, 65535); - set => this.WriteData(16, value, (ushort)65535); - } - - public ref ushort Tag => ref this.RefData(8); - - public bool IsSlot - { - get => Tag == 0; - set => Tag = 0; - } - - public uint Slot_Offset - { - get => IsSlot ? this.ReadDataUInt(32) : default; - set => this.WriteData(32, value); - } - - public Type.Writer Slot_Type - { - get => IsSlot ? BuildPointer(2) : default; - set => Link(2, value); - } - - public Value.Writer Slot_DefaultValue - { - get => IsSlot ? BuildPointer(3) : default; - set => Link(3, value); - } - - public bool Slot_HadExplicitDefault - { - get => IsSlot ? this.ReadDataBool(128) : default; - set => this.WriteData(128, value); - } - - public bool IsGroup - { - get => Tag == 1; - set => Tag = 1; - } - - public ref ulong Group_TypeId => ref this.RefData(2); - - public ref ushort Ordinal_Tag => ref this.RefData(5); - - public bool Ordinal_IsImplicit - { - get => Ordinal_Tag == 0; - set => Ordinal_Tag = 0; - } - - public bool Ordinal_IsExplicit - { - get => Ordinal_Tag == 1; - set => Ordinal_Tag = 1; - } - - public ref ushort Ordinal_Explicit => ref this.RefData(6); - } - } - - namespace Node - { - namespace Parameter - { - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public string Name => State.ReadText(0); - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(0, 1); - } - - public string Name - { - get => ReadText(0); - set => WriteText(0, value); - } - } - } - - namespace NestedNode - { - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public string Name => State.ReadText(0); - public ulong Id => State.ReadDataULong(0); - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(1, 1); - } - - public string Name - { - get => ReadText(0); - set => WriteText(0, value); - } - - public ref ulong Id => ref this.RefData(0); - } - } - - namespace SourceInfo - { - namespace Member - { - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public string DocComment => State.ReadText(0); - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(0, 1); - } - - public string DocComment - { - get => ReadText(0); - set => WriteText(0, value); - } - } - } - - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public ulong Id => State.ReadDataULong(0); - public string DocComment => State.ReadText(0); - public IReadOnlyList Members => State.ReadListOfStructs(1, Member.Reader.Create); - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(1, 2); - } - - public ref ulong Id => ref this.RefData(0); - - public string DocComment - { - get => ReadText(0); - set => WriteText(0, value); - } - - public ListOfStructsSerializer Members - { - get => BuildPointer>(1); - set => Link(1, value); - } - } - } - - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public ulong Id => State.ReadDataULong(0); - public string DisplayName => State.ReadText(0); - public uint DisplayNamePrefixLength => State.ReadDataUInt(64); - public ulong ScopeId => State.ReadDataULong(128); - public IReadOnlyList Parameters => State.ReadListOfStructs(5, Parameter.Reader.Create); - public bool IsGeneric => State.ReadDataBool(288); - public IReadOnlyList NestedNodes => State.ReadListOfStructs(1, NestedNode.Reader.Create); - public IReadOnlyList Annotations => State.ReadListOfStructs(2, Annotation.Reader.Create); - public ushort Tag => State.ReadDataUShort(96); - public bool IsFile => Tag == 0; - public bool IsStruct => Tag == 1; - public ushort Struct_DataWordCount => IsStruct ? State.ReadDataUShort(112) : default; - public ushort Struct_PointerCount => IsStruct ? State.ReadDataUShort(192) : default; - public ElementSize Struct_PreferredListEncoding => IsStruct ? (ElementSize)State.ReadDataUShort(208) : default; - public bool Struct_IsGroup => IsStruct ? State.ReadDataBool(224) : default; - public ushort Struct_DiscriminantCount => IsStruct ? State.ReadDataUShort(240) : default; - public uint Struct_DiscriminantOffset => IsStruct ? State.ReadDataUInt(256) : default; - public IReadOnlyList Fields => IsStruct ? State.ReadListOfStructs(3, Field.Reader.Create) : default; - public bool IsEnum => Tag == 2; - public IReadOnlyList Enumerants => IsEnum ? State.ReadListOfStructs(3, Field.Reader.Create) : default; - public bool IsInterface => Tag == 3; - public IReadOnlyList Interface_Methods => IsInterface ? State.ReadListOfStructs(3, Method.Reader.Create) : default; - public IReadOnlyList Interface_Superclasses => IsInterface ? State.ReadListOfStructs(4, Superclass.Reader.Create) : default; - public bool IsConst => Tag == 4; - public Type.Reader Const_Type => IsConst ? State.ReadStruct(3, Type.Reader.Create) : default; - public Value.Reader Const_Value => IsConst ? State.ReadStruct(4, Value.Reader.Create) : default; - public bool IsAnnotation => Tag == 5; - public Type.Reader Annotation_Type => IsAnnotation ? State.ReadStruct(3, Type.Reader.Create) : default; - public bool Annotation_TargetsFile => IsAnnotation ? State.ReadDataBool(112) : default; - public bool Annotation_TargetsConst => IsAnnotation ? State.ReadDataBool(113) : default; - public bool Annotation_TargetsEnum => IsAnnotation ? State.ReadDataBool(114) : default; - public bool Annotation_TargetsEnumerant => IsAnnotation ? State.ReadDataBool(115) : default; - public bool Annotation_TargetsStruct => IsAnnotation ? State.ReadDataBool(116) : default; - public bool Annotation_TargetsField => IsAnnotation ? State.ReadDataBool(117) : default; - public bool Annotation_TargetsUnion => IsAnnotation ? State.ReadDataBool(118) : default; - public bool Annotation_TargetsGroup => IsAnnotation ? State.ReadDataBool(119) : default; - public bool Annotation_TargetsInterface => IsAnnotation ? State.ReadDataBool(120) : default; - public bool Annotation_TargetsMethod => IsAnnotation ? State.ReadDataBool(121) : default; - public bool Annotation_TargetsParam => IsAnnotation ? State.ReadDataBool(122) : default; - public bool Annotation_TargetsAnnotation => IsAnnotation ? State.ReadDataBool(123) : default; - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(5, 6); - } - - public ulong Id - { - get => this.ReadDataULong(0); - set => this.WriteData(0, value); + get => this.ReadDataULong(0UL, 0UL); + set => this.WriteData(0UL, value, 0UL); } public string DisplayName { - get => ReadText(0); - set => WriteText(0, value); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); } - public ref uint DisplayNamePrefixLength => ref this.RefData(2); - - public ref ulong ScopeId => ref this.RefData(2); - - public ListOfStructsSerializer Parameters + public uint DisplayNamePrefixLength { - get => BuildPointer>(5); + get => this.ReadDataUInt(64UL, 0U); + set => this.WriteData(64UL, value, 0U); + } + + public ulong ScopeId + { + get => this.ReadDataULong(128UL, 0UL); + set => this.WriteData(128UL, value, 0UL); + } + + public ListOfStructsSerializer NestedNodes + { + get => BuildPointer>(1); + set => Link(1, value); + } + + public ListOfStructsSerializer Annotations + { + get => BuildPointer>(2); + set => Link(2, value); + } + + public @struct.WRITER Struct + { + get => which == WHICH.Struct ? Rewrap<@struct.WRITER>() : default; + } + + public @enum.WRITER Enum + { + get => which == WHICH.Enum ? Rewrap<@enum.WRITER>() : default; + } + + public @interface.WRITER Interface + { + get => which == WHICH.Interface ? Rewrap<@interface.WRITER>() : default; + } + + public @const.WRITER Const + { + get => which == WHICH.Const ? Rewrap<@const.WRITER>() : default; + } + + public annotation.WRITER Annotation + { + get => which == WHICH.Annotation ? Rewrap() : default; + } + + public ListOfStructsSerializer Parameters + { + get => BuildPointer>(5); set => Link(5, value); } public bool IsGeneric { - get => this.ReadDataBool(288); - set => this.WriteData(288, value); - } - - public ListOfStructsSerializer NestedNodes - { - get => BuildPointer>(1); - set => Link(1, value); - } - - public ListOfStructsSerializer Annotations - { - get => BuildPointer>(2); - set => Link(2, value); - } - - public ref ushort Tag => ref this.RefData(6); - - public bool IsFile - { - get => Tag == 0; - set => Tag = 0; - } - - public bool IsStruct - { - get => Tag == 1; - set => Tag = 1; - } - - public ref ushort Struct_DataWordCount => ref this.RefData(7); - - public ref ushort Struct_PointerCount => ref this.RefData(12); - - public ref ElementSize Struct_PreferredListEncoding => ref this.RefData(13); - - public bool Struct_IsGroup - { - get => IsStruct ? this.ReadDataBool(224) : default; - set => this.WriteData(224, value); - } - - public ref ushort Struct_DiscriminantCount => ref this.RefData(15); - - public ref uint Struct_DiscriminantOffset => ref this.RefData(8); - - public ListOfStructsSerializer Fields - { - get => BuildPointer>(3); - set => Link(3, value); - } - - public bool IsEnum - { - get => Tag == 2; - set => Tag = 2; - } - - public ListOfStructsSerializer Enumerants - { - get => BuildPointer>(3); - set => Link(3, value); - } - - public bool IsInterface - { - get => Tag == 3; - set => Tag = 3; - } - - public ListOfStructsSerializer Interface_Methods - { - get => BuildPointer>(3); - set => Link(3, value); - } - - public ListOfStructsSerializer Interface_Superclasses - { - get => IsInterface ? BuildPointer>(4) : default; - set => Link(4, value); - } - - public bool IsConst - { - get => Tag == 4; - set => Tag = 4; - } - - public Type.Writer Const_Type - { - get => IsConst ? BuildPointer(3) : default; - set => Link(3, value); - } - - public Value.Writer Const_Value - { - get => IsConst ? BuildPointer(4) : default; - set => Link(4, value); - } - - public bool IsAnnotation - { - get => Tag == 5; - set => Tag = 5; - } - - public Type.Writer Annotation_Type - { - get => IsAnnotation ? BuildPointer(3) : default; - set => Link(3, value); - } - - public bool Annotation_TargetsFile - { - get => IsAnnotation ? this.ReadDataBool(112) : default; - set => this.WriteData(112, value); - } - - public bool Annotation_TargetsConst - { - get => IsAnnotation ? this.ReadDataBool(113) : default; - set => this.WriteData(113, value); - } - - public bool Annotation_TargetsEnum - { - get => IsAnnotation ? this.ReadDataBool(114) : default; - set => this.WriteData(114, value); - } - - public bool Annotation_TargetsEnumerant - { - get => IsAnnotation ? this.ReadDataBool(115) : default; - set => this.WriteData(115, value); - } - - public bool Annotation_TargetsStruct - { - get => IsAnnotation ? this.ReadDataBool(116) : default; - set => this.WriteData(116, value); - } - - public bool Annotation_TargetsField - { - get => IsAnnotation ? this.ReadDataBool(117) : default; - set => this.WriteData(117, value); - } - - public bool Annotation_TargetsUnion - { - get => IsAnnotation ? this.ReadDataBool(118) : default; - set => this.WriteData(118, value); - } - - public bool Annotation_TargetsGroup - { - get => IsAnnotation ? this.ReadDataBool(119) : default; - set => this.WriteData(119, value); - } - - public bool Annotation_TargetsInterface - { - get => IsAnnotation ? this.ReadDataBool(120) : default; - set => this.WriteData(120, value); - } - - public bool Annotation_TargetsMethod - { - get => IsAnnotation ? this.ReadDataBool(121) : default; - set => this.WriteData(121, value); - } - - public bool Annotation_TargetsParam - { - get => IsAnnotation ? this.ReadDataBool(122) : default; - set => this.WriteData(122, value); - } - - public bool Annotation_TargetsAnnotation - { - get => IsAnnotation ? this.ReadDataBool(123) : default; - set => this.WriteData(123, value); + get => this.ReadDataBool(288UL, false); + set => this.WriteData(288UL, value, false); } } - } - namespace CapnpVersion - { - public struct Reader + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9ea0b19b37fb4435UL)] + public class @struct : ICapnpSerializable { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) + public const UInt64 typeId = 0x9ea0b19b37fb4435UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) { - State = ctx; + var reader = READER.create(arg_); + DataWordCount = reader.DataWordCount; + PointerCount = reader.PointerCount; + PreferredListEncoding = reader.PreferredListEncoding; + IsGroup = reader.IsGroup; + DiscriminantCount = reader.DiscriminantCount; + DiscriminantOffset = reader.DiscriminantOffset; + Fields = reader.Fields?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + applyDefaults(); } - public static Reader Create(DeserializerState ctx) => new Reader(ctx); + public void serialize(WRITER writer) + { + writer.DataWordCount = DataWordCount; + writer.PointerCount = PointerCount; + writer.PreferredListEncoding = PreferredListEncoding; + writer.IsGroup = IsGroup; + writer.DiscriminantCount = DiscriminantCount; + writer.DiscriminantOffset = DiscriminantOffset; + writer.Fields.Init(Fields, (_s1, _v1) => _v1?.serialize(_s1)); + } - public ushort Major => State.ReadDataUShort(0); - public byte Minor => State.ReadDataByte(16); - public byte Micro => State.ReadDataByte(24); + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ushort DataWordCount + { + get; + set; + } + + public ushort PointerCount + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.ElementSize PreferredListEncoding + { + get; + set; + } + + public bool IsGroup + { + get; + set; + } + + public ushort DiscriminantCount + { + get; + set; + } + + public uint DiscriminantOffset + { + get; + set; + } + + public IReadOnlyList Fields + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ushort DataWordCount => ctx.ReadDataUShort(112UL, (ushort)0); + public ushort PointerCount => ctx.ReadDataUShort(192UL, (ushort)0); + public CapnpC.CSharp.Generator.Schema.ElementSize PreferredListEncoding => (CapnpC.CSharp.Generator.Schema.ElementSize)ctx.ReadDataUShort(208UL, (ushort)0); + public bool IsGroup => ctx.ReadDataBool(224UL, false); + public ushort DiscriminantCount => ctx.ReadDataUShort(240UL, (ushort)0); + public uint DiscriminantOffset => ctx.ReadDataUInt(256UL, 0U); + public IReadOnlyList Fields => ctx.ReadList(3).Cast(CapnpC.CSharp.Generator.Schema.Field.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public ushort DataWordCount + { + get => this.ReadDataUShort(112UL, (ushort)0); + set => this.WriteData(112UL, value, (ushort)0); + } + + public ushort PointerCount + { + get => this.ReadDataUShort(192UL, (ushort)0); + set => this.WriteData(192UL, value, (ushort)0); + } + + public CapnpC.CSharp.Generator.Schema.ElementSize PreferredListEncoding + { + get => (CapnpC.CSharp.Generator.Schema.ElementSize)this.ReadDataUShort(208UL, (ushort)0); + set => this.WriteData(208UL, (ushort)value, (ushort)0); + } + + public bool IsGroup + { + get => this.ReadDataBool(224UL, false); + set => this.WriteData(224UL, value, false); + } + + public ushort DiscriminantCount + { + get => this.ReadDataUShort(240UL, (ushort)0); + set => this.WriteData(240UL, value, (ushort)0); + } + + public uint DiscriminantOffset + { + get => this.ReadDataUInt(256UL, 0U); + set => this.WriteData(256UL, value, 0U); + } + + public ListOfStructsSerializer Fields + { + get => BuildPointer>(3); + set => Link(3, value); + } + } } - public class Writer: SerializerState + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb54ab3364333f598UL)] + public class @enum : ICapnpSerializable { - public Writer() + public const UInt64 typeId = 0xb54ab3364333f598UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) { - SetStruct(1, 0); + var reader = READER.create(arg_); + Enumerants = reader.Enumerants?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + applyDefaults(); } - public ref ushort Major => ref this.RefData(0); - public ref byte Minor => ref this.RefData(2); - public ref byte Micro => ref this.RefData(3); + public void serialize(WRITER writer) + { + writer.Enumerants.Init(Enumerants, (_s1, _v1) => _v1?.serialize(_s1)); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public IReadOnlyList Enumerants + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public IReadOnlyList Enumerants => ctx.ReadList(3).Cast(CapnpC.CSharp.Generator.Schema.Enumerant.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public ListOfStructsSerializer Enumerants + { + get => BuildPointer>(3); + set => Link(3, value); + } + } } - } - namespace CodeGeneratorRequest - { - namespace RequestedFile + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xe82753cff0c2218fUL)] + public class @interface : ICapnpSerializable { - namespace Import + public const UInt64 typeId = 0xe82753cff0c2218fUL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) { - public struct Reader - { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public ulong Id => State.ReadDataULong(0); - public string Name => State.ReadText(0); - } - - public class Writer: SerializerState - { - public Writer() - { - SetStruct(1, 1); - } - - public ref ulong Id => ref this.RefData(0); - - public string Name - { - get => ReadText(0); - set => WriteText(0, value); - } - } + var reader = READER.create(arg_); + Methods = reader.Methods?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + Superclasses = reader.Superclasses?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + applyDefaults(); } - public struct Reader + public void serialize(WRITER writer) { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) - { - State = ctx; - } - - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public ulong Id => State.ReadDataULong(0); - public string Filename => State.ReadText(0); - public IReadOnlyList Imports => State.ReadListOfStructs(1, Import.Reader.Create); + writer.Methods.Init(Methods, (_s1, _v1) => _v1?.serialize(_s1)); + writer.Superclasses.Init(Superclasses, (_s1, _v1) => _v1?.serialize(_s1)); } - public class Writer: SerializerState + void ICapnpSerializable.Serialize(SerializerState arg_) { - public Writer() + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public IReadOnlyList Methods + { + get; + set; + } + + public IReadOnlyList Superclasses + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) { - SetStruct(1, 2); + this.ctx = ctx; } - public ref ulong Id => ref this.RefData(0); + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public IReadOnlyList Methods => ctx.ReadList(3).Cast(CapnpC.CSharp.Generator.Schema.Method.READER.create); + public IReadOnlyList Superclasses => ctx.ReadList(4).Cast(CapnpC.CSharp.Generator.Schema.Superclass.READER.create); + } - public string Filename + public class WRITER : SerializerState + { + public WRITER() { - get => ReadText(0); - set => WriteText(0, value); } - public ListOfStructsSerializer Imports + public ListOfStructsSerializer Methods { - get => BuildPointer>(1); + get => BuildPointer>(3); + set => Link(3, value); + } + + public ListOfStructsSerializer Superclasses + { + get => BuildPointer>(4); + set => Link(4, value); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb18aa5ac7a0d9420UL)] + public class @const : ICapnpSerializable + { + public const UInt64 typeId = 0xb18aa5ac7a0d9420UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Type = CapnpSerializable.Create(reader.Type); + Value = CapnpSerializable.Create(reader.Value); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + Type?.serialize(writer.Type); + Value?.serialize(writer.Value); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public CapnpC.CSharp.Generator.Schema.Type Type + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Value Value + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public CapnpC.CSharp.Generator.Schema.Type.READER Type => ctx.ReadStruct(3, CapnpC.CSharp.Generator.Schema.Type.READER.create); + public CapnpC.CSharp.Generator.Schema.Value.READER Value => ctx.ReadStruct(4, CapnpC.CSharp.Generator.Schema.Value.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public CapnpC.CSharp.Generator.Schema.Type.WRITER Type + { + get => BuildPointer(3); + set => Link(3, value); + } + + public CapnpC.CSharp.Generator.Schema.Value.WRITER Value + { + get => BuildPointer(4); + set => Link(4, value); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xec1619d4400a0290UL)] + public class annotation : ICapnpSerializable + { + public const UInt64 typeId = 0xec1619d4400a0290UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Type = CapnpSerializable.Create(reader.Type); + TargetsFile = reader.TargetsFile; + TargetsConst = reader.TargetsConst; + TargetsEnum = reader.TargetsEnum; + TargetsEnumerant = reader.TargetsEnumerant; + TargetsStruct = reader.TargetsStruct; + TargetsField = reader.TargetsField; + TargetsUnion = reader.TargetsUnion; + TargetsGroup = reader.TargetsGroup; + TargetsInterface = reader.TargetsInterface; + TargetsMethod = reader.TargetsMethod; + TargetsParam = reader.TargetsParam; + TargetsAnnotation = reader.TargetsAnnotation; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + Type?.serialize(writer.Type); + writer.TargetsFile = TargetsFile; + writer.TargetsConst = TargetsConst; + writer.TargetsEnum = TargetsEnum; + writer.TargetsEnumerant = TargetsEnumerant; + writer.TargetsStruct = TargetsStruct; + writer.TargetsField = TargetsField; + writer.TargetsUnion = TargetsUnion; + writer.TargetsGroup = TargetsGroup; + writer.TargetsInterface = TargetsInterface; + writer.TargetsMethod = TargetsMethod; + writer.TargetsParam = TargetsParam; + writer.TargetsAnnotation = TargetsAnnotation; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public CapnpC.CSharp.Generator.Schema.Type Type + { + get; + set; + } + + public bool TargetsFile + { + get; + set; + } + + public bool TargetsConst + { + get; + set; + } + + public bool TargetsEnum + { + get; + set; + } + + public bool TargetsEnumerant + { + get; + set; + } + + public bool TargetsStruct + { + get; + set; + } + + public bool TargetsField + { + get; + set; + } + + public bool TargetsUnion + { + get; + set; + } + + public bool TargetsGroup + { + get; + set; + } + + public bool TargetsInterface + { + get; + set; + } + + public bool TargetsMethod + { + get; + set; + } + + public bool TargetsParam + { + get; + set; + } + + public bool TargetsAnnotation + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public CapnpC.CSharp.Generator.Schema.Type.READER Type => ctx.ReadStruct(3, CapnpC.CSharp.Generator.Schema.Type.READER.create); + public bool TargetsFile => ctx.ReadDataBool(112UL, false); + public bool TargetsConst => ctx.ReadDataBool(113UL, false); + public bool TargetsEnum => ctx.ReadDataBool(114UL, false); + public bool TargetsEnumerant => ctx.ReadDataBool(115UL, false); + public bool TargetsStruct => ctx.ReadDataBool(116UL, false); + public bool TargetsField => ctx.ReadDataBool(117UL, false); + public bool TargetsUnion => ctx.ReadDataBool(118UL, false); + public bool TargetsGroup => ctx.ReadDataBool(119UL, false); + public bool TargetsInterface => ctx.ReadDataBool(120UL, false); + public bool TargetsMethod => ctx.ReadDataBool(121UL, false); + public bool TargetsParam => ctx.ReadDataBool(122UL, false); + public bool TargetsAnnotation => ctx.ReadDataBool(123UL, false); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public CapnpC.CSharp.Generator.Schema.Type.WRITER Type + { + get => BuildPointer(3); + set => Link(3, value); + } + + public bool TargetsFile + { + get => this.ReadDataBool(112UL, false); + set => this.WriteData(112UL, value, false); + } + + public bool TargetsConst + { + get => this.ReadDataBool(113UL, false); + set => this.WriteData(113UL, value, false); + } + + public bool TargetsEnum + { + get => this.ReadDataBool(114UL, false); + set => this.WriteData(114UL, value, false); + } + + public bool TargetsEnumerant + { + get => this.ReadDataBool(115UL, false); + set => this.WriteData(115UL, value, false); + } + + public bool TargetsStruct + { + get => this.ReadDataBool(116UL, false); + set => this.WriteData(116UL, value, false); + } + + public bool TargetsField + { + get => this.ReadDataBool(117UL, false); + set => this.WriteData(117UL, value, false); + } + + public bool TargetsUnion + { + get => this.ReadDataBool(118UL, false); + set => this.WriteData(118UL, value, false); + } + + public bool TargetsGroup + { + get => this.ReadDataBool(119UL, false); + set => this.WriteData(119UL, value, false); + } + + public bool TargetsInterface + { + get => this.ReadDataBool(120UL, false); + set => this.WriteData(120UL, value, false); + } + + public bool TargetsMethod + { + get => this.ReadDataBool(121UL, false); + set => this.WriteData(121UL, value, false); + } + + public bool TargetsParam + { + get => this.ReadDataBool(122UL, false); + set => this.WriteData(122UL, value, false); + } + + public bool TargetsAnnotation + { + get => this.ReadDataBool(123UL, false); + set => this.WriteData(123UL, value, false); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xb9521bccf10fa3b1UL)] + public class Parameter : ICapnpSerializable + { + public const UInt64 typeId = 0xb9521bccf10fa3b1UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Name = reader.Name; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Name = Name; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public string Name + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public string Name => ctx.ReadText(0, null); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(0, 1); + } + + public string Name + { + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xdebf55bbfa0fc242UL)] + public class NestedNode : ICapnpSerializable + { + public const UInt64 typeId = 0xdebf55bbfa0fc242UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Name = reader.Name; + Id = reader.Id; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Name = Name; + writer.Id = Id; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public string Name + { + get; + set; + } + + public ulong Id + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public string Name => ctx.ReadText(0, null); + public ulong Id => ctx.ReadDataULong(0UL, 0UL); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(1, 1); + } + + public string Name + { + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); + } + + public ulong Id + { + get => this.ReadDataULong(0UL, 0UL); + set => this.WriteData(0UL, value, 0UL); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf38e1de3041357aeUL)] + public class SourceInfo : ICapnpSerializable + { + public const UInt64 typeId = 0xf38e1de3041357aeUL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Id = reader.Id; + DocComment = reader.DocComment; + Members = reader.Members?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Id = Id; + writer.DocComment = DocComment; + writer.Members.Init(Members, (_s1, _v1) => _v1?.serialize(_s1)); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong Id + { + get; + set; + } + + public string DocComment + { + get; + set; + } + + public IReadOnlyList Members + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ulong Id => ctx.ReadDataULong(0UL, 0UL); + public string DocComment => ctx.ReadText(0, null); + public IReadOnlyList Members => ctx.ReadList(1).Cast(CapnpC.CSharp.Generator.Schema.Node.SourceInfo.Member.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(1, 2); + } + + public ulong Id + { + get => this.ReadDataULong(0UL, 0UL); + set => this.WriteData(0UL, value, 0UL); + } + + public string DocComment + { + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); + } + + public ListOfStructsSerializer Members + { + get => BuildPointer>(1); set => Link(1, value); } } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc2ba9038898e1fa2UL)] + public class Member : ICapnpSerializable + { + public const UInt64 typeId = 0xc2ba9038898e1fa2UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + DocComment = reader.DocComment; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.DocComment = DocComment; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public string DocComment + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public string DocComment => ctx.ReadText(0, null); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(0, 1); + } + + public string DocComment + { + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); + } + } + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9aad50a41f4af45fUL)] + public class Field : ICapnpSerializable + { + public const UInt64 typeId = 0x9aad50a41f4af45fUL; + public enum WHICH : ushort + { + Slot = 0, + Group = 1, + undefined = 65535 } - public struct Reader + void ICapnpSerializable.Deserialize(DeserializerState arg_) { - public DeserializerState State { get; } - - public Reader(DeserializerState ctx) + var reader = READER.create(arg_); + switch (reader.which) { - State = ctx; + case WHICH.Slot: + Slot = CapnpSerializable.Create(reader.Slot); + break; + case WHICH.Group: + Group = CapnpSerializable.Create(reader.Group); + break; } - public static Reader Create(DeserializerState ctx) => new Reader(ctx); - - public CapnpVersion.Reader CapnpVersion => State.ReadStruct(2, Schema.CapnpVersion.Reader.Create); - public IReadOnlyList Nodes => State.ReadListOfStructs(0, Node.Reader.Create); - public IReadOnlyList SourceInfo => State.ReadListOfStructs(3, Node.SourceInfo.Reader.Create); - public IReadOnlyList RequestedFiles => State.ReadListOfStructs(1, RequestedFile.Reader.Create); + Name = reader.Name; + CodeOrder = reader.CodeOrder; + Annotations = reader.Annotations?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + DiscriminantValue = reader.DiscriminantValue; + Ordinal = CapnpSerializable.Create(reader.Ordinal); + applyDefaults(); } - public class Writer: SerializerState + private WHICH _which = WHICH.undefined; + private object _content; + public WHICH which { - public Writer() + get => _which; + set { - SetStruct(0, 3); + if (value == _which) + return; + _which = value; + switch (value) + { + case WHICH.Slot: + _content = null; + break; + case WHICH.Group: + _content = null; + break; + } + } + } + + public void serialize(WRITER writer) + { + writer.which = which; + switch (which) + { + case WHICH.Slot: + Slot?.serialize(writer.Slot); + break; + case WHICH.Group: + Group?.serialize(writer.Group); + break; } - public CapnpVersion.Writer CapnpVersion + writer.Name = Name; + writer.CodeOrder = CodeOrder; + writer.Annotations.Init(Annotations, (_s1, _v1) => _v1?.serialize(_s1)); + writer.DiscriminantValue = DiscriminantValue; + Ordinal?.serialize(writer.Ordinal); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public string Name + { + get; + set; + } + + public ushort CodeOrder + { + get; + set; + } + + public IReadOnlyList Annotations + { + get; + set; + } + + public ushort DiscriminantValue + { + get; + set; + } + + = 65535; + public CapnpC.CSharp.Generator.Schema.Field.slot Slot + { + get => _which == WHICH.Slot ? (CapnpC.CSharp.Generator.Schema.Field.slot)_content : null; + set { - get => BuildPointer(2); - set => Link(2, value); + _which = WHICH.Slot; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Field.@group Group + { + get => _which == WHICH.Group ? (CapnpC.CSharp.Generator.Schema.Field.@group)_content : null; + set + { + _which = WHICH.Group; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Field.ordinal Ordinal + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; } - public ListOfStructsSerializer Nodes + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public WHICH which => (WHICH)ctx.ReadDataUShort(64U, (ushort)0); + public string Name => ctx.ReadText(0, null); + public ushort CodeOrder => ctx.ReadDataUShort(0UL, (ushort)0); + public IReadOnlyList Annotations => ctx.ReadList(1).Cast(CapnpC.CSharp.Generator.Schema.Annotation.READER.create); + public ushort DiscriminantValue => ctx.ReadDataUShort(16UL, (ushort)65535); + public slot.READER Slot => which == WHICH.Slot ? new slot.READER(ctx) : default; + public @group.READER Group => which == WHICH.Group ? new @group.READER(ctx) : default; + public ordinal.READER Ordinal => new ordinal.READER(ctx); + } + + public class WRITER : SerializerState + { + public WRITER() { - get => BuildPointer>(0); - set => Link(0, value); + this.SetStruct(3, 4); } - public ListOfStructsSerializer SourceInfo + public WHICH which { - get => BuildPointer>(3); - set => Link(3, value); + get => (WHICH)this.ReadDataUShort(64U, (ushort)0); + set => this.WriteData(64U, (ushort)value, (ushort)0); } - public ListOfStructsSerializer RequestedFiles + public string Name { - get => BuildPointer>(1); + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); + } + + public ushort CodeOrder + { + get => this.ReadDataUShort(0UL, (ushort)0); + set => this.WriteData(0UL, value, (ushort)0); + } + + public ListOfStructsSerializer Annotations + { + get => BuildPointer>(1); + set => Link(1, value); + } + + public ushort DiscriminantValue + { + get => this.ReadDataUShort(16UL, (ushort)65535); + set => this.WriteData(16UL, value, (ushort)65535); + } + + public slot.WRITER Slot + { + get => which == WHICH.Slot ? Rewrap() : default; + } + + public @group.WRITER Group + { + get => which == WHICH.Group ? Rewrap<@group.WRITER>() : default; + } + + public ordinal.WRITER Ordinal + { + get => Rewrap(); + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc42305476bb4746fUL)] + public class slot : ICapnpSerializable + { + public const UInt64 typeId = 0xc42305476bb4746fUL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Offset = reader.Offset; + Type = CapnpSerializable.Create(reader.Type); + DefaultValue = CapnpSerializable.Create(reader.DefaultValue); + HadExplicitDefault = reader.HadExplicitDefault; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Offset = Offset; + Type?.serialize(writer.Type); + DefaultValue?.serialize(writer.DefaultValue); + writer.HadExplicitDefault = HadExplicitDefault; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public uint Offset + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Type Type + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Value DefaultValue + { + get; + set; + } + + public bool HadExplicitDefault + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public uint Offset => ctx.ReadDataUInt(32UL, 0U); + public CapnpC.CSharp.Generator.Schema.Type.READER Type => ctx.ReadStruct(2, CapnpC.CSharp.Generator.Schema.Type.READER.create); + public CapnpC.CSharp.Generator.Schema.Value.READER DefaultValue => ctx.ReadStruct(3, CapnpC.CSharp.Generator.Schema.Value.READER.create); + public bool HadExplicitDefault => ctx.ReadDataBool(128UL, false); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public uint Offset + { + get => this.ReadDataUInt(32UL, 0U); + set => this.WriteData(32UL, value, 0U); + } + + public CapnpC.CSharp.Generator.Schema.Type.WRITER Type + { + get => BuildPointer(2); + set => Link(2, value); + } + + public CapnpC.CSharp.Generator.Schema.Value.WRITER DefaultValue + { + get => BuildPointer(3); + set => Link(3, value); + } + + public bool HadExplicitDefault + { + get => this.ReadDataBool(128UL, false); + set => this.WriteData(128UL, value, false); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xcafccddb68db1d11UL)] + public class @group : ICapnpSerializable + { + public const UInt64 typeId = 0xcafccddb68db1d11UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + TypeId = reader.TypeId; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.TypeId = TypeId; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong TypeId + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ulong TypeId => ctx.ReadDataULong(128UL, 0UL); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public ulong TypeId + { + get => this.ReadDataULong(128UL, 0UL); + set => this.WriteData(128UL, value, 0UL); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbb90d5c287870be6UL)] + public class ordinal : ICapnpSerializable + { + public const UInt64 typeId = 0xbb90d5c287870be6UL; + public enum WHICH : ushort + { + Implicit = 0, + Explicit = 1, + undefined = 65535 + } + + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + switch (reader.which) + { + case WHICH.Implicit: + which = reader.which; + break; + case WHICH.Explicit: + Explicit = reader.Explicit; + break; + } + + applyDefaults(); + } + + private WHICH _which = WHICH.undefined; + private object _content; + public WHICH which + { + get => _which; + set + { + if (value == _which) + return; + _which = value; + switch (value) + { + case WHICH.Implicit: + break; + case WHICH.Explicit: + _content = 0; + break; + } + } + } + + public void serialize(WRITER writer) + { + writer.which = which; + switch (which) + { + case WHICH.Implicit: + break; + case WHICH.Explicit: + writer.Explicit = Explicit.Value; + break; + } + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ushort? Explicit + { + get => _which == WHICH.Explicit ? (ushort?)_content : null; + set + { + _which = WHICH.Explicit; + _content = value; + } + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public WHICH which => (WHICH)ctx.ReadDataUShort(80U, (ushort)0); + public ushort Explicit => which == WHICH.Explicit ? ctx.ReadDataUShort(96UL, (ushort)0) : default; + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public WHICH which + { + get => (WHICH)this.ReadDataUShort(80U, (ushort)0); + set => this.WriteData(80U, (ushort)value, (ushort)0); + } + + public ushort Explicit + { + get => which == WHICH.Explicit ? this.ReadDataUShort(96UL, (ushort)0) : default; + set => this.WriteData(96UL, value, (ushort)0); + } + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x978a7cebdc549a4dUL)] + public class Enumerant : ICapnpSerializable + { + public const UInt64 typeId = 0x978a7cebdc549a4dUL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Name = reader.Name; + CodeOrder = reader.CodeOrder; + Annotations = reader.Annotations?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Name = Name; + writer.CodeOrder = CodeOrder; + writer.Annotations.Init(Annotations, (_s1, _v1) => _v1?.serialize(_s1)); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public string Name + { + get; + set; + } + + public ushort CodeOrder + { + get; + set; + } + + public IReadOnlyList Annotations + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public string Name => ctx.ReadText(0, null); + public ushort CodeOrder => ctx.ReadDataUShort(0UL, (ushort)0); + public IReadOnlyList Annotations => ctx.ReadList(1).Cast(CapnpC.CSharp.Generator.Schema.Annotation.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(1, 2); + } + + public string Name + { + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); + } + + public ushort CodeOrder + { + get => this.ReadDataUShort(0UL, (ushort)0); + set => this.WriteData(0UL, value, (ushort)0); + } + + public ListOfStructsSerializer Annotations + { + get => BuildPointer>(1); set => Link(1, value); } } } -} + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xa9962a9ed0a4d7f8UL)] + public class Superclass : ICapnpSerializable + { + public const UInt64 typeId = 0xa9962a9ed0a4d7f8UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Id = reader.Id; + Brand = CapnpSerializable.Create(reader.Brand); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Id = Id; + Brand?.serialize(writer.Brand); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong Id + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Brand Brand + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ulong Id => ctx.ReadDataULong(0UL, 0UL); + public CapnpC.CSharp.Generator.Schema.Brand.READER Brand => ctx.ReadStruct(0, CapnpC.CSharp.Generator.Schema.Brand.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(1, 1); + } + + public ulong Id + { + get => this.ReadDataULong(0UL, 0UL); + set => this.WriteData(0UL, value, 0UL); + } + + public CapnpC.CSharp.Generator.Schema.Brand.WRITER Brand + { + get => BuildPointer(0); + set => Link(0, value); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9500cce23b334d80UL)] + public class Method : ICapnpSerializable + { + public const UInt64 typeId = 0x9500cce23b334d80UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Name = reader.Name; + CodeOrder = reader.CodeOrder; + ParamStructType = reader.ParamStructType; + ResultStructType = reader.ResultStructType; + Annotations = reader.Annotations?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + ParamBrand = CapnpSerializable.Create(reader.ParamBrand); + ResultBrand = CapnpSerializable.Create(reader.ResultBrand); + ImplicitParameters = reader.ImplicitParameters?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Name = Name; + writer.CodeOrder = CodeOrder; + writer.ParamStructType = ParamStructType; + writer.ResultStructType = ResultStructType; + writer.Annotations.Init(Annotations, (_s1, _v1) => _v1?.serialize(_s1)); + ParamBrand?.serialize(writer.ParamBrand); + ResultBrand?.serialize(writer.ResultBrand); + writer.ImplicitParameters.Init(ImplicitParameters, (_s1, _v1) => _v1?.serialize(_s1)); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public string Name + { + get; + set; + } + + public ushort CodeOrder + { + get; + set; + } + + public ulong ParamStructType + { + get; + set; + } + + public ulong ResultStructType + { + get; + set; + } + + public IReadOnlyList Annotations + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Brand ParamBrand + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Brand ResultBrand + { + get; + set; + } + + public IReadOnlyList ImplicitParameters + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public string Name => ctx.ReadText(0, null); + public ushort CodeOrder => ctx.ReadDataUShort(0UL, (ushort)0); + public ulong ParamStructType => ctx.ReadDataULong(64UL, 0UL); + public ulong ResultStructType => ctx.ReadDataULong(128UL, 0UL); + public IReadOnlyList Annotations => ctx.ReadList(1).Cast(CapnpC.CSharp.Generator.Schema.Annotation.READER.create); + public CapnpC.CSharp.Generator.Schema.Brand.READER ParamBrand => ctx.ReadStruct(2, CapnpC.CSharp.Generator.Schema.Brand.READER.create); + public CapnpC.CSharp.Generator.Schema.Brand.READER ResultBrand => ctx.ReadStruct(3, CapnpC.CSharp.Generator.Schema.Brand.READER.create); + public IReadOnlyList ImplicitParameters => ctx.ReadList(4).Cast(CapnpC.CSharp.Generator.Schema.Node.Parameter.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(3, 5); + } + + public string Name + { + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); + } + + public ushort CodeOrder + { + get => this.ReadDataUShort(0UL, (ushort)0); + set => this.WriteData(0UL, value, (ushort)0); + } + + public ulong ParamStructType + { + get => this.ReadDataULong(64UL, 0UL); + set => this.WriteData(64UL, value, 0UL); + } + + public ulong ResultStructType + { + get => this.ReadDataULong(128UL, 0UL); + set => this.WriteData(128UL, value, 0UL); + } + + public ListOfStructsSerializer Annotations + { + get => BuildPointer>(1); + set => Link(1, value); + } + + public CapnpC.CSharp.Generator.Schema.Brand.WRITER ParamBrand + { + get => BuildPointer(2); + set => Link(2, value); + } + + public CapnpC.CSharp.Generator.Schema.Brand.WRITER ResultBrand + { + get => BuildPointer(3); + set => Link(3, value); + } + + public ListOfStructsSerializer ImplicitParameters + { + get => BuildPointer>(4); + set => Link(4, value); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd07378ede1f9cc60UL)] + public class Type : ICapnpSerializable + { + public const UInt64 typeId = 0xd07378ede1f9cc60UL; + public enum WHICH : ushort + { + Void = 0, + Bool = 1, + Int8 = 2, + Int16 = 3, + Int32 = 4, + Int64 = 5, + Uint8 = 6, + Uint16 = 7, + Uint32 = 8, + Uint64 = 9, + Float32 = 10, + Float64 = 11, + Text = 12, + Data = 13, + List = 14, + Enum = 15, + Struct = 16, + Interface = 17, + AnyPointer = 18, + undefined = 65535 + } + + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + switch (reader.which) + { + case WHICH.Void: + which = reader.which; + break; + case WHICH.Bool: + which = reader.which; + break; + case WHICH.Int8: + which = reader.which; + break; + case WHICH.Int16: + which = reader.which; + break; + case WHICH.Int32: + which = reader.which; + break; + case WHICH.Int64: + which = reader.which; + break; + case WHICH.Uint8: + which = reader.which; + break; + case WHICH.Uint16: + which = reader.which; + break; + case WHICH.Uint32: + which = reader.which; + break; + case WHICH.Uint64: + which = reader.which; + break; + case WHICH.Float32: + which = reader.which; + break; + case WHICH.Float64: + which = reader.which; + break; + case WHICH.Text: + which = reader.which; + break; + case WHICH.Data: + which = reader.which; + break; + case WHICH.List: + List = CapnpSerializable.Create(reader.List); + break; + case WHICH.Enum: + Enum = CapnpSerializable.Create(reader.Enum); + break; + case WHICH.Struct: + Struct = CapnpSerializable.Create(reader.Struct); + break; + case WHICH.Interface: + Interface = CapnpSerializable.Create(reader.Interface); + break; + case WHICH.AnyPointer: + AnyPointer = CapnpSerializable.Create(reader.AnyPointer); + break; + } + + applyDefaults(); + } + + private WHICH _which = WHICH.undefined; + private object _content; + public WHICH which + { + get => _which; + set + { + if (value == _which) + return; + _which = value; + switch (value) + { + case WHICH.Void: + break; + case WHICH.Bool: + break; + case WHICH.Int8: + break; + case WHICH.Int16: + break; + case WHICH.Int32: + break; + case WHICH.Int64: + break; + case WHICH.Uint8: + break; + case WHICH.Uint16: + break; + case WHICH.Uint32: + break; + case WHICH.Uint64: + break; + case WHICH.Float32: + break; + case WHICH.Float64: + break; + case WHICH.Text: + break; + case WHICH.Data: + break; + case WHICH.List: + _content = null; + break; + case WHICH.Enum: + _content = null; + break; + case WHICH.Struct: + _content = null; + break; + case WHICH.Interface: + _content = null; + break; + case WHICH.AnyPointer: + _content = null; + break; + } + } + } + + public void serialize(WRITER writer) + { + writer.which = which; + switch (which) + { + case WHICH.Void: + break; + case WHICH.Bool: + break; + case WHICH.Int8: + break; + case WHICH.Int16: + break; + case WHICH.Int32: + break; + case WHICH.Int64: + break; + case WHICH.Uint8: + break; + case WHICH.Uint16: + break; + case WHICH.Uint32: + break; + case WHICH.Uint64: + break; + case WHICH.Float32: + break; + case WHICH.Float64: + break; + case WHICH.Text: + break; + case WHICH.Data: + break; + case WHICH.List: + List?.serialize(writer.List); + break; + case WHICH.Enum: + Enum?.serialize(writer.Enum); + break; + case WHICH.Struct: + Struct?.serialize(writer.Struct); + break; + case WHICH.Interface: + Interface?.serialize(writer.Interface); + break; + case WHICH.AnyPointer: + AnyPointer?.serialize(writer.AnyPointer); + break; + } + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public CapnpC.CSharp.Generator.Schema.Type.list List + { + get => _which == WHICH.List ? (CapnpC.CSharp.Generator.Schema.Type.list)_content : null; + set + { + _which = WHICH.List; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Type.@enum Enum + { + get => _which == WHICH.Enum ? (CapnpC.CSharp.Generator.Schema.Type.@enum)_content : null; + set + { + _which = WHICH.Enum; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Type.@struct Struct + { + get => _which == WHICH.Struct ? (CapnpC.CSharp.Generator.Schema.Type.@struct)_content : null; + set + { + _which = WHICH.Struct; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Type.@interface Interface + { + get => _which == WHICH.Interface ? (CapnpC.CSharp.Generator.Schema.Type.@interface)_content : null; + set + { + _which = WHICH.Interface; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Type.anyPointer AnyPointer + { + get => _which == WHICH.AnyPointer ? (CapnpC.CSharp.Generator.Schema.Type.anyPointer)_content : null; + set + { + _which = WHICH.AnyPointer; + _content = value; + } + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public WHICH which => (WHICH)ctx.ReadDataUShort(0U, (ushort)0); + public list.READER List => which == WHICH.List ? new list.READER(ctx) : default; + public @enum.READER Enum => which == WHICH.Enum ? new @enum.READER(ctx) : default; + public @struct.READER Struct => which == WHICH.Struct ? new @struct.READER(ctx) : default; + public @interface.READER Interface => which == WHICH.Interface ? new @interface.READER(ctx) : default; + public anyPointer.READER AnyPointer => which == WHICH.AnyPointer ? new anyPointer.READER(ctx) : default; + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(3, 1); + } + + public WHICH which + { + get => (WHICH)this.ReadDataUShort(0U, (ushort)0); + set => this.WriteData(0U, (ushort)value, (ushort)0); + } + + public list.WRITER List + { + get => which == WHICH.List ? Rewrap() : default; + } + + public @enum.WRITER Enum + { + get => which == WHICH.Enum ? Rewrap<@enum.WRITER>() : default; + } + + public @struct.WRITER Struct + { + get => which == WHICH.Struct ? Rewrap<@struct.WRITER>() : default; + } + + public @interface.WRITER Interface + { + get => which == WHICH.Interface ? Rewrap<@interface.WRITER>() : default; + } + + public anyPointer.WRITER AnyPointer + { + get => which == WHICH.AnyPointer ? Rewrap() : default; + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x87e739250a60ea97UL)] + public class list : ICapnpSerializable + { + public const UInt64 typeId = 0x87e739250a60ea97UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + ElementType = CapnpSerializable.Create(reader.ElementType); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + ElementType?.serialize(writer.ElementType); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public CapnpC.CSharp.Generator.Schema.Type ElementType + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public CapnpC.CSharp.Generator.Schema.Type.READER ElementType => ctx.ReadStruct(0, CapnpC.CSharp.Generator.Schema.Type.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public CapnpC.CSharp.Generator.Schema.Type.WRITER ElementType + { + get => BuildPointer(0); + set => Link(0, value); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9e0e78711a7f87a9UL)] + public class @enum : ICapnpSerializable + { + public const UInt64 typeId = 0x9e0e78711a7f87a9UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + TypeId = reader.TypeId; + Brand = CapnpSerializable.Create(reader.Brand); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.TypeId = TypeId; + Brand?.serialize(writer.Brand); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong TypeId + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Brand Brand + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ulong TypeId => ctx.ReadDataULong(64UL, 0UL); + public CapnpC.CSharp.Generator.Schema.Brand.READER Brand => ctx.ReadStruct(0, CapnpC.CSharp.Generator.Schema.Brand.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public ulong TypeId + { + get => this.ReadDataULong(64UL, 0UL); + set => this.WriteData(64UL, value, 0UL); + } + + public CapnpC.CSharp.Generator.Schema.Brand.WRITER Brand + { + get => BuildPointer(0); + set => Link(0, value); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xac3a6f60ef4cc6d3UL)] + public class @struct : ICapnpSerializable + { + public const UInt64 typeId = 0xac3a6f60ef4cc6d3UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + TypeId = reader.TypeId; + Brand = CapnpSerializable.Create(reader.Brand); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.TypeId = TypeId; + Brand?.serialize(writer.Brand); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong TypeId + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Brand Brand + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ulong TypeId => ctx.ReadDataULong(64UL, 0UL); + public CapnpC.CSharp.Generator.Schema.Brand.READER Brand => ctx.ReadStruct(0, CapnpC.CSharp.Generator.Schema.Brand.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public ulong TypeId + { + get => this.ReadDataULong(64UL, 0UL); + set => this.WriteData(64UL, value, 0UL); + } + + public CapnpC.CSharp.Generator.Schema.Brand.WRITER Brand + { + get => BuildPointer(0); + set => Link(0, value); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xed8bca69f7fb0cbfUL)] + public class @interface : ICapnpSerializable + { + public const UInt64 typeId = 0xed8bca69f7fb0cbfUL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + TypeId = reader.TypeId; + Brand = CapnpSerializable.Create(reader.Brand); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.TypeId = TypeId; + Brand?.serialize(writer.Brand); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong TypeId + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Brand Brand + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ulong TypeId => ctx.ReadDataULong(64UL, 0UL); + public CapnpC.CSharp.Generator.Schema.Brand.READER Brand => ctx.ReadStruct(0, CapnpC.CSharp.Generator.Schema.Brand.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public ulong TypeId + { + get => this.ReadDataULong(64UL, 0UL); + set => this.WriteData(64UL, value, 0UL); + } + + public CapnpC.CSharp.Generator.Schema.Brand.WRITER Brand + { + get => BuildPointer(0); + set => Link(0, value); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc2573fe8a23e49f1UL)] + public class anyPointer : ICapnpSerializable + { + public const UInt64 typeId = 0xc2573fe8a23e49f1UL; + public enum WHICH : ushort + { + Unconstrained = 0, + Parameter = 1, + ImplicitMethodParameter = 2, + undefined = 65535 + } + + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + switch (reader.which) + { + case WHICH.Unconstrained: + Unconstrained = CapnpSerializable.Create(reader.Unconstrained); + break; + case WHICH.Parameter: + Parameter = CapnpSerializable.Create(reader.Parameter); + break; + case WHICH.ImplicitMethodParameter: + ImplicitMethodParameter = CapnpSerializable.Create(reader.ImplicitMethodParameter); + break; + } + + applyDefaults(); + } + + private WHICH _which = WHICH.undefined; + private object _content; + public WHICH which + { + get => _which; + set + { + if (value == _which) + return; + _which = value; + switch (value) + { + case WHICH.Unconstrained: + _content = null; + break; + case WHICH.Parameter: + _content = null; + break; + case WHICH.ImplicitMethodParameter: + _content = null; + break; + } + } + } + + public void serialize(WRITER writer) + { + writer.which = which; + switch (which) + { + case WHICH.Unconstrained: + Unconstrained?.serialize(writer.Unconstrained); + break; + case WHICH.Parameter: + Parameter?.serialize(writer.Parameter); + break; + case WHICH.ImplicitMethodParameter: + ImplicitMethodParameter?.serialize(writer.ImplicitMethodParameter); + break; + } + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public CapnpC.CSharp.Generator.Schema.Type.anyPointer.unconstrained Unconstrained + { + get => _which == WHICH.Unconstrained ? (CapnpC.CSharp.Generator.Schema.Type.anyPointer.unconstrained)_content : null; + set + { + _which = WHICH.Unconstrained; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Type.anyPointer.parameter Parameter + { + get => _which == WHICH.Parameter ? (CapnpC.CSharp.Generator.Schema.Type.anyPointer.parameter)_content : null; + set + { + _which = WHICH.Parameter; + _content = value; + } + } + + public CapnpC.CSharp.Generator.Schema.Type.anyPointer.implicitMethodParameter ImplicitMethodParameter + { + get => _which == WHICH.ImplicitMethodParameter ? (CapnpC.CSharp.Generator.Schema.Type.anyPointer.implicitMethodParameter)_content : null; + set + { + _which = WHICH.ImplicitMethodParameter; + _content = value; + } + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public WHICH which => (WHICH)ctx.ReadDataUShort(64U, (ushort)0); + public unconstrained.READER Unconstrained => which == WHICH.Unconstrained ? new unconstrained.READER(ctx) : default; + public parameter.READER Parameter => which == WHICH.Parameter ? new parameter.READER(ctx) : default; + public implicitMethodParameter.READER ImplicitMethodParameter => which == WHICH.ImplicitMethodParameter ? new implicitMethodParameter.READER(ctx) : default; + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public WHICH which + { + get => (WHICH)this.ReadDataUShort(64U, (ushort)0); + set => this.WriteData(64U, (ushort)value, (ushort)0); + } + + public unconstrained.WRITER Unconstrained + { + get => which == WHICH.Unconstrained ? Rewrap() : default; + } + + public parameter.WRITER Parameter + { + get => which == WHICH.Parameter ? Rewrap() : default; + } + + public implicitMethodParameter.WRITER ImplicitMethodParameter + { + get => which == WHICH.ImplicitMethodParameter ? Rewrap() : default; + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x8e3b5f79fe593656UL)] + public class unconstrained : ICapnpSerializable + { + public const UInt64 typeId = 0x8e3b5f79fe593656UL; + public enum WHICH : ushort + { + AnyKind = 0, + Struct = 1, + List = 2, + Capability = 3, + undefined = 65535 + } + + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + switch (reader.which) + { + case WHICH.AnyKind: + which = reader.which; + break; + case WHICH.Struct: + which = reader.which; + break; + case WHICH.List: + which = reader.which; + break; + case WHICH.Capability: + which = reader.which; + break; + } + + applyDefaults(); + } + + private WHICH _which = WHICH.undefined; + public WHICH which + { + get => _which; + set + { + if (value == _which) + return; + _which = value; + switch (value) + { + case WHICH.AnyKind: + break; + case WHICH.Struct: + break; + case WHICH.List: + break; + case WHICH.Capability: + break; + } + } + } + + public void serialize(WRITER writer) + { + writer.which = which; + switch (which) + { + case WHICH.AnyKind: + break; + case WHICH.Struct: + break; + case WHICH.List: + break; + case WHICH.Capability: + break; + } + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public WHICH which => (WHICH)ctx.ReadDataUShort(80U, (ushort)0); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public WHICH which + { + get => (WHICH)this.ReadDataUShort(80U, (ushort)0); + set => this.WriteData(80U, (ushort)value, (ushort)0); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x9dd1f724f4614a85UL)] + public class parameter : ICapnpSerializable + { + public const UInt64 typeId = 0x9dd1f724f4614a85UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + ScopeId = reader.ScopeId; + ParameterIndex = reader.ParameterIndex; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.ScopeId = ScopeId; + writer.ParameterIndex = ParameterIndex; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong ScopeId + { + get; + set; + } + + public ushort ParameterIndex + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ulong ScopeId => ctx.ReadDataULong(128UL, 0UL); + public ushort ParameterIndex => ctx.ReadDataUShort(80UL, (ushort)0); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public ulong ScopeId + { + get => this.ReadDataULong(128UL, 0UL); + set => this.WriteData(128UL, value, 0UL); + } + + public ushort ParameterIndex + { + get => this.ReadDataUShort(80UL, (ushort)0); + set => this.WriteData(80UL, value, (ushort)0); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbaefc9120c56e274UL)] + public class implicitMethodParameter : ICapnpSerializable + { + public const UInt64 typeId = 0xbaefc9120c56e274UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + ParameterIndex = reader.ParameterIndex; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.ParameterIndex = ParameterIndex; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ushort ParameterIndex + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ushort ParameterIndex => ctx.ReadDataUShort(80UL, (ushort)0); + } + + public class WRITER : SerializerState + { + public WRITER() + { + } + + public ushort ParameterIndex + { + get => this.ReadDataUShort(80UL, (ushort)0); + set => this.WriteData(80UL, value, (ushort)0); + } + } + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0x903455f06065422bUL)] + public class Brand : ICapnpSerializable + { + public const UInt64 typeId = 0x903455f06065422bUL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Scopes = reader.Scopes?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Scopes.Init(Scopes, (_s1, _v1) => _v1?.serialize(_s1)); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public IReadOnlyList Scopes + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public IReadOnlyList Scopes => ctx.ReadList(0).Cast(CapnpC.CSharp.Generator.Schema.Brand.Scope.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(0, 1); + } + + public ListOfStructsSerializer Scopes + { + get => BuildPointer>(0); + set => Link(0, value); + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xabd73485a9636bc9UL)] + public class Scope : ICapnpSerializable + { + public const UInt64 typeId = 0xabd73485a9636bc9UL; + public enum WHICH : ushort + { + Bind = 0, + Inherit = 1, + undefined = 65535 + } + + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + switch (reader.which) + { + case WHICH.Bind: + Bind = reader.Bind?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + break; + case WHICH.Inherit: + which = reader.which; + break; + } + + ScopeId = reader.ScopeId; + applyDefaults(); + } + + private WHICH _which = WHICH.undefined; + private object _content; + public WHICH which + { + get => _which; + set + { + if (value == _which) + return; + _which = value; + switch (value) + { + case WHICH.Bind: + _content = null; + break; + case WHICH.Inherit: + break; + } + } + } + + public void serialize(WRITER writer) + { + writer.which = which; + switch (which) + { + case WHICH.Bind: + writer.Bind.Init(Bind, (_s1, _v1) => _v1?.serialize(_s1)); + break; + case WHICH.Inherit: + break; + } + + writer.ScopeId = ScopeId; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong ScopeId + { + get; + set; + } + + public IReadOnlyList Bind + { + get => _which == WHICH.Bind ? (IReadOnlyList)_content : null; + set + { + _which = WHICH.Bind; + _content = value; + } + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public WHICH which => (WHICH)ctx.ReadDataUShort(64U, (ushort)0); + public ulong ScopeId => ctx.ReadDataULong(0UL, 0UL); + public IReadOnlyList Bind => which == WHICH.Bind ? ctx.ReadList(0).Cast(CapnpC.CSharp.Generator.Schema.Brand.Binding.READER.create) : default; + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(2, 1); + } + + public WHICH which + { + get => (WHICH)this.ReadDataUShort(64U, (ushort)0); + set => this.WriteData(64U, (ushort)value, (ushort)0); + } + + public ulong ScopeId + { + get => this.ReadDataULong(0UL, 0UL); + set => this.WriteData(0UL, value, 0UL); + } + + public ListOfStructsSerializer Bind + { + get => which == WHICH.Bind ? BuildPointer>(0) : default; + set => Link(0, value); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xc863cd16969ee7fcUL)] + public class Binding : ICapnpSerializable + { + public const UInt64 typeId = 0xc863cd16969ee7fcUL; + public enum WHICH : ushort + { + Unbound = 0, + Type = 1, + undefined = 65535 + } + + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + switch (reader.which) + { + case WHICH.Unbound: + which = reader.which; + break; + case WHICH.Type: + Type = CapnpSerializable.Create(reader.Type); + break; + } + + applyDefaults(); + } + + private WHICH _which = WHICH.undefined; + private object _content; + public WHICH which + { + get => _which; + set + { + if (value == _which) + return; + _which = value; + switch (value) + { + case WHICH.Unbound: + break; + case WHICH.Type: + _content = null; + break; + } + } + } + + public void serialize(WRITER writer) + { + writer.which = which; + switch (which) + { + case WHICH.Unbound: + break; + case WHICH.Type: + Type?.serialize(writer.Type); + break; + } + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public CapnpC.CSharp.Generator.Schema.Type Type + { + get => _which == WHICH.Type ? (CapnpC.CSharp.Generator.Schema.Type)_content : null; + set + { + _which = WHICH.Type; + _content = value; + } + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public WHICH which => (WHICH)ctx.ReadDataUShort(0U, (ushort)0); + public CapnpC.CSharp.Generator.Schema.Type.READER Type => which == WHICH.Type ? ctx.ReadStruct(0, CapnpC.CSharp.Generator.Schema.Type.READER.create) : default; + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(1, 1); + } + + public WHICH which + { + get => (WHICH)this.ReadDataUShort(0U, (ushort)0); + set => this.WriteData(0U, (ushort)value, (ushort)0); + } + + public CapnpC.CSharp.Generator.Schema.Type.WRITER Type + { + get => which == WHICH.Type ? BuildPointer(0) : default; + set => Link(0, value); + } + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xce23dcd2d7b00c9bUL)] + public class Value : ICapnpSerializable + { + public const UInt64 typeId = 0xce23dcd2d7b00c9bUL; + public enum WHICH : ushort + { + Void = 0, + Bool = 1, + Int8 = 2, + Int16 = 3, + Int32 = 4, + Int64 = 5, + Uint8 = 6, + Uint16 = 7, + Uint32 = 8, + Uint64 = 9, + Float32 = 10, + Float64 = 11, + Text = 12, + Data = 13, + List = 14, + Enum = 15, + Struct = 16, + Interface = 17, + AnyPointer = 18, + undefined = 65535 + } + + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + switch (reader.which) + { + case WHICH.Void: + which = reader.which; + break; + case WHICH.Bool: + Bool = reader.Bool; + break; + case WHICH.Int8: + Int8 = reader.Int8; + break; + case WHICH.Int16: + Int16 = reader.Int16; + break; + case WHICH.Int32: + Int32 = reader.Int32; + break; + case WHICH.Int64: + Int64 = reader.Int64; + break; + case WHICH.Uint8: + Uint8 = reader.Uint8; + break; + case WHICH.Uint16: + Uint16 = reader.Uint16; + break; + case WHICH.Uint32: + Uint32 = reader.Uint32; + break; + case WHICH.Uint64: + Uint64 = reader.Uint64; + break; + case WHICH.Float32: + Float32 = reader.Float32; + break; + case WHICH.Float64: + Float64 = reader.Float64; + break; + case WHICH.Text: + Text = reader.Text; + break; + case WHICH.Data: + Data = reader.Data; + break; + case WHICH.List: + List = CapnpSerializable.Create(reader.List); + break; + case WHICH.Enum: + Enum = reader.Enum; + break; + case WHICH.Struct: + Struct = CapnpSerializable.Create(reader.Struct); + break; + case WHICH.Interface: + which = reader.which; + break; + case WHICH.AnyPointer: + AnyPointer = CapnpSerializable.Create(reader.AnyPointer); + break; + } + + applyDefaults(); + } + + private WHICH _which = WHICH.undefined; + private object _content; + public WHICH which + { + get => _which; + set + { + if (value == _which) + return; + _which = value; + switch (value) + { + case WHICH.Void: + break; + case WHICH.Bool: + _content = false; + break; + case WHICH.Int8: + _content = 0; + break; + case WHICH.Int16: + _content = 0; + break; + case WHICH.Int32: + _content = 0; + break; + case WHICH.Int64: + _content = 0; + break; + case WHICH.Uint8: + _content = 0; + break; + case WHICH.Uint16: + _content = 0; + break; + case WHICH.Uint32: + _content = 0; + break; + case WHICH.Uint64: + _content = 0; + break; + case WHICH.Float32: + _content = 0F; + break; + case WHICH.Float64: + _content = 0; + break; + case WHICH.Text: + _content = null; + break; + case WHICH.Data: + _content = null; + break; + case WHICH.List: + _content = null; + break; + case WHICH.Enum: + _content = 0; + break; + case WHICH.Struct: + _content = null; + break; + case WHICH.Interface: + break; + case WHICH.AnyPointer: + _content = null; + break; + } + } + } + + public void serialize(WRITER writer) + { + writer.which = which; + switch (which) + { + case WHICH.Void: + break; + case WHICH.Bool: + writer.Bool = Bool.Value; + break; + case WHICH.Int8: + writer.Int8 = Int8.Value; + break; + case WHICH.Int16: + writer.Int16 = Int16.Value; + break; + case WHICH.Int32: + writer.Int32 = Int32.Value; + break; + case WHICH.Int64: + writer.Int64 = Int64.Value; + break; + case WHICH.Uint8: + writer.Uint8 = Uint8.Value; + break; + case WHICH.Uint16: + writer.Uint16 = Uint16.Value; + break; + case WHICH.Uint32: + writer.Uint32 = Uint32.Value; + break; + case WHICH.Uint64: + writer.Uint64 = Uint64.Value; + break; + case WHICH.Float32: + writer.Float32 = Float32.Value; + break; + case WHICH.Float64: + writer.Float64 = Float64.Value; + break; + case WHICH.Text: + writer.Text = Text; + break; + case WHICH.Data: + writer.Data.Init(Data); + break; + case WHICH.List: + writer.List.SetObject(List); + break; + case WHICH.Enum: + writer.Enum = Enum.Value; + break; + case WHICH.Struct: + writer.Struct.SetObject(Struct); + break; + case WHICH.Interface: + break; + case WHICH.AnyPointer: + writer.AnyPointer.SetObject(AnyPointer); + break; + } + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public bool? Bool + { + get => _which == WHICH.Bool ? (bool?)_content : null; + set + { + _which = WHICH.Bool; + _content = value; + } + } + + public sbyte? Int8 + { + get => _which == WHICH.Int8 ? (sbyte?)_content : null; + set + { + _which = WHICH.Int8; + _content = value; + } + } + + public short? Int16 + { + get => _which == WHICH.Int16 ? (short?)_content : null; + set + { + _which = WHICH.Int16; + _content = value; + } + } + + public int? Int32 + { + get => _which == WHICH.Int32 ? (int?)_content : null; + set + { + _which = WHICH.Int32; + _content = value; + } + } + + public long? Int64 + { + get => _which == WHICH.Int64 ? (long?)_content : null; + set + { + _which = WHICH.Int64; + _content = value; + } + } + + public byte? Uint8 + { + get => _which == WHICH.Uint8 ? (byte?)_content : null; + set + { + _which = WHICH.Uint8; + _content = value; + } + } + + public ushort? Uint16 + { + get => _which == WHICH.Uint16 ? (ushort?)_content : null; + set + { + _which = WHICH.Uint16; + _content = value; + } + } + + public uint? Uint32 + { + get => _which == WHICH.Uint32 ? (uint?)_content : null; + set + { + _which = WHICH.Uint32; + _content = value; + } + } + + public ulong? Uint64 + { + get => _which == WHICH.Uint64 ? (ulong?)_content : null; + set + { + _which = WHICH.Uint64; + _content = value; + } + } + + public float? Float32 + { + get => _which == WHICH.Float32 ? (float?)_content : null; + set + { + _which = WHICH.Float32; + _content = value; + } + } + + public double? Float64 + { + get => _which == WHICH.Float64 ? (double?)_content : null; + set + { + _which = WHICH.Float64; + _content = value; + } + } + + public string Text + { + get => _which == WHICH.Text ? (string)_content : null; + set + { + _which = WHICH.Text; + _content = value; + } + } + + public IReadOnlyList Data + { + get => _which == WHICH.Data ? (IReadOnlyList)_content : null; + set + { + _which = WHICH.Data; + _content = value; + } + } + + public object List + { + get => _which == WHICH.List ? (object)_content : null; + set + { + _which = WHICH.List; + _content = value; + } + } + + public ushort? Enum + { + get => _which == WHICH.Enum ? (ushort?)_content : null; + set + { + _which = WHICH.Enum; + _content = value; + } + } + + public object Struct + { + get => _which == WHICH.Struct ? (object)_content : null; + set + { + _which = WHICH.Struct; + _content = value; + } + } + + public object AnyPointer + { + get => _which == WHICH.AnyPointer ? (object)_content : null; + set + { + _which = WHICH.AnyPointer; + _content = value; + } + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public WHICH which => (WHICH)ctx.ReadDataUShort(0U, (ushort)0); + public bool Bool => which == WHICH.Bool ? ctx.ReadDataBool(16UL, false) : default; + public sbyte Int8 => which == WHICH.Int8 ? ctx.ReadDataSByte(16UL, (sbyte)0) : default; + public short Int16 => which == WHICH.Int16 ? ctx.ReadDataShort(16UL, (short)0) : default; + public int Int32 => which == WHICH.Int32 ? ctx.ReadDataInt(32UL, 0) : default; + public long Int64 => which == WHICH.Int64 ? ctx.ReadDataLong(64UL, 0L) : default; + public byte Uint8 => which == WHICH.Uint8 ? ctx.ReadDataByte(16UL, (byte)0) : default; + public ushort Uint16 => which == WHICH.Uint16 ? ctx.ReadDataUShort(16UL, (ushort)0) : default; + public uint Uint32 => which == WHICH.Uint32 ? ctx.ReadDataUInt(32UL, 0U) : default; + public ulong Uint64 => which == WHICH.Uint64 ? ctx.ReadDataULong(64UL, 0UL) : default; + public float Float32 => which == WHICH.Float32 ? ctx.ReadDataFloat(32UL, 0F) : default; + public double Float64 => which == WHICH.Float64 ? ctx.ReadDataDouble(64UL, 0) : default; + public string Text => which == WHICH.Text ? ctx.ReadText(0, null) : default; + public IReadOnlyList Data => which == WHICH.Data ? ctx.ReadList(0).CastByte() : default; + public DeserializerState List => which == WHICH.List ? ctx.StructReadPointer(0) : default; + public ushort Enum => which == WHICH.Enum ? ctx.ReadDataUShort(16UL, (ushort)0) : default; + public DeserializerState Struct => which == WHICH.Struct ? ctx.StructReadPointer(0) : default; + public DeserializerState AnyPointer => which == WHICH.AnyPointer ? ctx.StructReadPointer(0) : default; + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(2, 1); + } + + public WHICH which + { + get => (WHICH)this.ReadDataUShort(0U, (ushort)0); + set => this.WriteData(0U, (ushort)value, (ushort)0); + } + + public bool Bool + { + get => which == WHICH.Bool ? this.ReadDataBool(16UL, false) : default; + set => this.WriteData(16UL, value, false); + } + + public sbyte Int8 + { + get => which == WHICH.Int8 ? this.ReadDataSByte(16UL, (sbyte)0) : default; + set => this.WriteData(16UL, value, (sbyte)0); + } + + public short Int16 + { + get => which == WHICH.Int16 ? this.ReadDataShort(16UL, (short)0) : default; + set => this.WriteData(16UL, value, (short)0); + } + + public int Int32 + { + get => which == WHICH.Int32 ? this.ReadDataInt(32UL, 0) : default; + set => this.WriteData(32UL, value, 0); + } + + public long Int64 + { + get => which == WHICH.Int64 ? this.ReadDataLong(64UL, 0L) : default; + set => this.WriteData(64UL, value, 0L); + } + + public byte Uint8 + { + get => which == WHICH.Uint8 ? this.ReadDataByte(16UL, (byte)0) : default; + set => this.WriteData(16UL, value, (byte)0); + } + + public ushort Uint16 + { + get => which == WHICH.Uint16 ? this.ReadDataUShort(16UL, (ushort)0) : default; + set => this.WriteData(16UL, value, (ushort)0); + } + + public uint Uint32 + { + get => which == WHICH.Uint32 ? this.ReadDataUInt(32UL, 0U) : default; + set => this.WriteData(32UL, value, 0U); + } + + public ulong Uint64 + { + get => which == WHICH.Uint64 ? this.ReadDataULong(64UL, 0UL) : default; + set => this.WriteData(64UL, value, 0UL); + } + + public float Float32 + { + get => which == WHICH.Float32 ? this.ReadDataFloat(32UL, 0F) : default; + set => this.WriteData(32UL, value, 0F); + } + + public double Float64 + { + get => which == WHICH.Float64 ? this.ReadDataDouble(64UL, 0) : default; + set => this.WriteData(64UL, value, 0); + } + + public string Text + { + get => which == WHICH.Text ? this.ReadText(0, null) : default; + set => this.WriteText(0, value, null); + } + + public ListOfPrimitivesSerializer Data + { + get => which == WHICH.Data ? BuildPointer>(0) : default; + set => Link(0, value); + } + + public DynamicSerializerState List + { + get => which == WHICH.List ? BuildPointer(0) : default; + set => Link(0, value); + } + + public ushort Enum + { + get => which == WHICH.Enum ? this.ReadDataUShort(16UL, (ushort)0) : default; + set => this.WriteData(16UL, value, (ushort)0); + } + + public DynamicSerializerState Struct + { + get => which == WHICH.Struct ? BuildPointer(0) : default; + set => Link(0, value); + } + + public DynamicSerializerState AnyPointer + { + get => which == WHICH.AnyPointer ? BuildPointer(0) : default; + set => Link(0, value); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xf1c8950dab257542UL)] + public class Annotation : ICapnpSerializable + { + public const UInt64 typeId = 0xf1c8950dab257542UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Id = reader.Id; + Value = CapnpSerializable.Create(reader.Value); + Brand = CapnpSerializable.Create(reader.Brand); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Id = Id; + Value?.serialize(writer.Value); + Brand?.serialize(writer.Brand); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong Id + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Value Value + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.Brand Brand + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ulong Id => ctx.ReadDataULong(0UL, 0UL); + public CapnpC.CSharp.Generator.Schema.Value.READER Value => ctx.ReadStruct(0, CapnpC.CSharp.Generator.Schema.Value.READER.create); + public CapnpC.CSharp.Generator.Schema.Brand.READER Brand => ctx.ReadStruct(1, CapnpC.CSharp.Generator.Schema.Brand.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(1, 2); + } + + public ulong Id + { + get => this.ReadDataULong(0UL, 0UL); + set => this.WriteData(0UL, value, 0UL); + } + + public CapnpC.CSharp.Generator.Schema.Value.WRITER Value + { + get => BuildPointer(0); + set => Link(0, value); + } + + public CapnpC.CSharp.Generator.Schema.Brand.WRITER Brand + { + get => BuildPointer(1); + set => Link(1, value); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd1958f7dba521926UL)] + public enum ElementSize : ushort + { + empty, + bit, + @byte, + twoBytes, + fourBytes, + eightBytes, + pointer, + inlineComposite + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xd85d305b7d839963UL)] + public class CapnpVersion : ICapnpSerializable + { + public const UInt64 typeId = 0xd85d305b7d839963UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Major = reader.Major; + Minor = reader.Minor; + Micro = reader.Micro; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Major = Major; + writer.Minor = Minor; + writer.Micro = Micro; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ushort Major + { + get; + set; + } + + public byte Minor + { + get; + set; + } + + public byte Micro + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ushort Major => ctx.ReadDataUShort(0UL, (ushort)0); + public byte Minor => ctx.ReadDataByte(16UL, (byte)0); + public byte Micro => ctx.ReadDataByte(24UL, (byte)0); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(1, 0); + } + + public ushort Major + { + get => this.ReadDataUShort(0UL, (ushort)0); + set => this.WriteData(0UL, value, (ushort)0); + } + + public byte Minor + { + get => this.ReadDataByte(16UL, (byte)0); + set => this.WriteData(16UL, value, (byte)0); + } + + public byte Micro + { + get => this.ReadDataByte(24UL, (byte)0); + set => this.WriteData(24UL, value, (byte)0); + } + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xbfc546f6210ad7ceUL)] + public class CodeGeneratorRequest : ICapnpSerializable + { + public const UInt64 typeId = 0xbfc546f6210ad7ceUL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Nodes = reader.Nodes?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + RequestedFiles = reader.RequestedFiles?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + CapnpVersion = CapnpSerializable.Create(reader.CapnpVersion); + SourceInfo = reader.SourceInfo?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Nodes.Init(Nodes, (_s1, _v1) => _v1?.serialize(_s1)); + writer.RequestedFiles.Init(RequestedFiles, (_s1, _v1) => _v1?.serialize(_s1)); + CapnpVersion?.serialize(writer.CapnpVersion); + writer.SourceInfo.Init(SourceInfo, (_s1, _v1) => _v1?.serialize(_s1)); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public IReadOnlyList Nodes + { + get; + set; + } + + public IReadOnlyList RequestedFiles + { + get; + set; + } + + public CapnpC.CSharp.Generator.Schema.CapnpVersion CapnpVersion + { + get; + set; + } + + public IReadOnlyList SourceInfo + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public IReadOnlyList Nodes => ctx.ReadList(0).Cast(CapnpC.CSharp.Generator.Schema.Node.READER.create); + public IReadOnlyList RequestedFiles => ctx.ReadList(1).Cast(CapnpC.CSharp.Generator.Schema.CodeGeneratorRequest.RequestedFile.READER.create); + public CapnpC.CSharp.Generator.Schema.CapnpVersion.READER CapnpVersion => ctx.ReadStruct(2, CapnpC.CSharp.Generator.Schema.CapnpVersion.READER.create); + public IReadOnlyList SourceInfo => ctx.ReadList(3).Cast(CapnpC.CSharp.Generator.Schema.Node.SourceInfo.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(0, 4); + } + + public ListOfStructsSerializer Nodes + { + get => BuildPointer>(0); + set => Link(0, value); + } + + public ListOfStructsSerializer RequestedFiles + { + get => BuildPointer>(1); + set => Link(1, value); + } + + public CapnpC.CSharp.Generator.Schema.CapnpVersion.WRITER CapnpVersion + { + get => BuildPointer(2); + set => Link(2, value); + } + + public ListOfStructsSerializer SourceInfo + { + get => BuildPointer>(3); + set => Link(3, value); + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xcfea0eb02e810062UL)] + public class RequestedFile : ICapnpSerializable + { + public const UInt64 typeId = 0xcfea0eb02e810062UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Id = reader.Id; + Filename = reader.Filename; + Imports = reader.Imports?.ToReadOnlyList(_ => CapnpSerializable.Create(_)); + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Id = Id; + writer.Filename = Filename; + writer.Imports.Init(Imports, (_s1, _v1) => _v1?.serialize(_s1)); + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong Id + { + get; + set; + } + + public string Filename + { + get; + set; + } + + public IReadOnlyList Imports + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ulong Id => ctx.ReadDataULong(0UL, 0UL); + public string Filename => ctx.ReadText(0, null); + public IReadOnlyList Imports => ctx.ReadList(1).Cast(CapnpC.CSharp.Generator.Schema.CodeGeneratorRequest.RequestedFile.Import.READER.create); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(1, 2); + } + + public ulong Id + { + get => this.ReadDataULong(0UL, 0UL); + set => this.WriteData(0UL, value, 0UL); + } + + public string Filename + { + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); + } + + public ListOfStructsSerializer Imports + { + get => BuildPointer>(1); + set => Link(1, value); + } + } + + [System.CodeDom.Compiler.GeneratedCode("capnpc-csharp", "1.3.0.0"), TypeId(0xae504193122357e5UL)] + public class Import : ICapnpSerializable + { + public const UInt64 typeId = 0xae504193122357e5UL; + void ICapnpSerializable.Deserialize(DeserializerState arg_) + { + var reader = READER.create(arg_); + Id = reader.Id; + Name = reader.Name; + applyDefaults(); + } + + public void serialize(WRITER writer) + { + writer.Id = Id; + writer.Name = Name; + } + + void ICapnpSerializable.Serialize(SerializerState arg_) + { + serialize(arg_.Rewrap()); + } + + public void applyDefaults() + { + } + + public ulong Id + { + get; + set; + } + + public string Name + { + get; + set; + } + + public struct READER + { + readonly DeserializerState ctx; + public READER(DeserializerState ctx) + { + this.ctx = ctx; + } + + public static READER create(DeserializerState ctx) => new READER(ctx); + public static implicit operator DeserializerState(READER reader) => reader.ctx; + public static implicit operator READER(DeserializerState ctx) => new READER(ctx); + public ulong Id => ctx.ReadDataULong(0UL, 0UL); + public string Name => ctx.ReadText(0, null); + } + + public class WRITER : SerializerState + { + public WRITER() + { + this.SetStruct(1, 1); + } + + public ulong Id + { + get => this.ReadDataULong(0UL, 0UL); + set => this.WriteData(0UL, value, 0UL); + } + + public string Name + { + get => this.ReadText(0, null); + set => this.WriteText(0, value, null); + } + } + } + } + } +} \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 933127e..2f119b9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -83,10 +83,10 @@ test_script: vstest.console /logger:Appveyor /inIsolation CapnpC.CSharp.MsBuild.Generation.Tests\bin\Release\netcoreapp3.0\CapnpC.CSharp.MsBuild.Generation.Tests.dll msbuild -t:restore ./MsBuildGenerationTest/MsBuildGenerationTest.csproj /p:Configuration="Debug" /p:PackageReferenceVersion="%VERSION%" msbuild ./MsBuildGenerationTest/MsBuildGenerationTest.sln /p:Configuration="Debug" /p:PackageReferenceVersion="%VERSION%" - vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Debug\net471\Capnp.Net.Runtime.Tests.Std20.dll - vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Release\net471\Capnp.Net.Runtime.Tests.Std20.dll - vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Debug\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll - vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.Core21.dll + vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Debug\net471\Capnp.Net.Runtime.Tests.dll + vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Release\net471\Capnp.Net.Runtime.Tests.dll + vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Debug\netcoreapp2.1\Capnp.Net.Runtime.Tests.dll + vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.dll powershell -File .\scripts\measure-coverage.ps1 csmacnz.Coveralls --multiple -i "opencover=coverage\cov-Capnp.Net.Runtime.xml;opencover=coverage\cov-CapnpC.CSharp.Generator.xml" --repoToken %COVERALLS_REPO_TOKEN% on_finish : From d833dbe5919ec4c039fdf9fe039e9716c9bbd092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 19 Apr 2020 18:53:09 +0200 Subject: [PATCH 54/76] fixed race condition in RemoteResolvingCapability fixed test framework error --- Capnp.Net.Runtime.Tests/Interception.cs | 2 +- Capnp.Net.Runtime.Tests/TcpRpcPorted.cs | 2 +- Capnp.Net.Runtime.Tests/TcpRpcStress.cs | 12 ++++- Capnp.Net.Runtime.Tests/Util/FluctStream.cs | 50 +++++++++++++++++++ .../Util/ScatteringStream.cs | 1 + Capnp.Net.Runtime.Tests/Util/TestBase.cs | 33 +++++++++--- .../Rpc/RemoteResolvingCapability.cs | 21 +++----- .../Util/StrictlyOrderedAwaitTask.cs | 35 ++++++++++--- 8 files changed, 124 insertions(+), 32 deletions(-) create mode 100644 Capnp.Net.Runtime.Tests/Util/FluctStream.cs diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index 76421da..ab6b9f4 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -400,7 +400,7 @@ namespace Capnp.Net.Runtime.Tests { var policy = new MyPolicy("a"); - (var server, var client) = SetupClientServerPair(true); + (var server, var client) = SetupClientServerPair(TcpRpcTestOptions.ClientTracer); using (server) using (client) diff --git a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs index 20fc392..3e24333 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs @@ -26,7 +26,7 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void Pipeline() { - NewLocalhostTcpTestbed().RunTest(Testsuite.Pipeline); + NewLocalhostTcpTestbed(TcpRpcTestOptions.ClientTracer).RunTest(Testsuite.Pipeline); } [TestMethod] diff --git a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs index 43a3cbd..b5de959 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs @@ -53,6 +53,7 @@ namespace Capnp.Net.Runtime.Tests public void Cancel() { var t = new TcpRpcPorted(); + t.InitConsoleLogging(); Repeat(1000, t.Cancel); } @@ -60,13 +61,18 @@ namespace Capnp.Net.Runtime.Tests public void Embargo() { var t = new TcpRpcPorted(); - Repeat(100, t.Embargo); + t.InitConsoleLogging(); + Repeat(100, + () => + NewLocalhostTcpTestbed(TcpRpcTestOptions.ClientTracer | TcpRpcTestOptions.ClientFluctStream) + .RunTest(Testsuite.EmbargoOnPromisedAnswer)); } [TestMethod] public void EmbargoServer() { var t2 = new TcpRpcInterop(); + t2.InitConsoleLogging(); Repeat(20, t2.EmbargoServer); } @@ -76,9 +82,11 @@ namespace Capnp.Net.Runtime.Tests // Some code paths are really rare during this test, therefore increased repetition count. var t = new TcpRpcPorted(); + t.InitConsoleLogging(); Repeat(1000, t.EmbargoNull); var t2 = new TcpRpcInterop(); + t2.InitConsoleLogging(); Repeat(100, t2.EmbargoNullServer); } @@ -86,6 +94,7 @@ namespace Capnp.Net.Runtime.Tests public void RetainAndRelease() { var t = new TcpRpcPorted(); + t.InitConsoleLogging(); Repeat(100, t.RetainAndRelease); } @@ -93,6 +102,7 @@ namespace Capnp.Net.Runtime.Tests public void PipelineAfterReturn() { var t = new TcpRpc(); + t.InitConsoleLogging(); Repeat(100, t.PipelineAfterReturn); } diff --git a/Capnp.Net.Runtime.Tests/Util/FluctStream.cs b/Capnp.Net.Runtime.Tests/Util/FluctStream.cs new file mode 100644 index 0000000..e5a9406 --- /dev/null +++ b/Capnp.Net.Runtime.Tests/Util/FluctStream.cs @@ -0,0 +1,50 @@ +using System; +using System.IO; +using System.Threading; + +namespace Capnp.Net.Runtime.Tests +{ + class FluctStream : Stream + { + readonly Stream _baseStream; + readonly Random _rng = new Random(); + + public FluctStream(Stream baseStream) + { + _baseStream = baseStream; + } + + public override bool CanRead => _baseStream.CanRead; + + public override bool CanSeek => false; + + public override bool CanWrite => _baseStream.CanWrite; + + public override long Length => _baseStream.Length; + + public override long Position + { + get => _baseStream.Position; + set => throw new NotImplementedException(); + } + + public override void Flush() => _baseStream.Flush(); + + public override int Read(byte[] buffer, int offset, int count) + { + int n = _rng.Next(0, 8); + if (n >= 7) + Thread.Sleep(n - 7); + return _baseStream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException(); + + public override void SetLength(long value) => throw new NotImplementedException(); + + public override void Write(byte[] buffer, int offset, int count) + { + _baseStream.Write(buffer, offset, count); + } + } +} diff --git a/Capnp.Net.Runtime.Tests/Util/ScatteringStream.cs b/Capnp.Net.Runtime.Tests/Util/ScatteringStream.cs index e6b44df..6335167 100644 --- a/Capnp.Net.Runtime.Tests/Util/ScatteringStream.cs +++ b/Capnp.Net.Runtime.Tests/Util/ScatteringStream.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace Capnp.Net.Runtime.Tests diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 2b08763..41279b2 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -263,13 +263,19 @@ namespace Capnp.Net.Runtime.Tests protected class LocalhostTcpTestbed : ITestbed, ITestController { + readonly TcpRpcTestOptions _options; TcpRpcServer _server; TcpRpcClient _client; bool _prematurelyClosed; + public LocalhostTcpTestbed(TcpRpcTestOptions options) + { + _options = options; + } + public void RunTest(Action action) { - (_server, _client) = SetupClientServerPair(); + (_server, _client) = SetupClientServerPair(_options); Assert.IsTrue(SpinWait.SpinUntil(() => _server.ConnectionCount > 0, MediumNonDbgTimeout)); var conn = _server.Connections[0]; @@ -345,16 +351,26 @@ namespace Capnp.Net.Runtime.Tests protected ILogger Logger { get; set; } - protected static TcpRpcClient SetupClient(bool withTracer = false) + protected static TcpRpcClient SetupClient(TcpRpcTestOptions options = TcpRpcTestOptions.None) { var client = new TcpRpcClient(); client.AddBuffering(); - if (withTracer) + if (options.HasFlag(TcpRpcTestOptions.ClientTracer)) client.AttachTracer(new FrameTracing.RpcFrameTracer(Console.Out, false)); + if (options.HasFlag(TcpRpcTestOptions.ClientFluctStream)) + client.InjectMidlayer(s => new FluctStream(s)); client.Connect("localhost", TcpPort); return client; } + [Flags] + public enum TcpRpcTestOptions + { + None = 0, + ClientTracer = 1, + ClientFluctStream = 2 + } + protected static TcpRpcServer SetupServer() { int attempt = 0; @@ -381,10 +397,10 @@ namespace Capnp.Net.Runtime.Tests } } - protected static (TcpRpcServer, TcpRpcClient) SetupClientServerPair(bool withClientTracer = false) + protected static (TcpRpcServer, TcpRpcClient) SetupClientServerPair(TcpRpcTestOptions options = TcpRpcTestOptions.None) { var server = SetupServer(); - var client = SetupClient(withClientTracer); + var client = SetupClient(options); return (server, client); } @@ -404,7 +420,8 @@ namespace Capnp.Net.Runtime.Tests } protected static DtbdctTestbed NewDtbdctTestbed() => new DtbdctTestbed(); - protected static LocalhostTcpTestbed NewLocalhostTcpTestbed() => new LocalhostTcpTestbed(); + protected static LocalhostTcpTestbed NewLocalhostTcpTestbed(TcpRpcTestOptions options = TcpRpcTestOptions.None) => + new LocalhostTcpTestbed(options); protected static LocalTestbed NewLocalTestbed() => new LocalTestbed(); @@ -412,9 +429,9 @@ namespace Capnp.Net.Runtime.Tests public void InitConsoleLogging() { Logging.LoggerFactory?.Dispose(); -#pragma warning disable CS0618 // Typ oder Element ist veraltet +#pragma warning disable CS0618 Logging.LoggerFactory = new LoggerFactory().AddConsole((msg, level) => true); -#pragma warning restore CS0618 // Typ oder Element ist veraltet +#pragma warning restore CS0618 Logger = Logging.CreateLogger(); if (Thread.CurrentThread.Name == null) Thread.CurrentThread.Name = $"Test Thread {Thread.CurrentThread.ManagedThreadId}"; diff --git a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs index 937b66b..0dc9ac7 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Logging; +using Capnp.Util; +using Microsoft.Extensions.Logging; using System; using System.Threading; using System.Threading.Tasks; @@ -24,7 +25,7 @@ namespace Capnp.Rpc } protected int _pendingCallsOnPromise; - Task? _disembargo; + StrictlyOrderedAwaitTask? _disembargo; protected abstract ConsumedCapability? ResolvedCap { get; } @@ -64,7 +65,7 @@ namespace Capnp.Rpc #if DebugEmbargos Logger.LogDebug("Requesting disembargo"); #endif - _disembargo = _ep.RequestSenderLoopback(GetMessageTarget); + _disembargo = _ep.RequestSenderLoopback(GetMessageTarget).EnforceAwaitOrder(); } else { @@ -75,8 +76,10 @@ namespace Capnp.Rpc var cancellationTokenSource = new CancellationTokenSource(); - var callAfterDisembargo = _disembargo.ContinueWith(_ => + async Task AwaitAnswer() { + await _disembargo!; + // Two reasons for ignoring exceptions on the previous task (i.e. not _.Wait()ing): // 1. A faulting predecessor, especially due to cancellation, must not have any impact on this one. // 2. A faulting disembargo request would imply that the other side cannot send pending requests anyway. @@ -88,15 +91,7 @@ namespace Capnp.Rpc } using var proxy = new Proxy(resolvedCap); - return proxy.Call(interfaceId, methodId, args, default); - - }, TaskContinuationOptions.ExecuteSynchronously); - - _disembargo = callAfterDisembargo; - - async Task AwaitAnswer() - { - var promisedAnswer = await callAfterDisembargo; + var promisedAnswer = proxy.Call(interfaceId, methodId, args, default); using (cancellationTokenSource.Token.Register(promisedAnswer.Dispose)) { diff --git a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs index 1565aa4..a7c6602 100644 --- a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs +++ b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace Capnp.Util { - internal class StrictlyOrderedAwaitTask: INotifyCompletion + internal class StrictlyOrderedAwaitTask: INotifyCompletion { class Cover { } class Seal { } @@ -15,16 +15,16 @@ namespace Capnp.Util static readonly Cover s_cover = new Cover(); static readonly Seal s_seal = new Seal(); - readonly Task _awaitedTask; + readonly Task _awaitedTask; object? _state; - public StrictlyOrderedAwaitTask(Task awaitedTask) + public StrictlyOrderedAwaitTask(Task awaitedTask) { _awaitedTask = awaitedTask; _state = s_cover; } - public StrictlyOrderedAwaitTask GetAwaiter() + public StrictlyOrderedAwaitTask GetAwaiter() { return this; } @@ -94,18 +94,37 @@ namespace Capnp.Util public bool IsCompleted => _awaitedTask.IsCompleted && _state == s_seal; - public T GetResult() => _awaitedTask.GetAwaiter().GetResult(); + public void GetResult() => _awaitedTask.GetAwaiter().GetResult(); - public T Result => _awaitedTask.Result; - - public Task WrappedTask => _awaitedTask; + public Task WrappedTask => _awaitedTask; } + internal class StrictlyOrderedAwaitTask : StrictlyOrderedAwaitTask + { + public StrictlyOrderedAwaitTask(Task awaitedTask): base(awaitedTask) + { + } + + public new Task WrappedTask => (Task)base.WrappedTask; + public new StrictlyOrderedAwaitTask GetAwaiter() => this; + + public new T GetResult() => WrappedTask.GetAwaiter().GetResult(); + + public T Result => WrappedTask.Result; + + } + + internal static class StrictlyOrderedTaskExtensions { public static StrictlyOrderedAwaitTask EnforceAwaitOrder(this Task task) { return new StrictlyOrderedAwaitTask(task); } + + public static StrictlyOrderedAwaitTask EnforceAwaitOrder(this Task task) + { + return new StrictlyOrderedAwaitTask(task); + } } } From 14adb1ed71e95136b285d8cf7e400f2d7d5d6ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 19 Apr 2020 20:25:56 +0200 Subject: [PATCH 55/76] increased client connection timeout --- Capnp.Net.Runtime.Tests/Util/TestBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 41279b2..61d68ad 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -276,7 +276,7 @@ namespace Capnp.Net.Runtime.Tests public void RunTest(Action action) { (_server, _client) = SetupClientServerPair(_options); - Assert.IsTrue(SpinWait.SpinUntil(() => _server.ConnectionCount > 0, MediumNonDbgTimeout)); + Assert.IsTrue(SpinWait.SpinUntil(() => _server.ConnectionCount > 0, 2 * MediumNonDbgTimeout)); var conn = _server.Connections[0]; using (_server) From fcc8108e9e83ceecfdd3d38db3b0b4c2d3ac7077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 19 Apr 2020 22:08:10 +0200 Subject: [PATCH 56/76] made tcp server handling in tests more robust --- Capnp.Net.Runtime.Tests/TcpRpc.cs | 64 +++++++++++------------- Capnp.Net.Runtime.Tests/Util/TestBase.cs | 6 ++- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index 0a99b2e..1285b09 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -16,38 +16,9 @@ namespace Capnp.Net.Runtime.Tests [TestClass] [TestCategory("Coverage")] - public class TcpRpc + public class TcpRpc: TestBase { - public static int TcpPort = 49153; - - (TcpRpcServer, TcpRpcClient) SetupClientServerPair() - { - var server = new TcpRpcServer(IPAddress.Any, TcpPort); - var client = new TcpRpcClient("localhost", TcpPort); - return (server, client); - } - - bool ExpectingLogOutput { get; set; } - - [TestInitialize] - public void InitConsoleLogging() - { - ExpectingLogOutput = true; - - Logging.LoggerFactory?.Dispose(); -#pragma warning disable CS0618 // Typ oder Element ist veraltet - Logging.LoggerFactory = new LoggerFactory().AddConsole((msg, level) => - { - if (!ExpectingLogOutput && level != LogLevel.Debug) - { - Assert.Fail("Did not expect any logging output, but got this: " + msg); - } - return true; - }); -#pragma warning restore CS0618 // Typ oder Element ist veraltet - } - - int MediumNonDbgTimeout => Debugger.IsAttached ? Timeout.Infinite : 2000; + bool ExpectingLogOutput { get; set; } = true; [TestMethod] public void CreateAndDispose() @@ -720,9 +691,30 @@ namespace Capnp.Net.Runtime.Tests } } + static void RobustStartAccepting(TcpRpcServer server) + { + int retry = 0; + + do + { + try + { + server.StartAccepting(IPAddress.Any, TcpPort); + break; + } + catch (SocketException) + { + if (retry++ == 100) + throw; + + IncrementTcpPort(); + } + } while (true); + } + [TestMethod] public void Server1() - { + { var cbb = new BufferBlock(); var server = new TcpRpcServer(); server.Main = new TestInterfaceImpl2(); @@ -757,7 +749,7 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => server.StopListening()); - server.StartAccepting(IPAddress.Any, TcpPort); + RobustStartAccepting(server); Assert.IsTrue(server.IsAlive); Assert.ThrowsException(() => server.StartAccepting(IPAddress.Any, TcpPort)); @@ -822,7 +814,7 @@ namespace Capnp.Net.Runtime.Tests server.Dispose(); }; - server.StartAccepting(IPAddress.Any, TcpPort); + RobustStartAccepting(server); var client1 = new TcpRpcClient("localhost", TcpPort); Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout), "Did not connect"); @@ -842,7 +834,7 @@ namespace Capnp.Net.Runtime.Tests a.Connection.Close(); }; - server.StartAccepting(IPAddress.Any, TcpPort); + RobustStartAccepting(server); var client1 = new TcpRpcClient("localhost", TcpPort); Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout)); @@ -863,7 +855,7 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => client.GetMain()); Assert.ThrowsException(() => client.AttachTracer(null)); Assert.ThrowsException(() => client.InjectMidlayer(null)); - server.StartAccepting(IPAddress.Any, TcpPort); + RobustStartAccepting(server); client.Connect("localhost", TcpPort); Assert.ThrowsException(() => client.Connect("localhost", TcpPort)); Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 61d68ad..13a93bb 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -359,7 +359,8 @@ namespace Capnp.Net.Runtime.Tests client.AttachTracer(new FrameTracing.RpcFrameTracer(Console.Out, false)); if (options.HasFlag(TcpRpcTestOptions.ClientFluctStream)) client.InjectMidlayer(s => new FluctStream(s)); - client.Connect("localhost", TcpPort); + if (!options.HasFlag(TcpRpcTestOptions.ClientNoConnect)) + client.Connect("localhost", TcpPort); return client; } @@ -368,7 +369,8 @@ namespace Capnp.Net.Runtime.Tests { None = 0, ClientTracer = 1, - ClientFluctStream = 2 + ClientFluctStream = 2, + ClientNoConnect = 4 } protected static TcpRpcServer SetupServer() From e496a19e3d74fbdbe708bcfecbd42db15c6b9fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Sun, 19 Apr 2020 22:33:59 +0200 Subject: [PATCH 57/76] CI coverage upload fix --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 2f119b9..58e1811 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -88,7 +88,7 @@ test_script: vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Debug\netcoreapp2.1\Capnp.Net.Runtime.Tests.dll vstest.console /logger:Appveyor /inIsolation Capnp.Net.Runtime.Tests\bin\Release\netcoreapp2.1\Capnp.Net.Runtime.Tests.dll powershell -File .\scripts\measure-coverage.ps1 - csmacnz.Coveralls --multiple -i "opencover=coverage\cov-Capnp.Net.Runtime.xml;opencover=coverage\cov-CapnpC.CSharp.Generator.xml" --repoToken %COVERALLS_REPO_TOKEN% + csmacnz.Coveralls --opencover -i "coverage\coverage.xml" --repoToken %COVERALLS_REPO_TOKEN% on_finish : # any cleanup in here deploy: From 16c9f8871a8028d78e04b797c119b9092a0fec46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Mon, 20 Apr 2020 08:14:02 +0200 Subject: [PATCH 58/76] attempting to fix race cond. with StrictlyOrderedAwaitTask --- Capnp.Net.Runtime.Tests/General.cs | 7 ++++- Capnp.Net.Runtime.Tests/ImpatientTests.cs | 13 +++++++-- .../Mock/TestCapImplementations.cs | 1 + Capnp.Net.Runtime.Tests/TcpRpc.cs | 29 ++++++++++--------- .../TcpRpcAdvancedStuff.cs | 2 +- Capnp.Net.Runtime.Tests/TcpRpcInterop.cs | 4 +-- Capnp.Net.Runtime.Tests/Util/TestBase.cs | 2 +- Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs | 5 ++-- .../Rpc/Interception/CallContext.cs | 10 ++++--- Capnp.Net.Runtime/Rpc/LocalAnswer.cs | 7 +++-- .../Rpc/LocalAnswerCapability.cs | 7 +++-- Capnp.Net.Runtime/Rpc/PendingQuestion.cs | 8 +++-- Capnp.Net.Runtime/Rpc/PromisedCapability.cs | 5 ++-- .../Rpc/RemoteAnswerCapability.cs | 5 ++-- .../Util/StrictlyOrderedAwaitTask.cs | 6 ++-- 15 files changed, 68 insertions(+), 43 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/General.cs b/Capnp.Net.Runtime.Tests/General.cs index 3ca548b..856771b 100644 --- a/Capnp.Net.Runtime.Tests/General.cs +++ b/Capnp.Net.Runtime.Tests/General.cs @@ -48,7 +48,12 @@ namespace Capnp.Net.Runtime.Tests { readonly TaskCompletionSource _tcs = new TaskCompletionSource(); - public Task WhenReturned => _tcs.Task; + public PromisedAnswerMock() + { + WhenReturned = _tcs.Task.EnforceAwaitOrder(); + } + + public StrictlyOrderedAwaitTask WhenReturned { get; } public void Return() { diff --git a/Capnp.Net.Runtime.Tests/ImpatientTests.cs b/Capnp.Net.Runtime.Tests/ImpatientTests.cs index a009a43..f57dad7 100644 --- a/Capnp.Net.Runtime.Tests/ImpatientTests.cs +++ b/Capnp.Net.Runtime.Tests/ImpatientTests.cs @@ -1,5 +1,6 @@ using Capnp.Net.Runtime.Tests.GenImpls; using Capnp.Rpc; +using Capnp.Util; using Capnproto_test.Capnp.Test; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; @@ -140,7 +141,12 @@ namespace Capnp.Net.Runtime.Tests class PromisedAnswerMock : IPromisedAnswer { readonly TaskCompletionSource _tcs = new TaskCompletionSource(); - public Task WhenReturned => _tcs.Task; + public StrictlyOrderedAwaitTask WhenReturned { get; } + + public PromisedAnswerMock() + { + WhenReturned = _tcs.Task.EnforceAwaitOrder(); + } public bool IsTailCall => false; @@ -164,7 +170,7 @@ namespace Capnp.Net.Runtime.Tests { #pragma warning disable CS0618 var answer = new PromisedAnswerMock(); - Assert.ThrowsException(() => Impatient.GetAnswer(answer.WhenReturned)); + Assert.ThrowsException(() => Impatient.GetAnswer(Task.FromResult(new object()))); var t = Impatient.MakePipelineAware(answer, _ => _); Assert.AreEqual(answer, Impatient.GetAnswer(t)); #pragma warning restore CS0618 @@ -174,7 +180,8 @@ namespace Capnp.Net.Runtime.Tests public async Task Access() { var answer = new PromisedAnswerMock(); - var cap = Impatient.Access(answer.WhenReturned, new MemberAccessPath(), Task.FromResult(new TestInterfaceImpl2())); + async Task AwaitReturn() => await answer.WhenReturned; + var cap = Impatient.Access(AwaitReturn(), new MemberAccessPath(), Task.FromResult(new TestInterfaceImpl2())); using (var proxy = new BareProxy(cap)) { await proxy.WhenResolved; diff --git a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs index 7f1cac5..5d19630 100644 --- a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs @@ -608,6 +608,7 @@ namespace Capnp.Net.Runtime.Tests.GenImpls { lock (_lock) { + Assert.AreEqual(expected, _counter); return Task.FromResult(_counter++); } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index 1285b09..2abdc4e 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -132,7 +132,7 @@ namespace Capnp.Net.Runtime.Tests result.WriteData(0, 654321); mock.Return.SetResult(result); - Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer.WhenReturned.WrappedTask.Wait(MediumNonDbgTimeout)); var outresult = answer.WhenReturned.Result; Assert.AreEqual(ObjectKind.Struct, outresult.Kind); Assert.AreEqual(654321, outresult.ReadDataInt(0)); @@ -170,7 +170,7 @@ namespace Capnp.Net.Runtime.Tests mock.Return.SetCanceled(); - Assert.IsTrue(Assert.ThrowsExceptionAsync(() => answer.WhenReturned).Wait(MediumNonDbgTimeout)); + Assert.IsTrue(Assert.ThrowsExceptionAsync(async () => await answer.WhenReturned).Wait(MediumNonDbgTimeout)); } } } @@ -266,7 +266,8 @@ namespace Capnp.Net.Runtime.Tests // Even after the client cancelled the call, the server must still send // a response. - Assert.IsTrue(answer.WhenReturned.ContinueWith(t => { }).Wait(MediumNonDbgTimeout)); + async Task AwaitWhenReturned() => await answer.WhenReturned; + Assert.IsTrue(AwaitWhenReturned().ContinueWith(t => { }).Wait(MediumNonDbgTimeout)); } finally { @@ -312,7 +313,7 @@ namespace Capnp.Net.Runtime.Tests mock.Return.SetException(new MyTestException()); - var exTask = Assert.ThrowsExceptionAsync(() => answer.WhenReturned); + var exTask = Assert.ThrowsExceptionAsync(async () => await answer.WhenReturned); Assert.IsTrue(exTask.Wait(MediumNonDbgTimeout)); Assert.IsTrue(exTask.Result.Message.Contains(new MyTestException().Message)); } @@ -367,7 +368,7 @@ namespace Capnp.Net.Runtime.Tests mock.Return.SetResult(result); - Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer.WhenReturned.WrappedTask.Wait(MediumNonDbgTimeout)); Assert.IsFalse(ct.IsCancellationRequested); Assert.IsTrue(mock2.WhenCalled.Wait(MediumNonDbgTimeout)); @@ -383,7 +384,7 @@ namespace Capnp.Net.Runtime.Tests result2.WriteData(0, 222222); mock2.Return.SetResult(result2); - Assert.IsTrue(answer2.WhenReturned.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer2.WhenReturned.WrappedTask.Wait(MediumNonDbgTimeout)); var outresult2 = answer2.WhenReturned.Result; Assert.AreEqual(ObjectKind.Struct, outresult2.Kind); Assert.AreEqual(222222, outresult2.ReadDataInt(0)); @@ -443,7 +444,7 @@ namespace Capnp.Net.Runtime.Tests using (var answer2 = pipelined.Call(0x8765432187654321, 0x4444, args2)) { - Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer.WhenReturned.WrappedTask.Wait(MediumNonDbgTimeout)); Assert.IsTrue(mock2.WhenCalled.Wait(MediumNonDbgTimeout)); (var interfaceId2, var methodId2, var inargs2, var ct2) = mock2.WhenCalled.Result; @@ -457,7 +458,7 @@ namespace Capnp.Net.Runtime.Tests result2.WriteData(0, 222222); mock2.Return.SetResult(result2); - Assert.IsTrue(answer2.WhenReturned.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer2.WhenReturned.WrappedTask.Wait(MediumNonDbgTimeout)); var outresult2 = answer2.WhenReturned.Result; Assert.AreEqual(ObjectKind.Struct, outresult2.Kind); Assert.AreEqual(222222, outresult2.ReadDataInt(0)); @@ -521,7 +522,7 @@ namespace Capnp.Net.Runtime.Tests mock.Return.SetResult(result); - Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer.WhenReturned.WrappedTask.Wait(MediumNonDbgTimeout)); Assert.IsFalse(ct.IsCancellationRequested); var args4 = DynamicSerializerState.CreateForRpc(); @@ -570,10 +571,10 @@ namespace Capnp.Net.Runtime.Tests ret5.WriteData(0, -4); call5.Result.Result.SetResult(ret5); - Assert.IsTrue(answer2.WhenReturned.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(answer3.WhenReturned.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(answer4.WhenReturned.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(answer5.WhenReturned.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer2.WhenReturned.WrappedTask.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer3.WhenReturned.WrappedTask.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer4.WhenReturned.WrappedTask.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(answer5.WhenReturned.WrappedTask.Wait(MediumNonDbgTimeout)); Assert.AreEqual(-1, answer2.WhenReturned.Result.ReadDataInt(0)); Assert.AreEqual(-2, answer3.WhenReturned.Result.ReadDataInt(0)); @@ -686,7 +687,7 @@ namespace Capnp.Net.Runtime.Tests mock.Return.SetResult(result); Assert.IsTrue(Assert.ThrowsExceptionAsync( - () => answer2.WhenReturned).Wait(MediumNonDbgTimeout)); + async () => await answer2.WhenReturned).Wait(MediumNonDbgTimeout)); } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index e016ad5..0014891 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -238,7 +238,7 @@ namespace Capnp.Net.Runtime.Tests { var fooTask2 = main2.Foo(123, null); Assert.IsTrue(fooTask2.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(fooTask2.C().GetCallSequence(1).Wait(MediumNonDbgTimeout)); + Assert.IsTrue(fooTask2.C().GetCallSequence(0).Wait(MediumNonDbgTimeout)); } } } diff --git a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs index d274d67..6ec007a 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs @@ -423,8 +423,8 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(456u, promise.Result.I); Assert.AreEqual("from TestTailCaller", promise.Result.T); - var dependentCall1 = c.GetCallSequence(0, default); - var dependentCall2 = c.GetCallSequence(0, default); + var dependentCall1 = c.GetCallSequence(1, default); + var dependentCall2 = c.GetCallSequence(2, default); AssertOutput(stdout, "foo"); Assert.IsTrue(dependentCall0.Wait(MediumNonDbgTimeout)); diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 13a93bb..dc94dd3 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -276,7 +276,7 @@ namespace Capnp.Net.Runtime.Tests public void RunTest(Action action) { (_server, _client) = SetupClientServerPair(_options); - Assert.IsTrue(SpinWait.SpinUntil(() => _server.ConnectionCount > 0, 2 * MediumNonDbgTimeout)); + Assert.IsTrue(SpinWait.SpinUntil(() => _server.ConnectionCount > 0, LargeNonDbgTimeout)); var conn = _server.Connections[0]; using (_server) diff --git a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs index 6c0de2f..5bb9d9c 100644 --- a/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/IPromisedAnswer.cs @@ -1,4 +1,5 @@ -using System; +using Capnp.Util; +using System; using System.Threading.Tasks; namespace Capnp.Rpc @@ -15,7 +16,7 @@ namespace Capnp.Rpc /// /// Task which will complete when the RPC returns, delivering its result struct. /// - Task WhenReturned { get; } + StrictlyOrderedAwaitTask WhenReturned { get; } /// /// Creates a low-level capability for promise pipelining. diff --git a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs index 1caf2b6..b8b3a52 100644 --- a/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs +++ b/Capnp.Net.Runtime/Rpc/Interception/CallContext.cs @@ -1,4 +1,5 @@ -using System; +using Capnp.Util; +using System; using System.Threading; using System.Threading.Tasks; @@ -18,16 +19,17 @@ namespace Capnp.Rpc.Interception readonly CancellationTokenSource _cancelFromAlice = new CancellationTokenSource(); public PromisedAnswer(CallContext callContext) - { + { _callContext = callContext; + WhenReturned = _futureResult.Task.EnforceAwaitOrder(); } - public Task WhenReturned => _futureResult.Task; + public StrictlyOrderedAwaitTask WhenReturned { get; } public CancellationToken CancelFromAlice => _cancelFromAlice.Token; public ConsumedCapability Access(MemberAccessPath access) { - return _callContext._censorCapability.Policy.Attach(new LocalAnswerCapability(_futureResult.Task, access)); + return _callContext._censorCapability.Policy.Attach(new LocalAnswerCapability(WhenReturned, access)); } public ConsumedCapability Access(MemberAccessPath _, Task task) diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswer.cs b/Capnp.Net.Runtime/Rpc/LocalAnswer.cs index 516b6a7..294412e 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswer.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswer.cs @@ -1,4 +1,5 @@ -using System; +using Capnp.Util; +using System; using System.Threading; using System.Threading.Tasks; @@ -11,7 +12,7 @@ namespace Capnp.Rpc public LocalAnswer(CancellationTokenSource cts, Task call) { _cts = cts ?? throw new ArgumentNullException(nameof(cts)); - WhenReturned = call ?? throw new ArgumentNullException(nameof(call)); + WhenReturned = call?.EnforceAwaitOrder() ?? throw new ArgumentNullException(nameof(call)); CleanupAfterReturn(); } @@ -23,7 +24,7 @@ namespace Capnp.Rpc finally { _cts.Dispose(); } } - public Task WhenReturned { get; } + public StrictlyOrderedAwaitTask WhenReturned { get; } public bool IsTailCall => false; diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs index be55b2c..17d9c0c 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs @@ -1,4 +1,5 @@ -using System; +using Capnp.Util; +using System; using System.Threading; using System.Threading.Tasks; @@ -7,7 +8,7 @@ namespace Capnp.Rpc class LocalAnswerCapability : RefCountingCapability, IResolvingCapability { - static async Task TransferOwnershipToDummyProxy(Task answer, MemberAccessPath access) + static async Task TransferOwnershipToDummyProxy(StrictlyOrderedAwaitTask answer, MemberAccessPath access) { var result = await answer; var cap = access.Eval(result); @@ -23,7 +24,7 @@ namespace Capnp.Rpc _whenResolvedProxy = proxyTask; } - public LocalAnswerCapability(Task answer, MemberAccessPath access): + public LocalAnswerCapability(StrictlyOrderedAwaitTask answer, MemberAccessPath access): this(TransferOwnershipToDummyProxy(answer, access)) { diff --git a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs index 97be61a..73e074c 100644 --- a/Capnp.Net.Runtime/Rpc/PendingQuestion.cs +++ b/Capnp.Net.Runtime/Rpc/PendingQuestion.cs @@ -1,4 +1,5 @@ -using System; +using Capnp.Util; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; @@ -53,6 +54,7 @@ namespace Capnp.Rpc } readonly TaskCompletionSource _tcs = new TaskCompletionSource(); + readonly StrictlyOrderedAwaitTask _whenReturned; readonly uint _questionId; ConsumedCapability? _target; SerializerState? _inParams; @@ -64,6 +66,8 @@ namespace Capnp.Rpc _questionId = id; _target = target; _inParams = inParams; + _whenReturned = _tcs.Task.EnforceAwaitOrder(); + StateFlags = inParams == null ? State.Sent : State.None; if (target != null) @@ -81,7 +85,7 @@ namespace Capnp.Rpc /// /// Eventually returns the server answer /// - public Task WhenReturned => _tcs.Task; + public StrictlyOrderedAwaitTask WhenReturned => _whenReturned; /// /// Whether this question represents a tail call diff --git a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs index ad8db50..74b5849 100644 --- a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs @@ -1,4 +1,5 @@ -using System; +using Capnp.Util; +using System; using System.Diagnostics; using System.Threading.Tasks; @@ -72,7 +73,7 @@ namespace Capnp.Rpc return null; } - async void TrackCall(Task call) + async void TrackCall(StrictlyOrderedAwaitTask call) { try { diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index 53a759d..9b0b248 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -1,4 +1,5 @@ -using System; +using Capnp.Util; +using System; using System.Threading.Tasks; namespace Capnp.Rpc @@ -38,7 +39,7 @@ namespace Capnp.Rpc { } - async void ReAllowFinishWhenDone(Task task) + async void ReAllowFinishWhenDone(StrictlyOrderedAwaitTask task) { try { diff --git a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs index a7c6602..fa0d36c 100644 --- a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs +++ b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace Capnp.Util { - internal class StrictlyOrderedAwaitTask: INotifyCompletion + public class StrictlyOrderedAwaitTask: INotifyCompletion { class Cover { } class Seal { } @@ -99,7 +99,7 @@ namespace Capnp.Util public Task WrappedTask => _awaitedTask; } - internal class StrictlyOrderedAwaitTask : StrictlyOrderedAwaitTask + public class StrictlyOrderedAwaitTask : StrictlyOrderedAwaitTask { public StrictlyOrderedAwaitTask(Task awaitedTask): base(awaitedTask) { @@ -115,7 +115,7 @@ namespace Capnp.Util } - internal static class StrictlyOrderedTaskExtensions + public static class StrictlyOrderedTaskExtensions { public static StrictlyOrderedAwaitTask EnforceAwaitOrder(this Task task) { From 4e0d86f4eb93fe77d4d64a85b73045541a4547f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Mon, 20 Apr 2020 12:46:32 +0200 Subject: [PATCH 59/76] appveyor fix --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 58e1811..2033be4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -55,7 +55,7 @@ artifacts: - path: capnpc-csharp\nupkg\*.nupkg name: capnpc-csharp type: NuGetPackage - - path: coverage\report\* + - path: coverage\report name: Coverage report type: zip test_script: From 8f74ad79c07eb26a77cb9983d4b737014004463a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Mon, 20 Apr 2020 21:22:12 +0200 Subject: [PATCH 60/76] testsuite now using full loopback IP address range to avoid conflicts with existing/stale TCP ports --- Capnp.Net.Runtime.Tests/TcpRpc.cs | 61 +++---- .../TcpRpcAdvancedStuff.cs | 51 ++++-- Capnp.Net.Runtime.Tests/TcpRpcInterop.cs | 171 ++++++++++-------- Capnp.Net.Runtime.Tests/TcpRpcStress.cs | 59 +++--- Capnp.Net.Runtime.Tests/Util/TcpManager.cs | 32 ++++ Capnp.Net.Runtime.Tests/Util/TestBase.cs | 51 ++---- 6 files changed, 222 insertions(+), 203 deletions(-) create mode 100644 Capnp.Net.Runtime.Tests/Util/TcpManager.cs diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index 2abdc4e..f419f33 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Threading.Tasks.Dataflow; using Capnp.Net.Runtime.Tests.GenImpls; using Capnproto_test.Capnp.Test; +using Capnp.Net.Runtime.Tests.Util; namespace Capnp.Net.Runtime.Tests { @@ -56,7 +57,8 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void ConnectNoServer() { - using (var client = new TcpRpcClient("localhost", TcpPort)) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var client = new TcpRpcClient(addr.ToString(), port)) { Assert.IsTrue(Assert.ThrowsExceptionAsync(() => client.WhenConnected).Wait(10000)); } @@ -692,35 +694,15 @@ namespace Capnp.Net.Runtime.Tests } } - static void RobustStartAccepting(TcpRpcServer server) - { - int retry = 0; - - do - { - try - { - server.StartAccepting(IPAddress.Any, TcpPort); - break; - } - catch (SocketException) - { - if (retry++ == 100) - throw; - - IncrementTcpPort(); - } - } while (true); - } - [TestMethod] public void Server1() - { + { var cbb = new BufferBlock(); var server = new TcpRpcServer(); server.Main = new TestInterfaceImpl2(); bool init = true; var tracer = new FrameTracing.RpcFrameTracer(Console.Out); + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); server.OnConnectionChanged += (s, a) => { var c = a.Connection; @@ -734,7 +716,7 @@ namespace Capnp.Net.Runtime.Tests Assert.IsFalse(c.IsWaitingForData); Assert.AreEqual(ConnectionState.Initializing, c.State); Assert.IsNotNull(c.RemotePort); - Assert.AreEqual(TcpPort, c.LocalPort); + Assert.AreEqual(port, c.LocalPort); Assert.AreEqual(0L, c.RecvCount); Assert.AreEqual(0L, c.SendCount); } @@ -750,14 +732,14 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => server.StopListening()); - RobustStartAccepting(server); + server.StartAccepting(addr, port); Assert.IsTrue(server.IsAlive); - Assert.ThrowsException(() => server.StartAccepting(IPAddress.Any, TcpPort)); + Assert.ThrowsException(() => server.StartAccepting(addr, port)); var server2 = new TcpRpcServer(); - Assert.ThrowsException(() => server2.StartAccepting(IPAddress.Any, TcpPort)); + Assert.ThrowsException(() => server2.StartAccepting(addr, port)); - var client1 = new TcpRpcClient("localhost", TcpPort); + var client1 = new TcpRpcClient(addr.ToString(), port); var c1 = cbb.Receive(TimeSpan.FromMilliseconds(MediumNonDbgTimeout)); Assert.IsNotNull(c1); Assert.AreEqual(1, server.ConnectionCount); @@ -768,7 +750,7 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(c1.RecvCount > 0); Assert.IsTrue(c1.SendCount > 0); - var client2 = new TcpRpcClient("localhost", TcpPort); + var client2 = new TcpRpcClient(addr.ToString(), port); var c2 = cbb.Receive(TimeSpan.FromMilliseconds(MediumNonDbgTimeout)); Assert.IsNotNull(c2); Assert.AreEqual(2, server.ConnectionCount); @@ -795,7 +777,7 @@ namespace Capnp.Net.Runtime.Tests for (int i = 0; i < 100; i++) { - server.StartAccepting(IPAddress.Any, TcpPort); + server.StartAccepting(addr, port); Assert.IsTrue(server.IsAlive); server.StopListening(); Assert.IsFalse(server.IsAlive); @@ -815,9 +797,10 @@ namespace Capnp.Net.Runtime.Tests server.Dispose(); }; - RobustStartAccepting(server); + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + server.StartAccepting(addr, port); - var client1 = new TcpRpcClient("localhost", TcpPort); + var client1 = new TcpRpcClient(addr.ToString(), port); Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout), "Did not connect"); Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout), $"Connection did not go down: {client1.State}"); @@ -835,9 +818,10 @@ namespace Capnp.Net.Runtime.Tests a.Connection.Close(); }; - RobustStartAccepting(server); + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + server.StartAccepting(addr, port); - var client1 = new TcpRpcClient("localhost", TcpPort); + var client1 = new TcpRpcClient(addr.ToString(), port); Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout)); Assert.IsTrue(SpinWait.SpinUntil(() => client1.State == ConnectionState.Down, MediumNonDbgTimeout)); } @@ -856,13 +840,14 @@ namespace Capnp.Net.Runtime.Tests Assert.ThrowsException(() => client.GetMain()); Assert.ThrowsException(() => client.AttachTracer(null)); Assert.ThrowsException(() => client.InjectMidlayer(null)); - RobustStartAccepting(server); - client.Connect("localhost", TcpPort); - Assert.ThrowsException(() => client.Connect("localhost", TcpPort)); + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + server.StartAccepting(addr, port); + client.Connect(addr.ToString(), port); + Assert.ThrowsException(() => client.Connect(addr.ToString(), port)); Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); Assert.ThrowsException(() => client.AttachTracer(new FrameTracing.RpcFrameTracer(Console.Out, false))); Assert.ThrowsException(() => client.InjectMidlayer(_ => _)); - Assert.AreEqual(TcpPort, client.RemotePort); + Assert.AreEqual(port, client.RemotePort); Assert.IsTrue(client.LocalPort != 0); Assert.AreEqual(0L, client.SendCount); Assert.AreEqual(0L, client.RecvCount); diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index 0014891..1e81bf4 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -1,4 +1,5 @@ using Capnp.Net.Runtime.Tests.GenImpls; +using Capnp.Net.Runtime.Tests.Util; using Capnp.Rpc; using Capnproto_test.Capnp.Test; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -16,7 +17,8 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void MultiConnect() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); var tcs = new TaskCompletionSource(); @@ -24,7 +26,7 @@ namespace Capnp.Net.Runtime.Tests for (int i = 1; i <= 10; i++) { - using (var client = SetupClient()) + using (var client = SetupClient(addr, port)) { //client.WhenConnected.Wait(); @@ -54,13 +56,14 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void TwoClients() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - using (var client1 = SetupClient()) - using (var client2 = SetupClient()) + using (var client1 = SetupClient(addr, port)) + using (var client2 = SetupClient(addr, port)) { //Assert.IsTrue(client1.WhenConnected.Wait(MediumNonDbgTimeout)); //Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout)); @@ -95,12 +98,13 @@ namespace Capnp.Net.Runtime.Tests { for (int i = 0; i < 100; i++) { - var server = SetupServer(); + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + var server = SetupServer(addr, port); var counters = new Counters(); var tcs = new TaskCompletionSource(); server.Main = new TestInterfaceImpl(counters, tcs); - using (var client = SetupClient()) + using (var client = SetupClient(addr, port)) { client.WhenConnected.Wait(); @@ -125,12 +129,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void InheritFromGenericInterface() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new B2Impl(); - using (var client = SetupClient()) + using (var client = SetupClient(addr, port)) { //client.WhenConnected.Wait(); @@ -148,11 +153,12 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void Issue25() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { server.Main = new Issue25BImpl(); - using (var client = SetupClient()) + using (var client = SetupClient(addr, port)) { //client.WhenConnected.Wait(); @@ -177,12 +183,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void ExportCapToThirdParty() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl3(); - using (var client = SetupClient()) + using (var client = SetupClient(addr, port)) { //Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); @@ -190,11 +197,13 @@ namespace Capnp.Net.Runtime.Tests { var held = main.GetHeld().Eager(); - using (var server2 = SetupServer()) + (addr, port) = TcpManager.Instance.GetLocalAddressAndPort(); + + using (var server2 = SetupServer(addr, port)) { server2.Main = new TestMoreStuffImpl2(); - using (var client2 = SetupClient()) + using (var client2 = SetupClient(addr, port)) { //Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout)); @@ -215,11 +224,12 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void ExportTailCallCapToThirdParty() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { server.Main = new TestTailCallerImpl2(); - using (var client = SetupClient()) + using (var client = SetupClient(addr, port)) { //Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); @@ -230,7 +240,7 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(fooTask.Wait(MediumNonDbgTimeout)); using (var c = fooTask.Result.C) - using (var client2 = SetupClient()) + using (var client2 = SetupClient(addr, port)) { //Assert.IsTrue(client2.WhenConnected.Wait(MediumNonDbgTimeout)); @@ -249,11 +259,12 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void SalamiTactics() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { server.Main = new TestMoreStuffImpl3(); - using (var client = SetupClient()) + using (var client = SetupClient(addr, port)) { //client.WhenConnected.Wait(); diff --git a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs index 6ec007a..de99fa4 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs @@ -1,5 +1,6 @@ using Capnp.FrameTracing; using Capnp.Net.Runtime.Tests.GenImpls; +using Capnp.Net.Runtime.Tests.Util; using Capnp.Rpc; using Capnproto_test.Capnp.Test; using Microsoft.Extensions.Logging; @@ -9,6 +10,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; +using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -37,7 +39,7 @@ namespace Capnp.Net.Runtime.Tests Process _currentProcess; - bool TryLaunchCompatTestProcess(string whichTest, Action test) + bool TryLaunchCompatTestProcess(IPAddress addr, int port, string whichTest, Action test) { string myPath = Path.GetDirectoryName(typeof(TcpRpcInterop).Assembly.Location); string config; @@ -48,7 +50,7 @@ namespace Capnp.Net.Runtime.Tests #endif string path = Path.Combine(myPath, $@"..\..\..\..\{config}\CapnpCompatTest.exe"); path = Path.GetFullPath(path); - string arguments = $"{whichTest} 127.0.0.1:{TcpPort}"; + string arguments = $"{whichTest} {addr}:{port}"; var startInfo = new ProcessStartInfo(path, arguments) { UseShellExecute = false, @@ -96,15 +98,13 @@ namespace Capnp.Net.Runtime.Tests } } - void LaunchCompatTestProcess(string whichTest, Action test) + void LaunchCompatTestProcess(string whichTest, IPAddress addr, int port, Action test) { for (int retry = 0; retry < 5; retry++) { - if (TryLaunchCompatTestProcess(whichTest, test)) + if (TryLaunchCompatTestProcess(addr, port, whichTest, test)) return; - if (whichTest.StartsWith("server:")) - PrepareNextTest(); } Assert.Fail("Problem after launching test process"); @@ -122,18 +122,13 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(expected, line.Result); } - [TestInitialize] - public void PrepareNextTest() - { - IncrementTcpPort(); - } - [TestMethod] public void BasicClient() { - LaunchCompatTestProcess("server:Interface", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:Interface", addr, port, stdout => { - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //client.WhenConnected.Wait(); @@ -162,12 +157,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void BasicServer() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestInterfaceImpl(counters); - LaunchCompatTestProcess("client:Basic", stdout => + LaunchCompatTestProcess("client:Basic", addr, port, stdout => { AssertOutput(stdout, "Basic test start"); AssertOutput(stdout, "Basic test end"); @@ -179,11 +175,12 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void PipelineClient() { - LaunchCompatTestProcess("server:Pipeline", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:Pipeline", addr, port, stdout => { stdout.ReadToEndAsync().ContinueWith(t => Console.WriteLine(t.Result)); - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //client.WhenConnected.Wait(); @@ -216,12 +213,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void PipelineServer() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestPipelineImpl(counters); - LaunchCompatTestProcess("client:Pipelining", stdout => + LaunchCompatTestProcess("client:Pipelining", addr, port, stdout => { AssertOutput(stdout, "Pipelining test start"); AssertOutput(stdout, "foo 123 1"); @@ -235,9 +233,10 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void ReleaseClient() { - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //client.WhenConnected.Wait(); @@ -268,12 +267,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void ReleaseServer() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - LaunchCompatTestProcess("client:Release", stdout => + LaunchCompatTestProcess("client:Release", addr, port, stdout => { AssertOutput(stdout, "Release test start"); AssertOutput(stdout, "sync"); @@ -301,9 +301,10 @@ namespace Capnp.Net.Runtime.Tests // later on verify that the handle count is 0. int iterationCount = 5000; - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //client.WhenConnected.Wait(); @@ -380,12 +381,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void ReleaseOnCancelServer() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - LaunchCompatTestProcess("client:ReleaseOnCancel", stdout => + LaunchCompatTestProcess("client:ReleaseOnCancel", addr, port, stdout => { AssertOutput(stdout, "ReleaseOnCancel test start"); AssertOutput(stdout, "ReleaseOnCancel test end"); @@ -398,14 +400,15 @@ namespace Capnp.Net.Runtime.Tests [TestCategory("Coverage")] public void TestTailCallClient() { - LaunchCompatTestProcess("server:TailCaller", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:TailCaller", addr, port, stdout => { using (var client = new TcpRpcClient()) { var tracer = new RpcFrameTracer(Console.Out); client.AttachTracer(tracer); - client.Connect("localhost", TcpPort); + client.Connect(addr.ToString(), port); //client.WhenConnected.Wait(); @@ -441,8 +444,8 @@ namespace Capnp.Net.Runtime.Tests // For details on why this test is ignored, see https://github.com/capnproto/capnproto/issues/876 public void TestTailCallServer() { - - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var tracer = new RpcFrameTracer(Console.Out); @@ -455,7 +458,7 @@ namespace Capnp.Net.Runtime.Tests var counters = new Counters(); server.Main = new TestTailCallerImpl(counters); - LaunchCompatTestProcess("client:TailCall", stdout => + LaunchCompatTestProcess("client:TailCall", addr, port, stdout => { AssertOutput(stdout, "TailCall test start"); AssertOutput(stdout, "foo"); @@ -469,11 +472,12 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void CancelationServer() { - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { stdout.ReadToEndAsync().ContinueWith(t => Console.WriteLine(t.Result)); - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //client.WhenConnected.Wait(); @@ -499,12 +503,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void CancelationClient() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - LaunchCompatTestProcess("client:Cancelation", stdout => + LaunchCompatTestProcess("client:Cancelation", addr, port, stdout => { AssertOutput(stdout, "Cancelation test start"); AssertOutput(stdout, "~"); @@ -516,9 +521,10 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void PromiseResolveServer() { - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //client.WhenConnected.Wait(); @@ -560,12 +566,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void PromiseResolveClient() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - LaunchCompatTestProcess("client:PromiseResolve", stdout => + LaunchCompatTestProcess("client:PromiseResolve", addr, port, stdout => { AssertOutput(stdout, "PromiseResolve test start"); AssertOutput(stdout, "foo 123 1"); @@ -583,11 +590,12 @@ namespace Capnp.Net.Runtime.Tests var destructionPromise = new TaskCompletionSource(); var destructionTask = destructionPromise.Task; - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { stdout.ReadToEndAsync().ContinueWith(t => Console.WriteLine(t.Result)); - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //client.WhenConnected.Wait(); @@ -658,12 +666,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void RetainAndReleaseClient() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - LaunchCompatTestProcess("client:RetainAndRelease", stdout => + LaunchCompatTestProcess("client:RetainAndRelease", addr, port, stdout => { AssertOutput(stdout, "RetainAndRelease test start"); AssertOutput(stdout, "foo 123 1"); @@ -678,9 +687,10 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void CancelServer() { - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //client.WhenConnected.Wait(); @@ -719,12 +729,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void CancelClient() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - LaunchCompatTestProcess("client:Cancel", stdout => + LaunchCompatTestProcess("client:Cancel", addr, port, stdout => { AssertOutput(stdout, "Cancel test start"); AssertOutput(stdout, "~"); @@ -736,9 +747,10 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void SendTwiceServer() { - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //client.WhenConnected.Wait(); @@ -780,12 +792,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void SendTwiceClient() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - LaunchCompatTestProcess("client:SendTwice", stdout => + LaunchCompatTestProcess("client:SendTwice", addr, port, stdout => { AssertOutput(stdout, "SendTwice test start"); AssertOutput(stdout, "foo 123 1"); @@ -800,9 +813,10 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void EmbargoServer() { - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout), "client connect"); @@ -864,12 +878,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void EmbargoServer2() { - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { int retry = 0; label: - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout), "client connect"); @@ -947,12 +962,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void EmbargoClient() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - LaunchCompatTestProcess("client:Embargo", stdout => + LaunchCompatTestProcess("client:Embargo", addr, port, stdout => { AssertOutput(stdout, "Embargo test start"); AssertOutput(stdout, "Embargo test end"); @@ -960,9 +976,9 @@ namespace Capnp.Net.Runtime.Tests } } - public void EmbargoErrorImpl(StreamReader stdout) + public void EmbargoErrorImpl(IPAddress addr, int port, StreamReader stdout) { - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //Assert.IsTrue(client.WhenConnected.Wait(MediumNonDbgTimeout)); @@ -1017,17 +1033,19 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void EmbargoErrorServer() { - LaunchCompatTestProcess("server:MoreStuff", EmbargoErrorImpl); + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, r => EmbargoErrorImpl(addr, port, r)); } [TestMethod, Timeout(240000)] public void RepeatedEmbargoError() { - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { for (int i = 0; i < 20; i++) { - EmbargoErrorImpl(stdout); + EmbargoErrorImpl(addr, port, stdout); } }); } @@ -1035,12 +1053,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void EmbargoErrorClient() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - LaunchCompatTestProcess("client:EmbargoError", stdout => + LaunchCompatTestProcess("client:EmbargoError", addr, port, stdout => { AssertOutput(stdout, "EmbargoError test start"); AssertOutput(stdout, "EmbargoError test end"); @@ -1051,12 +1070,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void EmbargoNullServer() { - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { int retry = 0; label: - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //client.WhenConnected.Wait(); @@ -1111,12 +1131,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void EmbargoNullClient() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - LaunchCompatTestProcess("client:EmbargoNull", stdout => + LaunchCompatTestProcess("client:EmbargoNull", addr, port, stdout => { AssertOutput(stdout, "EmbargoNull test start"); AssertOutput(stdout, "EmbargoNull test end"); @@ -1127,9 +1148,10 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void CallBrokenPromiseServer() { - LaunchCompatTestProcess("server:MoreStuff", stdout => + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + LaunchCompatTestProcess("server:MoreStuff", addr, port, stdout => { - using (var client = new TcpRpcClient("localhost", TcpPort)) + using (var client = new TcpRpcClient(addr.ToString(), port)) { //client.WhenConnected.Wait(); @@ -1164,12 +1186,13 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void CallBrokenPromiseClient() { - using (var server = SetupServer()) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + using (var server = SetupServer(addr, port)) { var counters = new Counters(); server.Main = new TestMoreStuffImpl(counters); - LaunchCompatTestProcess("client:CallBrokenPromise", stdout => + LaunchCompatTestProcess("client:CallBrokenPromise", addr, port, stdout => { AssertOutput(stdout, "CallBrokenPromise test start"); AssertOutput(stdout, "CallBrokenPromise test end"); diff --git a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs index b5de959..b24095c 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs @@ -1,4 +1,5 @@ using Capnp.Net.Runtime.Tests.GenImpls; +using Capnp.Net.Runtime.Tests.Util; using Capnp.Rpc; using Capnproto_test.Capnp.Test; using Microsoft.Extensions.Logging; @@ -20,7 +21,6 @@ namespace Capnp.Net.Runtime.Tests for (int i = 0; i < count; i++) { Logger.LogTrace("Repetition {0}", i); - IncrementTcpPort(); action(); } } @@ -109,45 +109,36 @@ namespace Capnp.Net.Runtime.Tests [TestMethod] public void ScatteredTransfer() { - for (int retry = 0; retry < 10; retry++) + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + + using (var server = new TcpRpcServer(addr, port)) + using (var client = new TcpRpcClient()) { - try + server.InjectMidlayer(s => new ScatteringStream(s, 7)); + client.InjectMidlayer(s => new ScatteringStream(s, 10)); + client.Connect(addr.ToString(), port); + //client.WhenConnected.Wait(); + + var counters = new Counters(); + server.Main = new TestInterfaceImpl(counters); + using (var main = client.GetMain()) { - using (var server = new TcpRpcServer(IPAddress.Any, TcpPort)) - using (var client = new TcpRpcClient()) + for (int i = 0; i < 100; i++) { - server.InjectMidlayer(s => new ScatteringStream(s, 7)); - client.InjectMidlayer(s => new ScatteringStream(s, 10)); - client.Connect("localhost", TcpPort); - //client.WhenConnected.Wait(); + var request1 = main.Foo(123, true, default); + var request3 = Assert.ThrowsExceptionAsync(() => main.Bar(default)); + var s = new TestAllTypes(); + Common.InitTestMessage(s); + var request2 = main.Baz(s, default); - var counters = new Counters(); - server.Main = new TestInterfaceImpl(counters); - using (var main = client.GetMain()) - { - for (int i = 0; i < 100; i++) - { - var request1 = main.Foo(123, true, default); - var request3 = Assert.ThrowsExceptionAsync(() => main.Bar(default)); - var s = new TestAllTypes(); - Common.InitTestMessage(s); - var request2 = main.Baz(s, default); + Assert.IsTrue(request1.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(request2.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(request3.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(request1.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(request2.Wait(MediumNonDbgTimeout)); - Assert.IsTrue(request3.Wait(MediumNonDbgTimeout)); - - Assert.AreEqual("foo", request1.Result); - Assert.AreEqual(2, counters.CallCount); - counters.CallCount = 0; - } - } + Assert.AreEqual("foo", request1.Result); + Assert.AreEqual(2, counters.CallCount); + counters.CallCount = 0; } - return; - } - catch (SocketException) - { - IncrementTcpPort(); } } } diff --git a/Capnp.Net.Runtime.Tests/Util/TcpManager.cs b/Capnp.Net.Runtime.Tests/Util/TcpManager.cs new file mode 100644 index 0000000..102d352 --- /dev/null +++ b/Capnp.Net.Runtime.Tests/Util/TcpManager.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace Capnp.Net.Runtime.Tests.Util +{ + class TcpManager + { + public static readonly TcpManager Instance = new TcpManager(); + + readonly byte[] _nextAddress; + int _nextPort = 50005; + + public TcpManager() + { + _nextAddress = new byte[] { 127, 0, 0, 1 }; + } + + public (IPAddress, int) GetLocalAddressAndPort() + { + if (++_nextAddress[2] == 0 && + ++_nextAddress[1] == 0 && + ++_nextAddress[0] == 0) + { + _nextAddress[0] = 2; + } + + return (new IPAddress(_nextAddress), _nextPort); + } + } +} diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index dc94dd3..443e660 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -1,4 +1,5 @@ -using Capnp.Rpc; +using Capnp.Net.Runtime.Tests.Util; +using Capnp.Rpc; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; @@ -344,14 +345,13 @@ namespace Capnp.Net.Runtime.Tests } } - public static int TcpPort = 49152; public static int MediumNonDbgTimeout => Debugger.IsAttached ? Timeout.Infinite : 5000; public static int LargeNonDbgTimeout => Debugger.IsAttached ? Timeout.Infinite : 20000; public static int ShortTimeout => 500; protected ILogger Logger { get; set; } - protected static TcpRpcClient SetupClient(TcpRpcTestOptions options = TcpRpcTestOptions.None) + protected static TcpRpcClient SetupClient(IPAddress addr, int port, TcpRpcTestOptions options = TcpRpcTestOptions.None) { var client = new TcpRpcClient(); client.AddBuffering(); @@ -360,7 +360,7 @@ namespace Capnp.Net.Runtime.Tests if (options.HasFlag(TcpRpcTestOptions.ClientFluctStream)) client.InjectMidlayer(s => new FluctStream(s)); if (!options.HasFlag(TcpRpcTestOptions.ClientNoConnect)) - client.Connect("localhost", TcpPort); + client.Connect(addr.ToString(), port); return client; } @@ -373,36 +373,21 @@ namespace Capnp.Net.Runtime.Tests ClientNoConnect = 4 } - protected static TcpRpcServer SetupServer() + protected static TcpRpcServer SetupServer(IPAddress addr, int port) { - int attempt = 0; - - while (true) - { - try - { - var server = new TcpRpcServer(IPAddress.Any, TcpPort); - server.AddBuffering(); - return server; - } - catch (SocketException) - { - // If the TCP listening port is occupied by some other process, retry with a different one - // TIME_WAIT is 4min: http://blog.davidvassallo.me/2010/07/13/time_wait-and-port-reuse/ - if (attempt == 2400) - throw; - } - - IncrementTcpPort(); - ++attempt; - Thread.Sleep(100); - } + var server = new TcpRpcServer(); + server.AddBuffering(); + server.StartAccepting(addr, port); + return server; } protected static (TcpRpcServer, TcpRpcClient) SetupClientServerPair(TcpRpcTestOptions options = TcpRpcTestOptions.None) { - var server = SetupServer(); - var client = SetupClient(options); + (var addr, int port) = TcpManager.Instance.GetLocalAddressAndPort(); + + var server = SetupServer(addr, port); + var client = SetupClient(addr, port, options); + return (server, client); } @@ -413,14 +398,6 @@ namespace Capnp.Net.Runtime.Tests return (CapabilityReflection.CreateProxy(pair.Endpoint2.QueryMain()) as T); } - public static void IncrementTcpPort() - { - if (++TcpPort > 49200) - { - TcpPort = 49152; - } - } - protected static DtbdctTestbed NewDtbdctTestbed() => new DtbdctTestbed(); protected static LocalhostTcpTestbed NewLocalhostTcpTestbed(TcpRpcTestOptions options = TcpRpcTestOptions.None) => new LocalhostTcpTestbed(options); From 16f95e8f8ff4392d855a8319848ab76a701e40eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Mon, 20 Apr 2020 21:36:06 +0200 Subject: [PATCH 61/76] added missing documentation --- .../Util/StrictlyOrderedAwaitTask.cs | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs index fa0d36c..035fea8 100644 --- a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs +++ b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs @@ -7,6 +7,11 @@ using System.Threading.Tasks; namespace Capnp.Util { + /// + /// A task-like object which enforces that all await operations from the same thread leave in the exact order they were issued. + /// Note that an ordinary .NET Task does not fulfill this requirement if completed by a thread which is different from the + /// awaiting thread. + /// public class StrictlyOrderedAwaitTask: INotifyCompletion { class Cover { } @@ -18,12 +23,20 @@ namespace Capnp.Util readonly Task _awaitedTask; object? _state; + /// + /// Constructs an instance + /// + /// Task on which the order shall be enforced public StrictlyOrderedAwaitTask(Task awaitedTask) { _awaitedTask = awaitedTask; _state = s_cover; } + /// + /// await pattern implementation + /// + /// An object suitable for the await pattern public StrictlyOrderedAwaitTask GetAwaiter() { return this; @@ -55,6 +68,9 @@ namespace Capnp.Util } } + /// + /// Part of await pattern implementation. Do not use directly. + /// public void OnCompleted(Action continuation) { bool first = false; @@ -92,36 +108,82 @@ namespace Capnp.Util } } + /// + /// Whether the underlying task did complete and it is safe to skip continuation registration. + /// public bool IsCompleted => _awaitedTask.IsCompleted && _state == s_seal; + /// + /// Part of await pattern implementation. Do not use directly. + /// public void GetResult() => _awaitedTask.GetAwaiter().GetResult(); + /// + /// Task on which the order shall be enforced. + /// public Task WrappedTask => _awaitedTask; } + /// + /// A task-like object which enforces that all await operations from the same thread leave in the exact order they were issued. + /// Note that an ordinary .NET Task does not fulfill this requirement if completed by a thread which is different from the + /// awaiting thread. + /// public class StrictlyOrderedAwaitTask : StrictlyOrderedAwaitTask { + + /// + /// Constructs an instance + /// + /// Task on which the order shall be enforced public StrictlyOrderedAwaitTask(Task awaitedTask): base(awaitedTask) { } + /// + /// Task on which the order shall be enforced. + /// public new Task WrappedTask => (Task)base.WrappedTask; + + /// + /// await pattern implementation + /// + /// An object suitable for the await pattern public new StrictlyOrderedAwaitTask GetAwaiter() => this; + /// + /// Part of await pattern implementation. Do not use directly. + /// public new T GetResult() => WrappedTask.GetAwaiter().GetResult(); + /// + /// Redirects to the wrapped Task's result. + /// public T Result => WrappedTask.Result; } - + /// + /// Extension methods to simplify the use of + /// public static class StrictlyOrderedTaskExtensions { + /// + /// Converts the task to a task-like object which enforces that all await operations from the same thread leave in the exact order they were issued. + /// + /// The type of the result produced by the Task + /// Task to wrap + /// awaitable object public static StrictlyOrderedAwaitTask EnforceAwaitOrder(this Task task) { return new StrictlyOrderedAwaitTask(task); } + /// + /// Converts the task to a task-like object which enforces that all await operations from the same thread leave in the exact order they were issued. + /// + /// Task to wrap + /// awaitable object public static StrictlyOrderedAwaitTask EnforceAwaitOrder(this Task task) { return new StrictlyOrderedAwaitTask(task); From 7467c0f2368ec99e3a4e15dd5c65f8cf34764ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 21 Apr 2020 07:20:25 +0200 Subject: [PATCH 62/76] perf. tweak --- Benchmarking/Benchmark/Benchmark.csproj | 2 +- Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj | 2 +- Benchmarking/EchoServiceGrpc/EchoServiceGrpc.csproj | 1 + Benchmarking/NuGet.Config | 1 + Benchmarking/nuget.config | 1 + 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Benchmarking/Benchmark/Benchmark.csproj b/Benchmarking/Benchmark/Benchmark.csproj index 051d009..389c446 100644 --- a/Benchmarking/Benchmark/Benchmark.csproj +++ b/Benchmarking/Benchmark/Benchmark.csproj @@ -7,7 +7,7 @@ - + diff --git a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj index 2ef80ba..a35a473 100644 --- a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj +++ b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj @@ -6,7 +6,7 @@ - + diff --git a/Benchmarking/EchoServiceGrpc/EchoServiceGrpc.csproj b/Benchmarking/EchoServiceGrpc/EchoServiceGrpc.csproj index 861d83c..28b512c 100644 --- a/Benchmarking/EchoServiceGrpc/EchoServiceGrpc.csproj +++ b/Benchmarking/EchoServiceGrpc/EchoServiceGrpc.csproj @@ -2,6 +2,7 @@ netcoreapp3.1 + EchoService.Program diff --git a/Benchmarking/NuGet.Config b/Benchmarking/NuGet.Config index 3f0e003..3bb8cd5 100644 --- a/Benchmarking/NuGet.Config +++ b/Benchmarking/NuGet.Config @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/Benchmarking/nuget.config b/Benchmarking/nuget.config index 3f0e003..3bb8cd5 100644 --- a/Benchmarking/nuget.config +++ b/Benchmarking/nuget.config @@ -2,5 +2,6 @@ + \ No newline at end of file From 218ad9252590a3aaf5da5132c8c8c96c89d0006d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 21 Apr 2020 07:20:34 +0200 Subject: [PATCH 63/76] perf. tweak --- Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs index 035fea8..7567bf3 100644 --- a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs +++ b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs @@ -111,7 +111,7 @@ namespace Capnp.Util /// /// Whether the underlying task did complete and it is safe to skip continuation registration. /// - public bool IsCompleted => _awaitedTask.IsCompleted && _state == s_seal; + public bool IsCompleted => _awaitedTask.IsCompleted && (_state == s_cover || _state == s_seal); /// /// Part of await pattern implementation. Do not use directly. From debe76be897b94eb90ddd853c6b3c5146ea4ac98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 21 Apr 2020 07:49:37 +0200 Subject: [PATCH 64/76] SourceLink --- Benchmarking/Benchmark/Benchmark.csproj | 2 +- Benchmarking/CapnpBench.sln | 12 +++-- Benchmarking/CapnpProfile/CapnpProfile.csproj | 4 +- .../EchoServiceCapnp/EchoServiceCapnp.csproj | 2 +- .../EchoServiceGrpc2/EchoServiceGrpc.csproj | 15 +++++++ Benchmarking/EchoServiceGrpc2/Program.cs | 27 ++++++++++++ .../Services/GrpcEchoService.cs | 26 +++++++++++ Benchmarking/EchoServiceGrpc2/Startup.cs | 44 +++++++++++++++++++ .../appsettings.Development.json | 10 +++++ .../EchoServiceGrpc2/appsettings.json | 15 +++++++ Capnp.Net.Runtime/Capnp.Net.Runtime.csproj | 8 +++- 11 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 Benchmarking/EchoServiceGrpc2/EchoServiceGrpc.csproj create mode 100644 Benchmarking/EchoServiceGrpc2/Program.cs create mode 100644 Benchmarking/EchoServiceGrpc2/Services/GrpcEchoService.cs create mode 100644 Benchmarking/EchoServiceGrpc2/Startup.cs create mode 100644 Benchmarking/EchoServiceGrpc2/appsettings.Development.json create mode 100644 Benchmarking/EchoServiceGrpc2/appsettings.json diff --git a/Benchmarking/Benchmark/Benchmark.csproj b/Benchmarking/Benchmark/Benchmark.csproj index 389c446..e40a359 100644 --- a/Benchmarking/Benchmark/Benchmark.csproj +++ b/Benchmarking/Benchmark/Benchmark.csproj @@ -7,7 +7,7 @@ - + diff --git a/Benchmarking/CapnpBench.sln b/Benchmarking/CapnpBench.sln index 061559d..5d814fc 100644 --- a/Benchmarking/CapnpBench.sln +++ b/Benchmarking/CapnpBench.sln @@ -3,11 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29728.190 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EchoServiceGrpc", "EchoServiceGrpc\EchoServiceGrpc.csproj", "{D59C7B71-3887-426B-A636-2DBDA0549817}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EchoServiceGrpc", "EchoServiceGrpc\EchoServiceGrpc.csproj", "{D59C7B71-3887-426B-A636-2DBDA0549817}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmark", "Benchmark\Benchmark.csproj", "{7F7580CA-CCF0-4650-87BF-502D51A8F435}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmark", "Benchmark\Benchmark.csproj", "{7F7580CA-CCF0-4650-87BF-502D51A8F435}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EchoServiceCapnp", "EchoServiceCapnp\EchoServiceCapnp.csproj", "{309A4A26-F29E-4F49-AB49-76BAE0FD7D62}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EchoServiceCapnp", "EchoServiceCapnp\EchoServiceCapnp.csproj", "{309A4A26-F29E-4F49-AB49-76BAE0FD7D62}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EchoServiceGrpc2", "EchoServiceGrpc2\EchoServiceGrpc2.csproj", "{C9CEE2AD-AC6F-4CBD-A83D-2784832C1E37}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -27,6 +29,10 @@ Global {309A4A26-F29E-4F49-AB49-76BAE0FD7D62}.Debug|Any CPU.Build.0 = Debug|Any CPU {309A4A26-F29E-4F49-AB49-76BAE0FD7D62}.Release|Any CPU.ActiveCfg = Release|Any CPU {309A4A26-F29E-4F49-AB49-76BAE0FD7D62}.Release|Any CPU.Build.0 = Release|Any CPU + {C9CEE2AD-AC6F-4CBD-A83D-2784832C1E37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9CEE2AD-AC6F-4CBD-A83D-2784832C1E37}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9CEE2AD-AC6F-4CBD-A83D-2784832C1E37}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9CEE2AD-AC6F-4CBD-A83D-2784832C1E37}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Benchmarking/CapnpProfile/CapnpProfile.csproj b/Benchmarking/CapnpProfile/CapnpProfile.csproj index 953f368..5db3e9c 100644 --- a/Benchmarking/CapnpProfile/CapnpProfile.csproj +++ b/Benchmarking/CapnpProfile/CapnpProfile.csproj @@ -12,8 +12,8 @@ - - + + diff --git a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj index a35a473..99eff10 100644 --- a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj +++ b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj @@ -6,7 +6,7 @@ - + diff --git a/Benchmarking/EchoServiceGrpc2/EchoServiceGrpc.csproj b/Benchmarking/EchoServiceGrpc2/EchoServiceGrpc.csproj new file mode 100644 index 0000000..3d293a8 --- /dev/null +++ b/Benchmarking/EchoServiceGrpc2/EchoServiceGrpc.csproj @@ -0,0 +1,15 @@ + + + + netcoreapp3.1 + + + + + + + + + + + diff --git a/Benchmarking/EchoServiceGrpc2/Program.cs b/Benchmarking/EchoServiceGrpc2/Program.cs new file mode 100644 index 0000000..a3d05d6 --- /dev/null +++ b/Benchmarking/EchoServiceGrpc2/Program.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace EchoServiceGrpc2 +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + // Additional configuration is required to successfully run gRPC on macOS. + // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/Benchmarking/EchoServiceGrpc2/Services/GrpcEchoService.cs b/Benchmarking/EchoServiceGrpc2/Services/GrpcEchoService.cs new file mode 100644 index 0000000..71a7ef9 --- /dev/null +++ b/Benchmarking/EchoServiceGrpc2/Services/GrpcEchoService.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Grpc.Core; +using Microsoft.Extensions.Logging; + +namespace EchoService +{ + public class GrpcEchoService : Echoer.EchoerBase + { + private readonly ILogger _logger; + public GrpcEchoService(ILogger logger) + { + _logger = logger; + } + + public override Task Echo(EchoRequest request, ServerCallContext context) + { + return Task.FromResult(new EchoReply + { + Payload = request.Payload + }); + } + } +} diff --git a/Benchmarking/EchoServiceGrpc2/Startup.cs b/Benchmarking/EchoServiceGrpc2/Startup.cs new file mode 100644 index 0000000..3679177 --- /dev/null +++ b/Benchmarking/EchoServiceGrpc2/Startup.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using EchoService; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace EchoServiceGrpc2 +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + services.AddGrpc(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapGrpcService(); + + endpoints.MapGet("/", async context => + { + await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); + }); + }); + } + } +} diff --git a/Benchmarking/EchoServiceGrpc2/appsettings.Development.json b/Benchmarking/EchoServiceGrpc2/appsettings.Development.json new file mode 100644 index 0000000..fe20c40 --- /dev/null +++ b/Benchmarking/EchoServiceGrpc2/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Grpc": "Information", + "Microsoft": "Information" + } + } +} diff --git a/Benchmarking/EchoServiceGrpc2/appsettings.json b/Benchmarking/EchoServiceGrpc2/appsettings.json new file mode 100644 index 0000000..3110458 --- /dev/null +++ b/Benchmarking/EchoServiceGrpc2/appsettings.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Warning", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Warning" + } + }, + "AllowedHosts": "*", + "Kestrel": { + "EndpointDefaults": { + "Protocols": "Http2" + } + } +} diff --git a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj index b7675b9..4773820 100644 --- a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj +++ b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj @@ -22,8 +22,12 @@ capnp "Cap'n Proto" RPC serialization cerealization Debug;Release true + true + true + true + snupkg - + TRACE;DEBUG @@ -39,6 +43,6 @@ + - From 65e87e5aa97ffb05b484685b8274f8c6ae1870c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 21 Apr 2020 18:54:16 +0200 Subject: [PATCH 65/76] improved test design added perf. profiling for StrictlyOrderedAwaitTask --- Benchmarking/CapnpProfile/CapnpProfile.csproj | 4 +- .../Capnp.Net.Runtime.Tests.csproj | 4 + Capnp.Net.Runtime.Tests/TcpRpcStress.cs | 7 -- Capnp.Net.Runtime.Tests/Util/TestBase.cs | 39 ++++++--- Capnp.Net.Runtime/Capnp.Net.Runtime.csproj | 4 +- .../Util/StrictlyOrderedAwaitTask.cs | 80 ++++++++++++++++++- 6 files changed, 112 insertions(+), 26 deletions(-) diff --git a/Benchmarking/CapnpProfile/CapnpProfile.csproj b/Benchmarking/CapnpProfile/CapnpProfile.csproj index 5db3e9c..f3757eb 100644 --- a/Benchmarking/CapnpProfile/CapnpProfile.csproj +++ b/Benchmarking/CapnpProfile/CapnpProfile.csproj @@ -12,8 +12,8 @@ - - + + diff --git a/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.csproj b/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.csproj index 0b26467..0057a55 100644 --- a/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.csproj +++ b/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.csproj @@ -18,6 +18,10 @@ DEBUG;TRACE + + TRACE;SOTASK_PERF + + diff --git a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs index b24095c..7424277 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs @@ -53,7 +53,6 @@ namespace Capnp.Net.Runtime.Tests public void Cancel() { var t = new TcpRpcPorted(); - t.InitConsoleLogging(); Repeat(1000, t.Cancel); } @@ -61,7 +60,6 @@ namespace Capnp.Net.Runtime.Tests public void Embargo() { var t = new TcpRpcPorted(); - t.InitConsoleLogging(); Repeat(100, () => NewLocalhostTcpTestbed(TcpRpcTestOptions.ClientTracer | TcpRpcTestOptions.ClientFluctStream) @@ -72,7 +70,6 @@ namespace Capnp.Net.Runtime.Tests public void EmbargoServer() { var t2 = new TcpRpcInterop(); - t2.InitConsoleLogging(); Repeat(20, t2.EmbargoServer); } @@ -82,11 +79,9 @@ namespace Capnp.Net.Runtime.Tests // Some code paths are really rare during this test, therefore increased repetition count. var t = new TcpRpcPorted(); - t.InitConsoleLogging(); Repeat(1000, t.EmbargoNull); var t2 = new TcpRpcInterop(); - t2.InitConsoleLogging(); Repeat(100, t2.EmbargoNullServer); } @@ -94,7 +89,6 @@ namespace Capnp.Net.Runtime.Tests public void RetainAndRelease() { var t = new TcpRpcPorted(); - t.InitConsoleLogging(); Repeat(100, t.RetainAndRelease); } @@ -102,7 +96,6 @@ namespace Capnp.Net.Runtime.Tests public void PipelineAfterReturn() { var t = new TcpRpc(); - t.InitConsoleLogging(); Repeat(100, t.PipelineAfterReturn); } diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index 443e660..bad16c0 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -1,5 +1,6 @@ using Capnp.Net.Runtime.Tests.Util; using Capnp.Rpc; +using Capnp.Util; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; @@ -351,6 +352,32 @@ namespace Capnp.Net.Runtime.Tests protected ILogger Logger { get; set; } + protected TestBase() + { + Logging.LoggerFactory?.Dispose(); +#pragma warning disable CS0618 + Logging.LoggerFactory = new LoggerFactory().AddConsole((msg, level) => true); +#pragma warning restore CS0618 + Logger = Logging.CreateLogger(); + if (Thread.CurrentThread.Name == null) + Thread.CurrentThread.Name = $"Test Thread {Thread.CurrentThread.ManagedThreadId}"; + +#if SOTASK_PERF + StrictlyOrderedTaskExtensions.Stats.Reset(); +#endif + } + + [TestCleanup] + public void TestCleanup() + { +#if SOTASK_PERF + Console.WriteLine($"StrictlyOrderedTask performance statistics:"); + Console.WriteLine($"AwaitInternal: max. {StrictlyOrderedTaskExtensions.Stats.AwaitInternalMaxOuterIterations} outer iterations"); + Console.WriteLine($"AwaitInternal: max. {StrictlyOrderedTaskExtensions.Stats.AwaitInternalMaxInnerIterations} inner iterations"); + Console.WriteLine($"OnCompleted: max. {StrictlyOrderedTaskExtensions.Stats.OnCompletedMaxSpins} iterations"); +#endif + } + protected static TcpRpcClient SetupClient(IPAddress addr, int port, TcpRpcTestOptions options = TcpRpcTestOptions.None) { var client = new TcpRpcClient(); @@ -404,18 +431,6 @@ namespace Capnp.Net.Runtime.Tests protected static LocalTestbed NewLocalTestbed() => new LocalTestbed(); - [TestInitialize] - public void InitConsoleLogging() - { - Logging.LoggerFactory?.Dispose(); -#pragma warning disable CS0618 - Logging.LoggerFactory = new LoggerFactory().AddConsole((msg, level) => true); -#pragma warning restore CS0618 - Logger = Logging.CreateLogger(); - if (Thread.CurrentThread.Name == null) - Thread.CurrentThread.Name = $"Test Thread {Thread.CurrentThread.ManagedThreadId}"; - } - /// /// Somewhat ugly helper method which ensures that both Tcp client and server /// are waiting for data reception from each other. This is a "balanced" state, meaning diff --git a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj index 4773820..0ec7854 100644 --- a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj +++ b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj @@ -33,7 +33,7 @@ - + SOTASK_PERF @@ -43,6 +43,6 @@ - + diff --git a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs index 7567bf3..f86cf53 100644 --- a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs +++ b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs @@ -53,18 +53,37 @@ namespace Capnp.Util } finally { +#if SOTASK_PERF + long outerCount = 0, innerCount = 0; +#endif + SpinWait.SpinUntil(() => { Action? continuations; - do + + while (true) { +#if SOTASK_PERF + ++innerCount; +#endif + continuations = (Action?)Interlocked.Exchange(ref _state, null); - continuations?.Invoke(); - } while (continuations != null); + if (continuations != null) + continuations(); + else + break; + } +#if SOTASK_PERF + ++outerCount; +#endif return Interlocked.CompareExchange(ref _state, s_seal, null) == null; }); + +#if SOTASK_PERF + StrictlyOrderedTaskExtensions.Stats.UpdateAwaitInternal(outerCount, innerCount); +#endif } } @@ -75,7 +94,16 @@ namespace Capnp.Util { bool first = false; +#if SOTASK_PERF + long spinCount = 0; +#endif + SpinWait.SpinUntil(() => { + +#if SOTASK_PERF + ++spinCount; +#endif + object? cur, next; cur = Volatile.Read(ref _state); first = false; @@ -102,6 +130,10 @@ namespace Capnp.Util return Interlocked.CompareExchange(ref _state, next, cur) == cur; }); +#if SOTASK_PERF + StrictlyOrderedTaskExtensions.Stats.UpdateOnCompleted(spinCount); +#endif + if (first) { AwaitInternal(); @@ -168,6 +200,48 @@ namespace Capnp.Util /// public static class StrictlyOrderedTaskExtensions { +#if SOTASK_PERF + public class Statistics + { + internal long _awaitInternalMaxOuterIterations; + internal long _awaitInternalMaxInnerIterations; + internal long _onCompletedMaxSpins; + + public long AwaitInternalMaxOuterIterations => Volatile.Read(ref _awaitInternalMaxOuterIterations); + public long AwaitInternalMaxInnerIterations => Volatile.Read(ref _awaitInternalMaxInnerIterations); + public long OnCompletedMaxSpins => Volatile.Read(ref _onCompletedMaxSpins); + + public void Reset() + { + Volatile.Write(ref _awaitInternalMaxOuterIterations, 0); + Volatile.Write(ref _awaitInternalMaxInnerIterations, 0); + Volatile.Write(ref _onCompletedMaxSpins, 0); + } + + internal static void InterlockedMax(ref long current, long value) + { + long existing; + do + { + existing = Volatile.Read(ref current); + if (value <= existing) return; + } while (Interlocked.CompareExchange(ref current, value, existing) != existing); + } + + internal void UpdateAwaitInternal(long outerCount, long innerCount) + { + InterlockedMax(ref _awaitInternalMaxOuterIterations, outerCount); + InterlockedMax(ref _awaitInternalMaxInnerIterations, innerCount); + } + + internal void UpdateOnCompleted(long spinCount) + { + InterlockedMax(ref _onCompletedMaxSpins, spinCount); + } + } + + public static readonly Statistics Stats = new Statistics(); +#endif /// /// Converts the task to a task-like object which enforces that all await operations from the same thread leave in the exact order they were issued. /// From 78a62ddf98c39eed99048f1796463d202e6eca13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 21 Apr 2020 19:02:18 +0200 Subject: [PATCH 66/76] perf. profiling --- Benchmarking/CapnpProfile/CapnpProfile.csproj | 3 ++- Benchmarking/CapnpProfile/Program.cs | 16 ++++++++++++++++ .../Util/StrictlyOrderedAwaitTask.cs | 3 +++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Benchmarking/CapnpProfile/CapnpProfile.csproj b/Benchmarking/CapnpProfile/CapnpProfile.csproj index f3757eb..3f857cb 100644 --- a/Benchmarking/CapnpProfile/CapnpProfile.csproj +++ b/Benchmarking/CapnpProfile/CapnpProfile.csproj @@ -9,11 +9,12 @@ full true x64 + SOTASK_PERF - + diff --git a/Benchmarking/CapnpProfile/Program.cs b/Benchmarking/CapnpProfile/Program.cs index 274bb97..f2ddd00 100644 --- a/Benchmarking/CapnpProfile/Program.cs +++ b/Benchmarking/CapnpProfile/Program.cs @@ -21,11 +21,27 @@ namespace CapnpProfile var payload = new byte[20]; new Random().NextBytes(payload); +#if SOTASK_PERF + int counter = 0; +#endif + while (true) { var result = await echoer.Echo(payload); if (result.Count != payload.Length) throw new InvalidOperationException("Echo server malfunction"); + +#if SOTASK_PERF + if (++counter == 1000) + { + counter = 0; + + Console.WriteLine($"StrictlyOrderedTask performance statistics:"); + Console.WriteLine($"AwaitInternal: max. {Capnp.Util.StrictlyOrderedTaskExtensions.Stats.AwaitInternalMaxOuterIterations} outer iterations"); + Console.WriteLine($"AwaitInternal: max. {Capnp.Util.StrictlyOrderedTaskExtensions.Stats.AwaitInternalMaxInnerIterations} inner iterations"); + Console.WriteLine($"OnCompleted: max. {Capnp.Util.StrictlyOrderedTaskExtensions.Stats.OnCompletedMaxSpins} iterations"); + } +#endif } } } diff --git a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs index f86cf53..c5137c9 100644 --- a/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs +++ b/Capnp.Net.Runtime/Util/StrictlyOrderedAwaitTask.cs @@ -240,6 +240,9 @@ namespace Capnp.Util } } + /// + /// Performance profiling statistics + /// public static readonly Statistics Stats = new Statistics(); #endif /// From db2d6bce2e06ea9998bc745085a07e2eda97a57c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 21 Apr 2020 21:02:12 +0200 Subject: [PATCH 67/76] introduced BufferedNetworkStreamAdapter - better performance? --- Benchmarking/Benchmark/Benchmark.csproj | 2 +- Benchmarking/CapnpBench.sln | 8 +- Benchmarking/CapnpProfile/CapnpProfile.csproj | 4 +- Benchmarking/CapnpProfile/EnginePair.cs | 63 ++++++++++ Benchmarking/CapnpProfile/Program.cs | 39 ++++-- .../EchoServiceCapnp/EchoServiceCapnp.csproj | 2 +- .../EchoServiceGrpc/EchoServiceGrpc.csproj | 5 +- Benchmarking/EchoServiceGrpc/Program.cs | 2 +- .../EchoServiceGrpc/Protos/Echo.proto | 13 -- Benchmarking/EchoServiceGrpc/Startup.cs | 3 +- .../appsettings.Development.json | 8 +- .../EchoServiceGrpc2/EchoServiceGrpc.csproj | 15 --- Benchmarking/EchoServiceGrpc2/Program.cs | 27 ----- .../Services/GrpcEchoService.cs | 26 ---- Benchmarking/EchoServiceGrpc2/Startup.cs | 44 ------- .../appsettings.Development.json | 10 -- .../EchoServiceGrpc2/appsettings.json | 15 --- .../Capnp.Net.Runtime.Tests.csproj | 2 +- Capnp.Net.Runtime/Capnp.Net.Runtime.csproj | 2 +- Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs | 4 +- .../Util/BufferedNetworkStreamAdapter.cs | 114 ++++++++++++++++++ 21 files changed, 226 insertions(+), 182 deletions(-) create mode 100644 Benchmarking/CapnpProfile/EnginePair.cs delete mode 100644 Benchmarking/EchoServiceGrpc/Protos/Echo.proto delete mode 100644 Benchmarking/EchoServiceGrpc2/EchoServiceGrpc.csproj delete mode 100644 Benchmarking/EchoServiceGrpc2/Program.cs delete mode 100644 Benchmarking/EchoServiceGrpc2/Services/GrpcEchoService.cs delete mode 100644 Benchmarking/EchoServiceGrpc2/Startup.cs delete mode 100644 Benchmarking/EchoServiceGrpc2/appsettings.Development.json delete mode 100644 Benchmarking/EchoServiceGrpc2/appsettings.json create mode 100644 Capnp.Net.Runtime/Util/BufferedNetworkStreamAdapter.cs diff --git a/Benchmarking/Benchmark/Benchmark.csproj b/Benchmarking/Benchmark/Benchmark.csproj index e40a359..ec53112 100644 --- a/Benchmarking/Benchmark/Benchmark.csproj +++ b/Benchmarking/Benchmark/Benchmark.csproj @@ -7,7 +7,7 @@ - + diff --git a/Benchmarking/CapnpBench.sln b/Benchmarking/CapnpBench.sln index 5d814fc..700be3a 100644 --- a/Benchmarking/CapnpBench.sln +++ b/Benchmarking/CapnpBench.sln @@ -3,13 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29728.190 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EchoServiceGrpc", "EchoServiceGrpc\EchoServiceGrpc.csproj", "{D59C7B71-3887-426B-A636-2DBDA0549817}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmark", "Benchmark\Benchmark.csproj", "{7F7580CA-CCF0-4650-87BF-502D51A8F435}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EchoServiceCapnp", "EchoServiceCapnp\EchoServiceCapnp.csproj", "{309A4A26-F29E-4F49-AB49-76BAE0FD7D62}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EchoServiceGrpc2", "EchoServiceGrpc2\EchoServiceGrpc2.csproj", "{C9CEE2AD-AC6F-4CBD-A83D-2784832C1E37}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EchoServiceGrpc", "EchoServiceGrpc\EchoServiceGrpc.csproj", "{C9CEE2AD-AC6F-4CBD-A83D-2784832C1E37}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -17,10 +15,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D59C7B71-3887-426B-A636-2DBDA0549817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D59C7B71-3887-426B-A636-2DBDA0549817}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D59C7B71-3887-426B-A636-2DBDA0549817}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D59C7B71-3887-426B-A636-2DBDA0549817}.Release|Any CPU.Build.0 = Release|Any CPU {7F7580CA-CCF0-4650-87BF-502D51A8F435}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7F7580CA-CCF0-4650-87BF-502D51A8F435}.Debug|Any CPU.Build.0 = Debug|Any CPU {7F7580CA-CCF0-4650-87BF-502D51A8F435}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/Benchmarking/CapnpProfile/CapnpProfile.csproj b/Benchmarking/CapnpProfile/CapnpProfile.csproj index 3f857cb..9ffe4d3 100644 --- a/Benchmarking/CapnpProfile/CapnpProfile.csproj +++ b/Benchmarking/CapnpProfile/CapnpProfile.csproj @@ -9,11 +9,11 @@ full true x64 - SOTASK_PERF + - + diff --git a/Benchmarking/CapnpProfile/EnginePair.cs b/Benchmarking/CapnpProfile/EnginePair.cs new file mode 100644 index 0000000..815e12a --- /dev/null +++ b/Benchmarking/CapnpProfile/EnginePair.cs @@ -0,0 +1,63 @@ +using Capnp; +using Capnp.Rpc; +using System.Collections.Generic; + +namespace CapnpProfile +{ + class EnginePair + { + class EngineChannel : IEndpoint + { + readonly Queue _frameBuffer = new Queue(); + bool _dismissed; + + public EngineChannel() + { + } + + public RpcEngine.RpcEndpoint OtherEndpoint { get; set; } + public bool HasBufferedFrames => _frameBuffer.Count > 0; + public int FrameCounter { get; private set; } + + + public void Dismiss() + { + if (!_dismissed) + { + _dismissed = true; + OtherEndpoint.Dismiss(); + } + } + + public void Forward(WireFrame frame) + { + if (_dismissed) + return; + + OtherEndpoint.Forward(frame); + } + } + + readonly EngineChannel _channel1, _channel2; + + public RpcEngine Engine1 { get; } + public RpcEngine Engine2 { get; } + public RpcEngine.RpcEndpoint Endpoint1 { get; } + public RpcEngine.RpcEndpoint Endpoint2 { get; } + + public EnginePair() + { + Engine1 = new RpcEngine(); + Engine2 = new RpcEngine(); + _channel1 = new EngineChannel(); + Endpoint1 = Engine1.AddEndpoint(_channel1); + _channel2 = new EngineChannel(); + Endpoint2 = Engine2.AddEndpoint(_channel2); + _channel1.OtherEndpoint = Endpoint2; + _channel2.OtherEndpoint = Endpoint1; + } + + public int Channel1SendCount => _channel1.FrameCounter; + public int Channel2SendCount => _channel2.FrameCounter; + } +} diff --git a/Benchmarking/CapnpProfile/Program.cs b/Benchmarking/CapnpProfile/Program.cs index f2ddd00..97a28ce 100644 --- a/Benchmarking/CapnpProfile/Program.cs +++ b/Benchmarking/CapnpProfile/Program.cs @@ -7,17 +7,11 @@ using System.Threading.Tasks; namespace CapnpProfile { + class Program { - static async Task Main(string[] args) + static async Task Run(IEchoer echoer) { - using var server = new TcpRpcServer(); - server.Main = new CapnpEchoService(); - server.AddBuffering(); - server.StartAccepting(IPAddress.Any, 5002); - using var client = new TcpRpcClient("localhost", 5002); - await client.WhenConnected; - using var echoer = client.GetMain(); var payload = new byte[20]; new Random().NextBytes(payload); @@ -32,7 +26,7 @@ namespace CapnpProfile throw new InvalidOperationException("Echo server malfunction"); #if SOTASK_PERF - if (++counter == 1000) + if (++counter == 10000) { counter = 0; @@ -44,5 +38,32 @@ namespace CapnpProfile #endif } } + + static async Task Main(string[] args) + { + + if (args.Length > 0) + { + var pair = new EnginePair(); + pair.Engine1.Main = new CapnpEchoService(); + var echoer = (CapabilityReflection.CreateProxy(pair.Endpoint2.QueryMain()) as IEchoer); + + await Run(echoer); + } + else + { + using var server = new TcpRpcServer(); + server.Main = new CapnpEchoService(); + server.AddBuffering(); + server.StartAccepting(IPAddress.Any, 5002); + using var client = new TcpRpcClient(); + client.AddBuffering(); + client.Connect("localhost", 5002); + await client.WhenConnected; + using var echoer = client.GetMain(); + + await Run(echoer); + } + } } } diff --git a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj index 99eff10..ebbd9c6 100644 --- a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj +++ b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj @@ -6,7 +6,7 @@ - + diff --git a/Benchmarking/EchoServiceGrpc/EchoServiceGrpc.csproj b/Benchmarking/EchoServiceGrpc/EchoServiceGrpc.csproj index 28b512c..da2e193 100644 --- a/Benchmarking/EchoServiceGrpc/EchoServiceGrpc.csproj +++ b/Benchmarking/EchoServiceGrpc/EchoServiceGrpc.csproj @@ -2,11 +2,12 @@ netcoreapp3.1 - EchoService.Program - + + Protos\Echo.proto + diff --git a/Benchmarking/EchoServiceGrpc/Program.cs b/Benchmarking/EchoServiceGrpc/Program.cs index f24aee5..a3d05d6 100644 --- a/Benchmarking/EchoServiceGrpc/Program.cs +++ b/Benchmarking/EchoServiceGrpc/Program.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; -namespace EchoService +namespace EchoServiceGrpc2 { public class Program { diff --git a/Benchmarking/EchoServiceGrpc/Protos/Echo.proto b/Benchmarking/EchoServiceGrpc/Protos/Echo.proto deleted file mode 100644 index b1b0c0d..0000000 --- a/Benchmarking/EchoServiceGrpc/Protos/Echo.proto +++ /dev/null @@ -1,13 +0,0 @@ -syntax = "proto3"; - -service Echoer { - rpc Echo (EchoRequest) returns (EchoReply); -} - -message EchoRequest { - bytes payload = 1; -} - -message EchoReply { - bytes payload = 1; -} \ No newline at end of file diff --git a/Benchmarking/EchoServiceGrpc/Startup.cs b/Benchmarking/EchoServiceGrpc/Startup.cs index b93a112..3679177 100644 --- a/Benchmarking/EchoServiceGrpc/Startup.cs +++ b/Benchmarking/EchoServiceGrpc/Startup.cs @@ -2,13 +2,14 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using EchoService; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace EchoService +namespace EchoServiceGrpc2 { public class Startup { diff --git a/Benchmarking/EchoServiceGrpc/appsettings.Development.json b/Benchmarking/EchoServiceGrpc/appsettings.Development.json index 1ca5366..fe20c40 100644 --- a/Benchmarking/EchoServiceGrpc/appsettings.Development.json +++ b/Benchmarking/EchoServiceGrpc/appsettings.Development.json @@ -1,10 +1,10 @@ { "Logging": { "LogLevel": { - "Default": "Warning", - "System": "Warning", - "Grpc": "Warning", - "Microsoft": "Warning" + "Default": "Debug", + "System": "Information", + "Grpc": "Information", + "Microsoft": "Information" } } } diff --git a/Benchmarking/EchoServiceGrpc2/EchoServiceGrpc.csproj b/Benchmarking/EchoServiceGrpc2/EchoServiceGrpc.csproj deleted file mode 100644 index 3d293a8..0000000 --- a/Benchmarking/EchoServiceGrpc2/EchoServiceGrpc.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp3.1 - - - - - - - - - - - diff --git a/Benchmarking/EchoServiceGrpc2/Program.cs b/Benchmarking/EchoServiceGrpc2/Program.cs deleted file mode 100644 index a3d05d6..0000000 --- a/Benchmarking/EchoServiceGrpc2/Program.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; - -namespace EchoServiceGrpc2 -{ - public class Program - { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - // Additional configuration is required to successfully run gRPC on macOS. - // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); - } -} diff --git a/Benchmarking/EchoServiceGrpc2/Services/GrpcEchoService.cs b/Benchmarking/EchoServiceGrpc2/Services/GrpcEchoService.cs deleted file mode 100644 index 71a7ef9..0000000 --- a/Benchmarking/EchoServiceGrpc2/Services/GrpcEchoService.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Grpc.Core; -using Microsoft.Extensions.Logging; - -namespace EchoService -{ - public class GrpcEchoService : Echoer.EchoerBase - { - private readonly ILogger _logger; - public GrpcEchoService(ILogger logger) - { - _logger = logger; - } - - public override Task Echo(EchoRequest request, ServerCallContext context) - { - return Task.FromResult(new EchoReply - { - Payload = request.Payload - }); - } - } -} diff --git a/Benchmarking/EchoServiceGrpc2/Startup.cs b/Benchmarking/EchoServiceGrpc2/Startup.cs deleted file mode 100644 index 3679177..0000000 --- a/Benchmarking/EchoServiceGrpc2/Startup.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using EchoService; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace EchoServiceGrpc2 -{ - public class Startup - { - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 - public void ConfigureServices(IServiceCollection services) - { - services.AddGrpc(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseRouting(); - - app.UseEndpoints(endpoints => - { - endpoints.MapGrpcService(); - - endpoints.MapGet("/", async context => - { - await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); - }); - }); - } - } -} diff --git a/Benchmarking/EchoServiceGrpc2/appsettings.Development.json b/Benchmarking/EchoServiceGrpc2/appsettings.Development.json deleted file mode 100644 index fe20c40..0000000 --- a/Benchmarking/EchoServiceGrpc2/appsettings.Development.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Grpc": "Information", - "Microsoft": "Information" - } - } -} diff --git a/Benchmarking/EchoServiceGrpc2/appsettings.json b/Benchmarking/EchoServiceGrpc2/appsettings.json deleted file mode 100644 index 3110458..0000000 --- a/Benchmarking/EchoServiceGrpc2/appsettings.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Warning", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Warning" - } - }, - "AllowedHosts": "*", - "Kestrel": { - "EndpointDefaults": { - "Protocols": "Http2" - } - } -} diff --git a/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.csproj b/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.csproj index 0057a55..8cfe88d 100644 --- a/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.csproj +++ b/Capnp.Net.Runtime.Tests/Capnp.Net.Runtime.Tests.csproj @@ -19,7 +19,7 @@ - TRACE;SOTASK_PERF + TRACE diff --git a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj index 0ec7854..f6bcfa4 100644 --- a/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj +++ b/Capnp.Net.Runtime/Capnp.Net.Runtime.csproj @@ -33,7 +33,7 @@ - SOTASK_PERF + diff --git a/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs b/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs index eb6fbae..ca05312 100644 --- a/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs @@ -17,7 +17,7 @@ namespace Capnp.Rpc /// Buffer size (bytes). You should choose it according to the maximum expected raw capnp frame size public static void AddBuffering(this ISupportsMidlayers obj, int bufferSize) { - obj.InjectMidlayer(s => new Util.DuplexBufferedStream(s, bufferSize)); + obj.InjectMidlayer(s => new Util.BufferedNetworkStreamAdapter(s, bufferSize)); } /// @@ -27,7 +27,7 @@ namespace Capnp.Rpc /// or public static void AddBuffering(this ISupportsMidlayers obj) { - obj.InjectMidlayer(s => new Util.DuplexBufferedStream(s)); + obj.InjectMidlayer(s => new Util.BufferedNetworkStreamAdapter(s)); } } } diff --git a/Capnp.Net.Runtime/Util/BufferedNetworkStreamAdapter.cs b/Capnp.Net.Runtime/Util/BufferedNetworkStreamAdapter.cs new file mode 100644 index 0000000..f52a4f6 --- /dev/null +++ b/Capnp.Net.Runtime/Util/BufferedNetworkStreamAdapter.cs @@ -0,0 +1,114 @@ +using System; +using System.IO; +using System.Net.Sockets; +using System.Threading; + +namespace Capnp.Util +{ + internal class BufferedNetworkStreamAdapter : Stream + { + // A buffer size of 1024 bytes seems to be a good comprise, giving good performance + // in TCP/IP-over-localhost scenarios for small to medium (200kiB) frame sizes. + const int DefaultBufferSize = 1024; + + readonly BufferedStream _readStream; + readonly NetworkStream _writeStream; + readonly object _reentrancyBlocker = new object(); + Exception? _bufferedException; + + public BufferedNetworkStreamAdapter(Stream stream, int bufferSize) + { + _readStream = new BufferedStream(stream, bufferSize); + _writeStream = stream as NetworkStream ?? throw new ArgumentException("stream argument must be a NetworkStream"); + } + + public BufferedNetworkStreamAdapter(Stream stream) : this(stream, DefaultBufferSize) + { + } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length => 0; + + public override long Position + { + get => 0; + set => throw new NotSupportedException(); + } + + public override void Flush() + { + _writeStream.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + return _readStream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + void WriteCallback(IAsyncResult ar) + { + try + { + _writeStream.EndWrite(ar); + } + catch (Exception exception) + { + Volatile.Write(ref _bufferedException, exception); + } + } + + public override void Write(byte[] buffer, int offset, int count) + { + var exception = Volatile.Read(ref _bufferedException); + + if (exception != null) + { + Dispose(); + throw exception; + } + + _writeStream.BeginWrite(buffer, offset, count, WriteCallback, null); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + lock (_reentrancyBlocker) + { + try + { + _readStream.Dispose(); + } + catch + { + } + try + { + _writeStream.Dispose(); + } + catch + { + } + } + } + + base.Dispose(disposing); + } + } +} From 73bd1de241a1b5dc6ad0ce2cb385de6934a212ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 21 Apr 2020 21:17:34 +0200 Subject: [PATCH 68/76] additional write buffer --- Benchmarking/Benchmark/Benchmark.csproj | 2 +- Benchmarking/Benchmark/Program.cs | 7 +- .../EchoServiceCapnp/EchoServiceCapnp.csproj | 4 +- Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs | 4 +- Capnp.Net.Runtime/Util/WriteBufferedStream.cs | 96 +++++++++++++++++++ 5 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 Capnp.Net.Runtime/Util/WriteBufferedStream.cs diff --git a/Benchmarking/Benchmark/Benchmark.csproj b/Benchmarking/Benchmark/Benchmark.csproj index ec53112..56eb5f7 100644 --- a/Benchmarking/Benchmark/Benchmark.csproj +++ b/Benchmarking/Benchmark/Benchmark.csproj @@ -7,7 +7,7 @@ - + diff --git a/Benchmarking/Benchmark/Program.cs b/Benchmarking/Benchmark/Program.cs index 16a0924..fe51c0a 100644 --- a/Benchmarking/Benchmark/Program.cs +++ b/Benchmarking/Benchmark/Program.cs @@ -11,8 +11,11 @@ namespace Benchmark { static void Main(string[] args) { - BenchmarkRunner.Run(); - BenchmarkRunner.Run(); + if (args.Length == 0 || args[0] == "grpc") + BenchmarkRunner.Run(); + + if (args.Length == 0 || args[0] == "capnp") + BenchmarkRunner.Run(); } } } diff --git a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj index ebbd9c6..317f6be 100644 --- a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj +++ b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs b/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs index ca05312..8205ee4 100644 --- a/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs @@ -17,7 +17,7 @@ namespace Capnp.Rpc /// Buffer size (bytes). You should choose it according to the maximum expected raw capnp frame size public static void AddBuffering(this ISupportsMidlayers obj, int bufferSize) { - obj.InjectMidlayer(s => new Util.BufferedNetworkStreamAdapter(s, bufferSize)); + obj.InjectMidlayer(s => new Util.WriteBufferedStream(new Util.BufferedNetworkStreamAdapter(s, bufferSize), bufferSize)); } /// @@ -27,7 +27,7 @@ namespace Capnp.Rpc /// or public static void AddBuffering(this ISupportsMidlayers obj) { - obj.InjectMidlayer(s => new Util.BufferedNetworkStreamAdapter(s)); + obj.InjectMidlayer(s => new Util.WriteBufferedStream(new Util.BufferedNetworkStreamAdapter(s))); } } } diff --git a/Capnp.Net.Runtime/Util/WriteBufferedStream.cs b/Capnp.Net.Runtime/Util/WriteBufferedStream.cs new file mode 100644 index 0000000..6e91c9d --- /dev/null +++ b/Capnp.Net.Runtime/Util/WriteBufferedStream.cs @@ -0,0 +1,96 @@ +using System; +using System.IO; + +namespace Capnp.Util +{ + internal class WriteBufferedStream : Stream + { + // A buffer size of 1024 bytes seems to be a good comprise, giving good performance + // in TCP/IP-over-localhost scenarios for small to medium (200kiB) frame sizes. + const int DefaultBufferSize = 1024; + + readonly Stream _readStream; + readonly BufferedStream _writeStream; + readonly int _bufferSize; + readonly object _reentrancyBlocker = new object(); + + public WriteBufferedStream(Stream stream, int bufferSize) + { + _readStream = stream; + _writeStream = new BufferedStream(stream, bufferSize); + _bufferSize = bufferSize; + } + + public WriteBufferedStream(Stream stream) : this(stream, DefaultBufferSize) + { + } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length => 0; + + public override long Position + { + get => 0; + set => throw new NotSupportedException(); + } + + public override void Flush() + { + _writeStream.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + return _readStream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (buffer.Length > _bufferSize) // avoid moiré-like timing effects + _writeStream.Flush(); + + _writeStream.Write(buffer, offset, count); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + lock (_reentrancyBlocker) + { + try + { + _readStream.Dispose(); + } + catch + { + } + try + { + _writeStream.Dispose(); + } + catch + { + } + } + } + + base.Dispose(disposing); + } + } +} From 87575f12bf445b2574dc52f6579b5233e665c202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 21 Apr 2020 21:42:51 +0200 Subject: [PATCH 69/76] another async variant --- Benchmarking/Benchmark/Benchmark.csproj | 2 +- .../EchoServiceCapnp/EchoServiceCapnp.csproj | 2 +- Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs | 4 +- ...Stream.cs => AsyncNetworkStreamAdapter.cs} | 60 ++++----- .../Util/BufferedNetworkStreamAdapter.cs | 114 ------------------ 5 files changed, 35 insertions(+), 147 deletions(-) rename Capnp.Net.Runtime/Util/{WriteBufferedStream.cs => AsyncNetworkStreamAdapter.cs} (53%) delete mode 100644 Capnp.Net.Runtime/Util/BufferedNetworkStreamAdapter.cs diff --git a/Benchmarking/Benchmark/Benchmark.csproj b/Benchmarking/Benchmark/Benchmark.csproj index 56eb5f7..43c2aab 100644 --- a/Benchmarking/Benchmark/Benchmark.csproj +++ b/Benchmarking/Benchmark/Benchmark.csproj @@ -7,7 +7,7 @@ - + diff --git a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj index 317f6be..3b41a29 100644 --- a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj +++ b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj @@ -6,7 +6,7 @@ - + diff --git a/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs b/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs index 8205ee4..200aecd 100644 --- a/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs @@ -17,7 +17,7 @@ namespace Capnp.Rpc /// Buffer size (bytes). You should choose it according to the maximum expected raw capnp frame size public static void AddBuffering(this ISupportsMidlayers obj, int bufferSize) { - obj.InjectMidlayer(s => new Util.WriteBufferedStream(new Util.BufferedNetworkStreamAdapter(s, bufferSize), bufferSize)); + obj.InjectMidlayer(s => new Util.DuplexBufferedStream(new Util.AsyncNetworkStreamAdapter(s), bufferSize)); } /// @@ -27,7 +27,7 @@ namespace Capnp.Rpc /// or public static void AddBuffering(this ISupportsMidlayers obj) { - obj.InjectMidlayer(s => new Util.WriteBufferedStream(new Util.BufferedNetworkStreamAdapter(s))); + obj.InjectMidlayer(s => new Util.DuplexBufferedStream(new Util.AsyncNetworkStreamAdapter(s))); } } } diff --git a/Capnp.Net.Runtime/Util/WriteBufferedStream.cs b/Capnp.Net.Runtime/Util/AsyncNetworkStreamAdapter.cs similarity index 53% rename from Capnp.Net.Runtime/Util/WriteBufferedStream.cs rename to Capnp.Net.Runtime/Util/AsyncNetworkStreamAdapter.cs index 6e91c9d..cfd255a 100644 --- a/Capnp.Net.Runtime/Util/WriteBufferedStream.cs +++ b/Capnp.Net.Runtime/Util/AsyncNetworkStreamAdapter.cs @@ -1,28 +1,19 @@ using System; using System.IO; +using System.Net.Sockets; +using System.Threading; namespace Capnp.Util { - internal class WriteBufferedStream : Stream + internal class AsyncNetworkStreamAdapter : Stream { - // A buffer size of 1024 bytes seems to be a good comprise, giving good performance - // in TCP/IP-over-localhost scenarios for small to medium (200kiB) frame sizes. - const int DefaultBufferSize = 1024; - - readonly Stream _readStream; - readonly BufferedStream _writeStream; - readonly int _bufferSize; + readonly NetworkStream _stream; readonly object _reentrancyBlocker = new object(); + //Exception? _bufferedException; - public WriteBufferedStream(Stream stream, int bufferSize) - { - _readStream = stream; - _writeStream = new BufferedStream(stream, bufferSize); - _bufferSize = bufferSize; - } - - public WriteBufferedStream(Stream stream) : this(stream, DefaultBufferSize) + public AsyncNetworkStreamAdapter(Stream stream) { + _stream = stream as NetworkStream ?? throw new ArgumentException("stream argument must be a NetworkStream"); } public override bool CanRead => true; @@ -41,12 +32,12 @@ namespace Capnp.Util public override void Flush() { - _writeStream.Flush(); + _stream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { - return _readStream.Read(buffer, offset, count); + return _stream.Read(buffer, offset, count); } public override long Seek(long offset, SeekOrigin origin) @@ -59,12 +50,30 @@ namespace Capnp.Util throw new NotSupportedException(); } + //void WriteCallback(IAsyncResult ar) + //{ + // try + // { + // _stream.EndWrite(ar); + // } + // catch (Exception exception) + // { + // Volatile.Write(ref _bufferedException, exception); + // } + //} + public override void Write(byte[] buffer, int offset, int count) { - if (buffer.Length > _bufferSize) // avoid moiré-like timing effects - _writeStream.Flush(); + _stream.WriteAsync(buffer, offset, count); + //var exception = Volatile.Read(ref _bufferedException); + + //if (exception != null) + //{ + // Dispose(); + // throw exception; + //} - _writeStream.Write(buffer, offset, count); + //_stream.BeginWrite(buffer, offset, count, WriteCallback, null); } protected override void Dispose(bool disposing) @@ -75,14 +84,7 @@ namespace Capnp.Util { try { - _readStream.Dispose(); - } - catch - { - } - try - { - _writeStream.Dispose(); + _stream.Dispose(); } catch { diff --git a/Capnp.Net.Runtime/Util/BufferedNetworkStreamAdapter.cs b/Capnp.Net.Runtime/Util/BufferedNetworkStreamAdapter.cs deleted file mode 100644 index f52a4f6..0000000 --- a/Capnp.Net.Runtime/Util/BufferedNetworkStreamAdapter.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.IO; -using System.Net.Sockets; -using System.Threading; - -namespace Capnp.Util -{ - internal class BufferedNetworkStreamAdapter : Stream - { - // A buffer size of 1024 bytes seems to be a good comprise, giving good performance - // in TCP/IP-over-localhost scenarios for small to medium (200kiB) frame sizes. - const int DefaultBufferSize = 1024; - - readonly BufferedStream _readStream; - readonly NetworkStream _writeStream; - readonly object _reentrancyBlocker = new object(); - Exception? _bufferedException; - - public BufferedNetworkStreamAdapter(Stream stream, int bufferSize) - { - _readStream = new BufferedStream(stream, bufferSize); - _writeStream = stream as NetworkStream ?? throw new ArgumentException("stream argument must be a NetworkStream"); - } - - public BufferedNetworkStreamAdapter(Stream stream) : this(stream, DefaultBufferSize) - { - } - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => true; - - public override long Length => 0; - - public override long Position - { - get => 0; - set => throw new NotSupportedException(); - } - - public override void Flush() - { - _writeStream.Flush(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - return _readStream.Read(buffer, offset, count); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - void WriteCallback(IAsyncResult ar) - { - try - { - _writeStream.EndWrite(ar); - } - catch (Exception exception) - { - Volatile.Write(ref _bufferedException, exception); - } - } - - public override void Write(byte[] buffer, int offset, int count) - { - var exception = Volatile.Read(ref _bufferedException); - - if (exception != null) - { - Dispose(); - throw exception; - } - - _writeStream.BeginWrite(buffer, offset, count, WriteCallback, null); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - lock (_reentrancyBlocker) - { - try - { - _readStream.Dispose(); - } - catch - { - } - try - { - _writeStream.Dispose(); - } - catch - { - } - } - } - - base.Dispose(disposing); - } - } -} From 4f76073ee5ed7fcc5f1b188f091d4ec9dfa7db15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Tue, 21 Apr 2020 22:23:08 +0200 Subject: [PATCH 70/76] tweak --- Benchmarking/Benchmark/Benchmark.csproj | 4 +-- .../EchoServiceCapnp/EchoServiceCapnp.csproj | 2 +- .../Util/AsyncNetworkStreamAdapter.cs | 25 ++++++++++++++----- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Benchmarking/Benchmark/Benchmark.csproj b/Benchmarking/Benchmark/Benchmark.csproj index 43c2aab..f9f1474 100644 --- a/Benchmarking/Benchmark/Benchmark.csproj +++ b/Benchmarking/Benchmark/Benchmark.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj index 3b41a29..5954408 100644 --- a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj +++ b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj @@ -6,7 +6,7 @@ - + diff --git a/Capnp.Net.Runtime/Util/AsyncNetworkStreamAdapter.cs b/Capnp.Net.Runtime/Util/AsyncNetworkStreamAdapter.cs index cfd255a..9c9481e 100644 --- a/Capnp.Net.Runtime/Util/AsyncNetworkStreamAdapter.cs +++ b/Capnp.Net.Runtime/Util/AsyncNetworkStreamAdapter.cs @@ -7,15 +7,24 @@ namespace Capnp.Util { internal class AsyncNetworkStreamAdapter : Stream { - readonly NetworkStream _stream; - readonly object _reentrancyBlocker = new object(); - //Exception? _bufferedException; + // Async I/O pays off for large payloads. Perf. profiling gave a threshold around 200kB + const int DefaultAsyncThreshold = 200000; - public AsyncNetworkStreamAdapter(Stream stream) + readonly NetworkStream _stream; + readonly int _asyncThreshold; + readonly object _reentrancyBlocker = new object(); + Exception? _bufferedException; + + public AsyncNetworkStreamAdapter(Stream stream, int asyncThreshold) { + _asyncThreshold = asyncThreshold; _stream = stream as NetworkStream ?? throw new ArgumentException("stream argument must be a NetworkStream"); } + public AsyncNetworkStreamAdapter(Stream stream): this(stream, DefaultAsyncThreshold) + { + } + public override bool CanRead => true; public override bool CanSeek => false; @@ -32,7 +41,8 @@ namespace Capnp.Util public override void Flush() { - _stream.Flush(); + _stream.FlushAsync(); + //_stream.Flush(); } public override int Read(byte[] buffer, int offset, int count) @@ -73,7 +83,10 @@ namespace Capnp.Util // throw exception; //} - //_stream.BeginWrite(buffer, offset, count, WriteCallback, null); + //if (count >= _asyncThreshold) + // _stream.BeginWrite(buffer, offset, count, WriteCallback, null); + //else + // _stream.Write(buffer, offset, count); } protected override void Dispose(bool disposing) From 3ef9a60a7f7d90d45796f6c3165c00eb09465be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Wed, 22 Apr 2020 07:20:27 +0200 Subject: [PATCH 71/76] removed async. stream adapter - no benefit --- Benchmarking/Benchmark/Benchmark.csproj | 4 +- .../EchoServiceCapnp/EchoServiceCapnp.csproj | 4 +- Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs | 4 +- .../Util/AsyncNetworkStreamAdapter.cs | 111 ------------------ 4 files changed, 6 insertions(+), 117 deletions(-) delete mode 100644 Capnp.Net.Runtime/Util/AsyncNetworkStreamAdapter.cs diff --git a/Benchmarking/Benchmark/Benchmark.csproj b/Benchmarking/Benchmark/Benchmark.csproj index f9f1474..0471ab5 100644 --- a/Benchmarking/Benchmark/Benchmark.csproj +++ b/Benchmarking/Benchmark/Benchmark.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj index 5954408..57d08f5 100644 --- a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj +++ b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs b/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs index 200aecd..eb6fbae 100644 --- a/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs +++ b/Capnp.Net.Runtime/Rpc/MidlayerExtensions.cs @@ -17,7 +17,7 @@ namespace Capnp.Rpc /// Buffer size (bytes). You should choose it according to the maximum expected raw capnp frame size public static void AddBuffering(this ISupportsMidlayers obj, int bufferSize) { - obj.InjectMidlayer(s => new Util.DuplexBufferedStream(new Util.AsyncNetworkStreamAdapter(s), bufferSize)); + obj.InjectMidlayer(s => new Util.DuplexBufferedStream(s, bufferSize)); } /// @@ -27,7 +27,7 @@ namespace Capnp.Rpc /// or public static void AddBuffering(this ISupportsMidlayers obj) { - obj.InjectMidlayer(s => new Util.DuplexBufferedStream(new Util.AsyncNetworkStreamAdapter(s))); + obj.InjectMidlayer(s => new Util.DuplexBufferedStream(s)); } } } diff --git a/Capnp.Net.Runtime/Util/AsyncNetworkStreamAdapter.cs b/Capnp.Net.Runtime/Util/AsyncNetworkStreamAdapter.cs deleted file mode 100644 index 9c9481e..0000000 --- a/Capnp.Net.Runtime/Util/AsyncNetworkStreamAdapter.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.IO; -using System.Net.Sockets; -using System.Threading; - -namespace Capnp.Util -{ - internal class AsyncNetworkStreamAdapter : Stream - { - // Async I/O pays off for large payloads. Perf. profiling gave a threshold around 200kB - const int DefaultAsyncThreshold = 200000; - - readonly NetworkStream _stream; - readonly int _asyncThreshold; - readonly object _reentrancyBlocker = new object(); - Exception? _bufferedException; - - public AsyncNetworkStreamAdapter(Stream stream, int asyncThreshold) - { - _asyncThreshold = asyncThreshold; - _stream = stream as NetworkStream ?? throw new ArgumentException("stream argument must be a NetworkStream"); - } - - public AsyncNetworkStreamAdapter(Stream stream): this(stream, DefaultAsyncThreshold) - { - } - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => true; - - public override long Length => 0; - - public override long Position - { - get => 0; - set => throw new NotSupportedException(); - } - - public override void Flush() - { - _stream.FlushAsync(); - //_stream.Flush(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - return _stream.Read(buffer, offset, count); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - //void WriteCallback(IAsyncResult ar) - //{ - // try - // { - // _stream.EndWrite(ar); - // } - // catch (Exception exception) - // { - // Volatile.Write(ref _bufferedException, exception); - // } - //} - - public override void Write(byte[] buffer, int offset, int count) - { - _stream.WriteAsync(buffer, offset, count); - //var exception = Volatile.Read(ref _bufferedException); - - //if (exception != null) - //{ - // Dispose(); - // throw exception; - //} - - //if (count >= _asyncThreshold) - // _stream.BeginWrite(buffer, offset, count, WriteCallback, null); - //else - // _stream.Write(buffer, offset, count); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - lock (_reentrancyBlocker) - { - try - { - _stream.Dispose(); - } - catch - { - } - } - } - - base.Dispose(disposing); - } - } -} From 4f0abaac735efa8f52ac7ef9b3251846d962862c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Wed, 22 Apr 2020 22:19:16 +0200 Subject: [PATCH 72/76] flush optimization --- Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs | 5 ++ Capnp.Net.Runtime.Tests/Util/TestBase.cs | 4 + Capnp.Net.Runtime/FramePump.cs | 16 +++- Capnp.Net.Runtime/Rpc/IEndpoint.cs | 2 + Capnp.Net.Runtime/Rpc/RpcEngine.cs | 94 +++++++++++++++++++++ Capnp.Net.Runtime/Rpc/TcpRpcClient.cs | 5 ++ Capnp.Net.Runtime/Rpc/TcpRpcServer.cs | 5 ++ 7 files changed, 130 insertions(+), 1 deletion(-) diff --git a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs index 1cace55..a48e1a4 100644 --- a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs +++ b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs @@ -45,6 +45,11 @@ namespace Capnp.Net.Runtime.Tests _fromEnginePump.Send(frame); } + public void Flush() + { + _fromEnginePump.Flush(); + } + public WireFrame ReadNextFrame() { var frame = _reader.ReadWireFrame(); diff --git a/Capnp.Net.Runtime.Tests/Util/TestBase.cs b/Capnp.Net.Runtime.Tests/Util/TestBase.cs index bad16c0..2899428 100644 --- a/Capnp.Net.Runtime.Tests/Util/TestBase.cs +++ b/Capnp.Net.Runtime.Tests/Util/TestBase.cs @@ -104,6 +104,10 @@ namespace Capnp.Net.Runtime.Tests return false; } } + + void IEndpoint.Flush() + { + } } readonly DecisionTree _decisionTree; diff --git a/Capnp.Net.Runtime/FramePump.cs b/Capnp.Net.Runtime/FramePump.cs index dad87c3..71c611b 100644 --- a/Capnp.Net.Runtime/FramePump.cs +++ b/Capnp.Net.Runtime/FramePump.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Net.Sockets; using System.Runtime.InteropServices; @@ -117,8 +118,21 @@ namespace Capnp #endif _writer.Write(bytes); } + } + } - _writer.Flush(); + public void Flush() + { + if (Monitor.TryEnter(_writeLock)) + { + try + { + _writer?.Flush(); + } + finally + { + Monitor.Exit(_writeLock); + } } } diff --git a/Capnp.Net.Runtime/Rpc/IEndpoint.cs b/Capnp.Net.Runtime/Rpc/IEndpoint.cs index 267cafa..02aa5d6 100644 --- a/Capnp.Net.Runtime/Rpc/IEndpoint.cs +++ b/Capnp.Net.Runtime/Rpc/IEndpoint.cs @@ -10,6 +10,8 @@ /// void Forward(WireFrame frame); + void Flush(); + /// /// Close this endpoint. /// diff --git a/Capnp.Net.Runtime/Rpc/RpcEngine.cs b/Capnp.Net.Runtime/Rpc/RpcEngine.cs index 60cc0ef..787b711 100644 --- a/Capnp.Net.Runtime/Rpc/RpcEngine.cs +++ b/Capnp.Net.Runtime/Rpc/RpcEngine.cs @@ -66,8 +66,59 @@ namespace Capnp.Rpc Dismissed } + class FlushContext + { + readonly FlushContext? _prev; + readonly RpcEndpoint _ep; + bool _requested; + + public FlushContext(FlushContext? prev, RpcEndpoint ep) + { + _prev = prev; + _ep = ep; + _requested = false; + } + + public RpcEndpoint Ep => _ep; + + public void Request() + { + _requested = true; + } + + public void Remove() + { + _flushRequests.Value = _prev; + + if (_requested) + _ep._tx.Flush(); + } + } + + readonly struct FlushContextKeeper: IDisposable + { + readonly FlushContext _context; + readonly bool _owner; + + public FlushContextKeeper(FlushContext context, bool owner) + { + _context = context; + _owner = owner; + } + + public void Dispose() + { + if (_owner) + { + _context.Remove(); + } + } + + } + static readonly ThreadLocal _deferredCall = new ThreadLocal(); static readonly ThreadLocal _canDeferCalls = new ThreadLocal(); + static readonly ThreadLocal _flushRequests = new ThreadLocal(); ILogger Logger { get; } = Logging.CreateLogger(); @@ -138,6 +189,10 @@ namespace Capnp.Rpc ProcessFrame(frame); } + void IEndpoint.Flush() + { + } + /// /// Number of frames sent so far /// @@ -204,11 +259,37 @@ namespace Capnp.Rpc } } + FlushContextKeeper SetupFlushContext() + { + if (_flushRequests.Value?.Ep == this) + { + return new FlushContextKeeper(_flushRequests.Value, false); + } + else + { + _flushRequests.Value = new FlushContext(_flushRequests.Value, this); + return new FlushContextKeeper(_flushRequests.Value, true); + } + } + + void RequestFlush() + { + if (_flushRequests.Value?.Ep == this) + { + _flushRequests.Value.Request(); + } + else + { + _tx.Flush(); + } + } + void Tx(WireFrame frame) { try { _tx.Forward(frame); + RequestFlush(); Interlocked.Increment(ref _sendCount); } catch (System.Exception exception) @@ -235,6 +316,8 @@ namespace Capnp.Rpc void IRpcEndpoint.Resolve(uint preliminaryId, Skeleton preliminaryCap, Func resolvedCapGetter) { + using var fc = SetupFlushContext(); + lock (_reentrancyBlocker) { if (!_exportTable.TryGetValue(preliminaryId, out var existing) || @@ -1168,6 +1251,7 @@ namespace Capnp.Rpc req.Bootstrap!.QuestionId = pendingBootstrap.QuestionId; Tx(mb.Frame); + _tx.Flush(); var main = new RemoteAnswerCapability( pendingBootstrap, @@ -1178,6 +1262,7 @@ namespace Capnp.Rpc void ProcessFrame(WireFrame frame) { + using var fc = SetupFlushContext(); var dec = DeserializerState.CreateRoot(frame); var msg = Message.READER.create(dec); @@ -1415,6 +1500,7 @@ namespace Capnp.Rpc PendingQuestion IRpcEndpoint.BeginQuestion(ConsumedCapability target, SerializerState inParams) { + using var fc = SetupFlushContext(); var question = AllocateQuestion(target, inParams); if (_canDeferCalls.Value) @@ -1458,11 +1544,14 @@ namespace Capnp.Rpc void IRpcEndpoint.Finish(uint questionId) { + using var fc = SetupFlushContext(); Finish(questionId); } void IRpcEndpoint.ReleaseImport(uint importId) { + using var fc = SetupFlushContext(); + bool exists; int count = 0; @@ -1492,6 +1581,7 @@ namespace Capnp.Rpc try { Tx(mb.Frame); + RequestFlush(); } catch (RpcException exception) { @@ -1502,6 +1592,8 @@ namespace Capnp.Rpc Task IRpcEndpoint.RequestSenderLoopback(Action describe) { + using var fc = SetupFlushContext(); + (var tcs, uint id) = AllocateDisembargo(); var mb = MessageBuilder.Create(); @@ -1520,6 +1612,8 @@ namespace Capnp.Rpc void IRpcEndpoint.DeleteQuestion(PendingQuestion question) { + using var fc = SetupFlushContext(); + lock (_reentrancyBlocker) { if (!_questionTable.Remove(question.QuestionId)) diff --git a/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs b/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs index f52d702..216d280 100644 --- a/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs +++ b/Capnp.Net.Runtime/Rpc/TcpRpcClient.cs @@ -36,6 +36,11 @@ namespace Capnp.Rpc { _pump.Send(frame); } + + public void Flush() + { + _pump.Flush(); + } } readonly RpcEngine _rpcEngine; diff --git a/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs b/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs index 150ddd5..758ae3d 100644 --- a/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs +++ b/Capnp.Net.Runtime/Rpc/TcpRpcServer.cs @@ -57,6 +57,11 @@ namespace Capnp.Rpc { _pump.Send(frame); } + + public void Flush() + { + _pump.Flush(); + } } class Connection: IConnection From f896acf06bfe81e697bf088c9599ed59574dbd14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Wed, 22 Apr 2020 22:35:06 +0200 Subject: [PATCH 73/76] doc. added --- Benchmarking/Benchmark/Benchmark.csproj | 4 ++-- Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj | 4 ++-- Capnp.Net.Runtime/FramePump.cs | 3 +++ Capnp.Net.Runtime/Rpc/IEndpoint.cs | 3 +++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Benchmarking/Benchmark/Benchmark.csproj b/Benchmarking/Benchmark/Benchmark.csproj index 0471ab5..5193d73 100644 --- a/Benchmarking/Benchmark/Benchmark.csproj +++ b/Benchmarking/Benchmark/Benchmark.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj index 57d08f5..cbc0e54 100644 --- a/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj +++ b/Benchmarking/EchoServiceCapnp/EchoServiceCapnp.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/Capnp.Net.Runtime/FramePump.cs b/Capnp.Net.Runtime/FramePump.cs index 71c611b..1184f46 100644 --- a/Capnp.Net.Runtime/FramePump.cs +++ b/Capnp.Net.Runtime/FramePump.cs @@ -121,6 +121,9 @@ namespace Capnp } } + /// + /// Flushes all buffered frames. + /// public void Flush() { if (Monitor.TryEnter(_writeLock)) diff --git a/Capnp.Net.Runtime/Rpc/IEndpoint.cs b/Capnp.Net.Runtime/Rpc/IEndpoint.cs index 02aa5d6..e7e37b6 100644 --- a/Capnp.Net.Runtime/Rpc/IEndpoint.cs +++ b/Capnp.Net.Runtime/Rpc/IEndpoint.cs @@ -10,6 +10,9 @@ /// void Forward(WireFrame frame); + /// + /// Indicates that the endpoint should flush any buffered frames. + /// void Flush(); /// From 044042dbdd81bb87f189e12bdf8e821304c7d18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Thu, 23 Apr 2020 07:34:02 +0200 Subject: [PATCH 74/76] made test more robust --- Capnp.Net.Runtime.Tests/Interception.cs | 4 ++-- Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index ab6b9f4..dee17a0 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -310,8 +310,8 @@ namespace Capnp.Net.Runtime.Tests Assert.IsTrue(cc.CancelFromAlice.IsCancellationRequested); cc.ForwardToBob(); - Assert.IsTrue(policy.Returns.ReceiveAsync().Wait(MediumNonDbgTimeout)); - Assert.IsTrue(cc.ReturnCanceled); + Assert.IsTrue(policy.Returns.ReceiveAsync().Wait(MediumNonDbgTimeout), "must return"); + Assert.IsTrue(cc.ReturnCanceled, "must be canceled"); cc.ReturnCanceled = false; cc.Exception = "Cancelled"; diff --git a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs index 5d19630..630d527 100644 --- a/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs +++ b/Capnp.Net.Runtime.Tests/Mock/TestCapImplementations.cs @@ -432,6 +432,7 @@ namespace Capnp.Net.Runtime.Tests.GenImpls public virtual Task Foo(uint i, bool j, CancellationToken cancellationToken) { Interlocked.Increment(ref _counters.CallCount); + cancellationToken.ThrowIfCancellationRequested(); Assert.AreEqual(123u, i); Assert.IsTrue(j); return Task.FromResult("foo"); From 3924fa0080929a3ebcf599f993b7cc8a3990049e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Thu, 23 Apr 2020 21:54:17 +0200 Subject: [PATCH 75/76] fixed cancelation race in test case InterceptClientSideOverrideCanceledCall --- Capnp.Net.Runtime.Tests/Interception.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/Interception.cs b/Capnp.Net.Runtime.Tests/Interception.cs index dee17a0..8eaaa4b 100644 --- a/Capnp.Net.Runtime.Tests/Interception.cs +++ b/Capnp.Net.Runtime.Tests/Interception.cs @@ -301,10 +301,10 @@ namespace Capnp.Net.Runtime.Tests client.WhenConnected.Wait(); var counters = new Counters(); - server.Main = new TestInterfaceImpl(counters); - using (var main = policy.Attach(client.GetMain())) + server.Main = new TestMoreStuffImpl(counters); + using (var main = policy.Attach(client.GetMain())) { - var request1 = main.Foo(321, false, new CancellationToken(true)); + var request1 = main.NeverReturn(new TestInterfaceImpl(new Counters()), new CancellationToken(true)); Assert.IsTrue(policy.Calls.TryReceive(out var cc)); Assert.IsFalse(request1.IsCompleted); Assert.IsTrue(cc.CancelFromAlice.IsCancellationRequested); From 0b8e32edf9f6916aa3be1548735bb889911503c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Thu, 23 Apr 2020 22:34:45 +0200 Subject: [PATCH 76/76] factored StrictlyOrderedAwaitTask into resolving proxy tasks --- Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs | 2 +- Capnp.Net.Runtime.Tests/TcpRpc.cs | 26 ++++++++-------- .../TcpRpcAdvancedStuff.cs | 2 +- Capnp.Net.Runtime.Tests/TcpRpcInterop.cs | 10 +++--- Capnp.Net.Runtime.Tests/TcpRpcPorted.cs | 4 +-- Capnp.Net.Runtime.Tests/TcpRpcStress.cs | 2 +- Capnp.Net.Runtime.Tests/Testsuite.cs | 31 +++++++------------ Capnp.Net.Runtime/Rpc/IResolvingCapability.cs | 5 +-- Capnp.Net.Runtime/Rpc/LazyCapability.cs | 10 +++--- .../Rpc/LocalAnswerCapability.cs | 8 ++--- Capnp.Net.Runtime/Rpc/PromisedCapability.cs | 8 ++--- Capnp.Net.Runtime/Rpc/Proxy.cs | 7 +++-- .../Rpc/RemoteAnswerCapability.cs | 8 ++--- .../Rpc/RemoteResolvingCapability.cs | 2 +- 14 files changed, 59 insertions(+), 66 deletions(-) diff --git a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs index a48e1a4..225b5b8 100644 --- a/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs +++ b/Capnp.Net.Runtime.Tests/EdgeCaseHandling.cs @@ -1284,7 +1284,7 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(Message.WHICH.Finish, _.which); }); Assert.IsTrue(proxy.WhenResolved.IsCompleted); - Assert.IsTrue(proxy.WhenResolved.IsFaulted); + Assert.IsTrue(proxy.WhenResolved.WrappedTask.IsFaulted); tester.ExpectAbort(); } diff --git a/Capnp.Net.Runtime.Tests/TcpRpc.cs b/Capnp.Net.Runtime.Tests/TcpRpc.cs index f419f33..fe89a30 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpc.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpc.cs @@ -79,7 +79,7 @@ namespace Capnp.Net.Runtime.Tests server.Main = new ProvidedCapabilityMock(); var main = client.GetMain(); var resolving = main as IResolvingCapability; - Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(resolving.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); } } @@ -97,7 +97,7 @@ namespace Capnp.Net.Runtime.Tests var main = client.GetMain(); var resolving = main as IResolvingCapability; - Assert.IsTrue(Assert.ThrowsExceptionAsync(() => resolving.WhenResolved).Wait(MediumNonDbgTimeout)); + Assert.IsTrue(Assert.ThrowsExceptionAsync(() => resolving.WhenResolved.WrappedTask).Wait(MediumNonDbgTimeout)); } } @@ -116,7 +116,7 @@ namespace Capnp.Net.Runtime.Tests var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(main.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); @@ -157,7 +157,7 @@ namespace Capnp.Net.Runtime.Tests var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(main.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); @@ -197,7 +197,7 @@ namespace Capnp.Net.Runtime.Tests server.Main = mock; var main = client.GetMain(); var resolving = main as IResolvingCapability; - Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(resolving.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); @@ -240,7 +240,7 @@ namespace Capnp.Net.Runtime.Tests var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(main.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); @@ -300,7 +300,7 @@ namespace Capnp.Net.Runtime.Tests var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(main.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); @@ -337,7 +337,7 @@ namespace Capnp.Net.Runtime.Tests var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(main.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); @@ -410,7 +410,7 @@ namespace Capnp.Net.Runtime.Tests var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(main.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); @@ -486,7 +486,7 @@ namespace Capnp.Net.Runtime.Tests var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(main.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); @@ -603,7 +603,7 @@ namespace Capnp.Net.Runtime.Tests var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(main.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); @@ -650,7 +650,7 @@ namespace Capnp.Net.Runtime.Tests var mock = new ProvidedCapabilityMock(); server.Main = mock; var main = client.GetMain(); - Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(main.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var args = DynamicSerializerState.CreateForRpc(); args.SetStruct(1, 0); args.WriteData(0, 123456); @@ -746,7 +746,7 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(c1, server.Connections[0]); Assert.AreEqual(ConnectionState.Active, c1.State); var proxy = client1.GetMain(); - Assert.IsTrue(proxy is IResolvingCapability r && r.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(proxy is IResolvingCapability r && r.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); Assert.IsTrue(c1.RecvCount > 0); Assert.IsTrue(c1.SendCount > 0); diff --git a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs index 1e81bf4..a94ca6e 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcAdvancedStuff.cs @@ -116,7 +116,7 @@ namespace Capnp.Net.Runtime.Tests try { - Assert.IsTrue(((IResolvingCapability)main).WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(((IResolvingCapability)main).WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); } catch (AggregateException) { diff --git a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs index de99fa4..ca821b9 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcInterop.cs @@ -310,7 +310,7 @@ namespace Capnp.Net.Runtime.Tests using (var main = client.GetMain()) { - ((Proxy)main).WhenResolved.Wait(MediumNonDbgTimeout); + ((Proxy)main).WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout); async Task VerifyOutput() { @@ -896,7 +896,7 @@ namespace Capnp.Net.Runtime.Tests try { - success = resolving.WhenResolved.Wait(MediumNonDbgTimeout); + success = resolving.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout); } catch { @@ -986,7 +986,7 @@ namespace Capnp.Net.Runtime.Tests using (var main = client.GetMain()) { var resolving = main as IResolvingCapability; - Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(resolving.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var cap = new TaskCompletionSource(); @@ -1088,7 +1088,7 @@ namespace Capnp.Net.Runtime.Tests try { - success = resolving.WhenResolved.Wait(MediumNonDbgTimeout); + success = resolving.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout); } catch { @@ -1158,7 +1158,7 @@ namespace Capnp.Net.Runtime.Tests using (var main = client.GetMain()) { var resolving = main as IResolvingCapability; - Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(resolving.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); var tcs = new TaskCompletionSource(); diff --git a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs index 3e24333..5dd9132 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcPorted.cs @@ -49,7 +49,7 @@ namespace Capnp.Net.Runtime.Tests server.Main = new TestMoreStuffImpl(counters); using (var main = client.GetMain()) { - ((Proxy)main).WhenResolved.Wait(MediumNonDbgTimeout); + ((Proxy)main).WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout); // Since we have a threaded model, there is no way to deterministically provoke the situation // where Cancel and Finish message cross paths. Instead, we'll do a lot of such requests and @@ -158,7 +158,7 @@ namespace Capnp.Net.Runtime.Tests { using (var main = client.GetMain()) { - ((Proxy)main).WhenResolved.Wait(MediumNonDbgTimeout); + ((Proxy)main).WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout); } Assert.IsFalse(impl.IsDisposed); } diff --git a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs index 7424277..2610677 100644 --- a/Capnp.Net.Runtime.Tests/TcpRpcStress.cs +++ b/Capnp.Net.Runtime.Tests/TcpRpcStress.cs @@ -43,7 +43,7 @@ namespace Capnp.Net.Runtime.Tests using (var main = client.GetMain()) { var resolving = main as IResolvingCapability; - Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout)); + Assert.IsTrue(resolving.WhenResolved.WrappedTask.Wait(MediumNonDbgTimeout)); } } }); diff --git a/Capnp.Net.Runtime.Tests/Testsuite.cs b/Capnp.Net.Runtime.Tests/Testsuite.cs index 29dbfd1..5240f1d 100644 --- a/Capnp.Net.Runtime.Tests/Testsuite.cs +++ b/Capnp.Net.Runtime.Tests/Testsuite.cs @@ -65,7 +65,7 @@ namespace Capnp.Net.Runtime.Tests using (var main = testbed.ConnectMain(impl)) { if (main is IResolvingCapability resolving) - testbed.MustComplete(resolving.WhenResolved); + testbed.MustComplete(resolving.WhenResolved.WrappedTask); var cap = new TestCallOrderImpl(); cap.CountToDispose = 6; @@ -92,20 +92,12 @@ namespace Capnp.Net.Runtime.Tests var call4 = pipeline.GetCallSequence(4, default); var call5 = pipeline.GetCallSequence(5, default); - try - { - testbed.MustComplete(call0); - testbed.MustComplete(call1); - testbed.MustComplete(call2); - testbed.MustComplete(call3); - testbed.MustComplete(call4); - testbed.MustComplete(call5); - } - catch (System.Exception) - { - cap.CountToDispose = null; - throw; - } + testbed.MustComplete(call0); + testbed.MustComplete(call1); + testbed.MustComplete(call2); + testbed.MustComplete(call3); + testbed.MustComplete(call4); + testbed.MustComplete(call5); Assert.AreEqual(0u, call0.Result); Assert.AreEqual(1u, call1.Result); @@ -113,6 +105,7 @@ namespace Capnp.Net.Runtime.Tests Assert.AreEqual(3u, call3.Result); Assert.AreEqual(4u, call4.Result); Assert.AreEqual(5u, call5.Result); + Assert.AreEqual(cap.Count, cap.CountToDispose, "counter must have reached number of calls"); } } } @@ -182,7 +175,7 @@ namespace Capnp.Net.Runtime.Tests using (var main = testbed.ConnectMain(impl)) { if (main is IResolvingCapability resolving) - testbed.MustComplete(resolving.WhenResolved); + testbed.MustComplete(resolving.WhenResolved.WrappedTask); var cap = new TaskCompletionSource(); @@ -223,7 +216,7 @@ namespace Capnp.Net.Runtime.Tests using (var main = testbed.ConnectMain(impl)) { if (main is IResolvingCapability resolving) - testbed.MustComplete(resolving.WhenResolved); + testbed.MustComplete(resolving.WhenResolved.WrappedTask); var promise = main.GetNull(default); @@ -250,7 +243,7 @@ namespace Capnp.Net.Runtime.Tests using (var main = testbed.ConnectMain(impl)) { if (main is IResolvingCapability resolving) - testbed.MustComplete(resolving.WhenResolved); + testbed.MustComplete(resolving.WhenResolved.WrappedTask); var tcs = new TaskCompletionSource(); @@ -770,7 +763,7 @@ namespace Capnp.Net.Runtime.Tests peer.EnableEcho(); - testbed.MustComplete(r.WhenResolved); + testbed.MustComplete(r.WhenResolved.WrappedTask); heldTask.Result.Dispose(); } diff --git a/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs b/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs index b3dc986..f041890 100644 --- a/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/IResolvingCapability.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using Capnp.Util; +using System.Threading.Tasks; namespace Capnp.Rpc { @@ -10,7 +11,7 @@ namespace Capnp.Rpc /// /// Completes when the capability gets resolved. /// - Task WhenResolved { get; } + StrictlyOrderedAwaitTask WhenResolved { get; } /// /// Returns the resolved capability diff --git a/Capnp.Net.Runtime/Rpc/LazyCapability.cs b/Capnp.Net.Runtime/Rpc/LazyCapability.cs index 5c1f7f7..d1e2f4a 100644 --- a/Capnp.Net.Runtime/Rpc/LazyCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LazyCapability.cs @@ -18,7 +18,7 @@ namespace Capnp.Rpc return new LazyCapability(Task.FromCanceled(token)); } - readonly Task? _proxyTask; + readonly StrictlyOrderedAwaitTask? _proxyTask; readonly StrictlyOrderedAwaitTask _capTask; public LazyCapability(Task capabilityTask) @@ -28,7 +28,7 @@ namespace Capnp.Rpc public LazyCapability(Task proxyTask) { - _proxyTask = proxyTask; + _proxyTask = proxyTask.EnforceAwaitOrder(); async Task AwaitCap() => (await _proxyTask!).ConsumedCap; @@ -37,7 +37,7 @@ namespace Capnp.Rpc internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { - if (WhenResolved.ReplacementTaskIsCompletedSuccessfully()) + if (WhenResolved.IsCompleted && WhenResolved.WrappedTask.ReplacementTaskIsCompletedSuccessfully()) { using var proxy = GetResolvedCapability()!; return proxy.Export(endpoint, writer); @@ -62,9 +62,7 @@ namespace Capnp.Rpc } } - async Task AwaitWhenResolved() => await _capTask; - - public Task WhenResolved => AwaitWhenResolved(); + public StrictlyOrderedAwaitTask WhenResolved => _capTask; public T? GetResolvedCapability() where T: class { diff --git a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs index 17d9c0c..f615ec5 100644 --- a/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/LocalAnswerCapability.cs @@ -17,11 +17,11 @@ namespace Capnp.Rpc return proxy; } - readonly Task _whenResolvedProxy; + readonly StrictlyOrderedAwaitTask _whenResolvedProxy; public LocalAnswerCapability(Task proxyTask) { - _whenResolvedProxy = proxyTask; + _whenResolvedProxy = proxyTask.EnforceAwaitOrder(); } public LocalAnswerCapability(StrictlyOrderedAwaitTask answer, MemberAccessPath access): @@ -30,9 +30,9 @@ namespace Capnp.Rpc } - public Task WhenResolved => _whenResolvedProxy; + public StrictlyOrderedAwaitTask WhenResolved => _whenResolvedProxy; - public T? GetResolvedCapability() where T : class => _whenResolvedProxy.GetResolvedCapability(); + public T? GetResolvedCapability() where T : class => _whenResolvedProxy.WrappedTask.GetResolvedCapability(); internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { diff --git a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs index 74b5849..652dc71 100644 --- a/Capnp.Net.Runtime/Rpc/PromisedCapability.cs +++ b/Capnp.Net.Runtime/Rpc/PromisedCapability.cs @@ -10,7 +10,7 @@ namespace Capnp.Rpc readonly uint _remoteId; readonly object _reentrancyBlocker = new object(); readonly TaskCompletionSource _resolvedCap = new TaskCompletionSource(); - readonly Task _whenResolvedProxy; + readonly StrictlyOrderedAwaitTask _whenResolvedProxy; bool _released; public PromisedCapability(IRpcEndpoint ep, uint remoteId): base(ep) @@ -18,11 +18,11 @@ namespace Capnp.Rpc _remoteId = remoteId; async Task AwaitProxy() => new Proxy(await _resolvedCap.Task); - _whenResolvedProxy = AwaitProxy(); + _whenResolvedProxy = AwaitProxy().EnforceAwaitOrder(); } - public override Task WhenResolved => _resolvedCap.Task; - public override T? GetResolvedCapability() where T: class => _whenResolvedProxy.GetResolvedCapability(); + public override StrictlyOrderedAwaitTask WhenResolved => _whenResolvedProxy; + public override T? GetResolvedCapability() where T: class => _whenResolvedProxy.WrappedTask.GetResolvedCapability(); internal override Action? Export(IRpcEndpoint endpoint, CapDescriptor.WRITER writer) { diff --git a/Capnp.Net.Runtime/Rpc/Proxy.cs b/Capnp.Net.Runtime/Rpc/Proxy.cs index 57f70ce..715b341 100644 --- a/Capnp.Net.Runtime/Rpc/Proxy.cs +++ b/Capnp.Net.Runtime/Rpc/Proxy.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Logging; +using Capnp.Util; +using Microsoft.Extensions.Logging; using System; using System.Diagnostics; using System.Threading; @@ -31,12 +32,12 @@ namespace Capnp.Rpc /// /// Completes when the capability gets resolved. /// - public Task WhenResolved + public StrictlyOrderedAwaitTask WhenResolved { get { return ConsumedCap is IResolvingCapability resolving ? - resolving.WhenResolved : Task.CompletedTask; + resolving.WhenResolved : Task.CompletedTask.EnforceAwaitOrder(); } } diff --git a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs index 9b0b248..d09bd49 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteAnswerCapability.cs @@ -17,13 +17,13 @@ namespace Capnp.Rpc readonly PendingQuestion _question; readonly MemberAccessPath _access; - readonly Task _whenResolvedProxy; + readonly StrictlyOrderedAwaitTask _whenResolvedProxy; public RemoteAnswerCapability(PendingQuestion question, MemberAccessPath access, Task proxyTask) : base(question.RpcEndpoint) { _question = question ?? throw new ArgumentNullException(nameof(question)); _access = access ?? throw new ArgumentNullException(nameof(access)); - _whenResolvedProxy = proxyTask ?? throw new ArgumentNullException(nameof(proxyTask)); + _whenResolvedProxy = (proxyTask ?? throw new ArgumentNullException(nameof(proxyTask))).EnforceAwaitOrder(); } static async Task TransferOwnershipToDummyProxy(PendingQuestion question, MemberAccessPath access) @@ -85,9 +85,9 @@ namespace Capnp.Rpc } } - public override Task WhenResolved => _whenResolvedProxy; + public override StrictlyOrderedAwaitTask WhenResolved => _whenResolvedProxy; - public override T? GetResolvedCapability() where T: class => _whenResolvedProxy.GetResolvedCapability(); + public override T? GetResolvedCapability() where T: class => _whenResolvedProxy.WrappedTask.GetResolvedCapability(); protected override void GetMessageTarget(MessageTarget.WRITER wr) { diff --git a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs index 0dc9ac7..0c39e5c 100644 --- a/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs +++ b/Capnp.Net.Runtime/Rpc/RemoteResolvingCapability.cs @@ -17,7 +17,7 @@ namespace Capnp.Rpc ILogger Logger { get; } = Logging.CreateLogger(); #endif - public abstract Task WhenResolved { get; } + public abstract StrictlyOrderedAwaitTask WhenResolved { get; } public abstract T? GetResolvedCapability() where T : class; protected RemoteResolvingCapability(IRpcEndpoint ep) : base(ep)