diff --git a/compiler/src/main/cpp/capnpc-java.c++ b/compiler/src/main/cpp/capnpc-java.c++ index 3c3b39d..996e2f1 100644 --- a/compiler/src/main/cpp/capnpc-java.c++ +++ b/compiler/src/main/cpp/capnpc-java.c++ @@ -711,6 +711,7 @@ private: struct FieldText { kj::StringTree readerMethodDecls; kj::StringTree builderMethodDecls; + kj::StringTree pipelineMethodDecls; }; enum class FieldKind { @@ -869,7 +870,10 @@ private: " return new ", scope, titleCase, ".Builder(segment, data, pointers, dataSize, pointerCount);\n", spaces(indent), " }\n", - "\n") + "\n"), + + // TODO pipelineMethodDecls + kj::strTree() }; } } @@ -1028,7 +1032,7 @@ private: } else if (kind == FieldKind::INTERFACE) { auto factoryArg = kj::str(typeName(field.getType()), ".factory"); - auto capType = kj::str(typeName(field.getType()), ".Client"); + auto clientType = kj::str(typeName(field.getType()), ".Client"); return FieldText { kj::strTree( @@ -1038,7 +1042,7 @@ private: spaces(indent), " return !_pointerFieldIsNull(", offset, ");\n", spaces(indent), " }\n", - spaces(indent), " public ", capType, " get", titleCase, "() {\n", + spaces(indent), " public ", clientType, " get", titleCase, "() {\n", unionDiscrim.check, spaces(indent), " return _getPointerField(", factoryArg, ", ", offset, ");\n", spaces(indent), " }\n"), @@ -1049,17 +1053,23 @@ private: spaces(indent), " return !_pointerFieldIsNull(", offset, ");\n", spaces(indent), " }\n", - spaces(indent), " public ", capType, " get", titleCase, "() {\n", + spaces(indent), " public ", clientType, " get", titleCase, "() {\n", unionDiscrim.check, spaces(indent), " return _getPointerField(", factoryArg, ", ", offset, ");\n", spaces(indent), " }\n", - spaces(indent), " public void set", titleCase, "(", capType, " value) {\n", + spaces(indent), " public void set", titleCase, "(", clientType, " value) {\n", unionDiscrim.set, spaces(indent), " _initPointerField(", factoryArg, ", ", offset, ", 0);\n", spaces(indent), " }\n", - "\n") - }; + "\n"), + + kj::strTree( + spaces(indent), " public ", clientType, " get", titleCase, "() {\n", + spaces(indent), " return new ", clientType, "(typeless.getPointerField((short)", offset, ").asCap());\n", + spaces(indent), " }\n" + ) + }; } else if (kind == FieldKind::ANY_POINTER) { auto factoryArg = makeFactoryArg(field.getType()); @@ -1563,7 +1573,16 @@ private: spaces(indent), " _NOT_IN_SCHEMA,\n", spaces(indent), " }\n"), KJ_MAP(n, nestedTypeDecls) { return kj::mv(n); }, - spaces(indent), "}\n" + + spaces(indent), " public static class Pipeline {\n", + spaces(indent), " private org.capnproto.AnyPointer.Pipeline typeless;\n\n", + spaces(indent), " public Pipeline() {}\n", + spaces(indent), " public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) {\n", + spaces(indent), " this.typeless = typeless;\n", + spaces(indent), " }\n", + KJ_MAP(f, fieldTexts) { return kj::mv(f.pipelineMethodDecls); }, + spaces(indent), " }\n", + spaces(indent), "}\n", "\n", "\n"), @@ -1571,6 +1590,7 @@ private: kj::strTree() }; } + // ----------------------------------------------------------------- struct InterfaceText { diff --git a/runtime/src/main/java/org/capnproto/AnyPointer.java b/runtime/src/main/java/org/capnproto/AnyPointer.java index feb304e..2f45285 100644 --- a/runtime/src/main/java/org/capnproto/AnyPointer.java +++ b/runtime/src/main/java/org/capnproto/AnyPointer.java @@ -143,4 +143,46 @@ public final class AnyPointer { } } + public static final class Pipeline { + private PipelineHook hook; + private final PipelineOp[] ops; + + Pipeline() { + this.hook = null; + this.ops = new PipelineOp[0]; + } + + Pipeline(PipelineHook hook) { + this.hook = hook; + this.ops = new PipelineOp[0]; + } + + Pipeline(PipelineHook hook, PipelineOp[] ops) { + this.hook = hook; + this.ops = ops; + } + + Pipeline noop() { + return new Pipeline(this.hook, this.ops.clone()); + } + + public ClientHook asCap() { + return this.hook.getPipelinedCap(this.ops); + } + + PipelineHook releasePipelineHook() { + var tmp = this.hook; + this.hook = null; + return tmp; + } + + public Pipeline getPointerField(short pointerIndex) { + var newOps = new PipelineOp[this.ops.length+1]; + for (int ii = 0; ii < this.ops.length; ++ii) { + newOps[ii] = this.ops[ii]; + } + newOps[this.ops.length] = PipelineOp.PointerField(pointerIndex); + return new Pipeline(this.hook, newOps); + } + } } diff --git a/runtime/src/main/java/org/capnproto/Capability.java b/runtime/src/main/java/org/capnproto/Capability.java index f711e83..c270d37 100644 --- a/runtime/src/main/java/org/capnproto/Capability.java +++ b/runtime/src/main/java/org/capnproto/Capability.java @@ -267,7 +267,7 @@ public final class Capability { return context.response; }); - return new RemotePromise(promise, promiseAndPipeline.pipeline); + return new RemotePromise<>(promise, promiseAndPipeline.pipeline); } @Override diff --git a/runtime/src/main/java/org/capnproto/RemotePromise.java b/runtime/src/main/java/org/capnproto/RemotePromise.java index ab278bc..ae4ad2e 100644 --- a/runtime/src/main/java/org/capnproto/RemotePromise.java +++ b/runtime/src/main/java/org/capnproto/RemotePromise.java @@ -13,6 +13,7 @@ class RemotePromise { this.pipeline = pipeline; } + public CompletableFuture> getResponse() { return response; } diff --git a/runtime/src/main/java/org/capnproto/Request.java b/runtime/src/main/java/org/capnproto/Request.java index 6573f7b..020eb01 100644 --- a/runtime/src/main/java/org/capnproto/Request.java +++ b/runtime/src/main/java/org/capnproto/Request.java @@ -28,7 +28,7 @@ public class Request { var typedPromise = typelessPromise.getResponse().thenApply(response -> { return new Response( resultsReader, - response.get(), + response.getResults(), response.hook); }); diff --git a/runtime/src/main/java/org/capnproto/Response.java b/runtime/src/main/java/org/capnproto/Response.java index ee6c038..c89e97f 100644 --- a/runtime/src/main/java/org/capnproto/Response.java +++ b/runtime/src/main/java/org/capnproto/Response.java @@ -14,7 +14,7 @@ class Response { this.results = reader; } - public final Results get() { + public final Results getResults() { return this.results.getAs(factory); } } \ No newline at end of file diff --git a/runtime/src/test/java/org/capnproto/TwoPartyTest.java b/runtime/src/test/java/org/capnproto/TwoPartyTest.java index 56b01b6..d2806be 100644 --- a/runtime/src/test/java/org/capnproto/TwoPartyTest.java +++ b/runtime/src/test/java/org/capnproto/TwoPartyTest.java @@ -120,6 +120,32 @@ class TestCap0Impl extends TestCap0.Server { class TestCap1Impl extends TestCap1.Server { } +class Iface0Impl extends Demo.Iface0.Server { + @Override + protected CompletableFuture method0(CallContext context) { + System.out.println("Called Iface0.method0"); + return CompletableFuture.completedFuture(null); + } + + @Override + protected CompletableFuture method1(StreamingCallContext context) { + return super.method1(context); + } +} +class Iface1Impl extends Demo.Iface1.Server { + @Override + protected CompletableFuture method0(CallContext context) { + return super.method0(context); + } + + @Override + protected CompletableFuture method1(CallContext context) { + context.getResults().setResult0(new Demo.Iface0.Client(new Iface0Impl())); + System.out.println("Called Iface0.method0"); + return CompletableFuture.completedFuture(null); + } +} + public class TwoPartyTest { AsynchronousServerSocketChannel serverSocket; @@ -163,13 +189,13 @@ public class TwoPartyTest { var request = demoClient.testMethod0Request(); var params = request.params(); params.setParam0(4321); - var resultsPromise = request.send(); - while (!resultsPromise.isDone()) { - CompletableFuture.anyOf(resultsPromise, server.runOnce()).join(); + var promise = request.send(); + while (!promise.response.isDone()) { + CompletableFuture.anyOf(promise.response, server.runOnce()).join(); } - Assert.assertTrue(resultsPromise.isDone()); - var results = resultsPromise.get(); - Assert.assertEquals(params.getParam0(), results.getResult0()); + Assert.assertTrue(promise.response.isDone()); + var response = promise.response.get(); + Assert.assertEquals(params.getParam0(), response.getResults().getResult0()); } @Test @@ -181,12 +207,14 @@ public class TwoPartyTest { var demoClient = new TestCap0.Client(this.client.bootstrap()); var request = demoClient.testMethod1Request(); var params = request.params(); - var resultsPromise = request.send(); - while (!resultsPromise.isDone()) { - CompletableFuture.anyOf(resultsPromise, server.runOnce(), client.runOnce()).join(); + var promise = request.send(); + while (!promise.response.isDone()) { + CompletableFuture.anyOf(promise.response, server.runOnce(), client.runOnce()).join(); } - Assert.assertTrue(resultsPromise.isDone()); - var results = resultsPromise.get(); + Assert.assertTrue(promise.response.isDone()); + + var response = promise.response.get(); + var results = response.getResults(); var cap0 = results.getResult0(); Assert.assertFalse(cap0.isNull()); var cap1 = results.getResult1(); @@ -202,7 +230,10 @@ public class TwoPartyTest { var request = client.testMethod0Request(); var params = request.params(); params.setParam0(4321); - var results = request.send().get(); + var promise = request.send(); + var future = promise.getResponse(); + var response = future.get(); + var results = response.getResults(); Assert.assertEquals(params.getParam0(), results.getResult0()); } @@ -212,8 +243,18 @@ public class TwoPartyTest { var client = new TestCap0.Client(demo); var request = client.testMethod0Request(); var params = request.params(); - params.setParam0(4321); - var results = request.send().get(); + var promise = request.send(); + var future = promise.getResponse(); + var response = future.get(); + var results = response.getResults(); Assert.assertEquals(params.getParam0(), results.getResult0()); } + + @Test + public void testTwoStagePipeline() { + var iface1Client = new Demo.Iface1.Client(new Iface1Impl()); + var request = iface1Client.method1Request(); + var response = request.send(); + + } } \ No newline at end of file diff --git a/runtime/src/test/java/org/capnproto/demo/Demo.java b/runtime/src/test/java/org/capnproto/demo/Demo.java index 1f70ba4..a84b8f5 100644 --- a/runtime/src/test/java/org/capnproto/demo/Demo.java +++ b/runtime/src/test/java/org/capnproto/demo/Demo.java @@ -52,6 +52,14 @@ public final class Demo { } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -103,6 +111,14 @@ public final class Demo { } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -162,6 +178,14 @@ public final class Demo { } } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -259,6 +283,14 @@ public final class Demo { } } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -310,6 +342,14 @@ public final class Demo { } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -414,6 +454,14 @@ public final class Demo { } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -454,6 +502,14 @@ public final class Demo { } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -494,6 +550,14 @@ public final class Demo { } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -572,6 +636,17 @@ public final class Demo { } } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + public org.capnproto.demo.Demo.Iface0.Client getF1i() { + return new org.capnproto.demo.Demo.Iface0.Client(typeless.getPointerField((short)1).asCap()); + } + } } @@ -706,6 +781,14 @@ public final class Demo { } } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -746,6 +829,14 @@ public final class Demo { } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -818,6 +909,14 @@ public final class Demo { } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -858,6 +957,14 @@ public final class Demo { } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + } } @@ -914,6 +1021,17 @@ public final class Demo { } } + public static class Pipeline { + private org.capnproto.AnyPointer.Pipeline typeless; + + public Pipeline() {} + public Pipeline(org.capnproto.AnyPointer.Pipeline typeless) { + this.typeless = typeless; + } + public org.capnproto.demo.Demo.Iface0.Client getResult0() { + return new org.capnproto.demo.Demo.Iface0.Client(typeless.getPointerField((short)0).asCap()); + } + } }