diff --git a/compiler/src/main/cpp/capnpc-java.c++ b/compiler/src/main/cpp/capnpc-java.c++ index 5130646..723901d 100644 --- a/compiler/src/main/cpp/capnpc-java.c++ +++ b/compiler/src/main/cpp/capnpc-java.c++ @@ -381,6 +381,7 @@ private: return kj::strTree("org.capnproto.ListList.", suffix, "<", kj::mv(inner), ">"); } case schema::Type::INTERFACE: + return kj::strTree("org.capnproto.PrimitiveList.Void.", suffix); case schema::Type::ANY_POINTER: KJ_FAIL_REQUIRE("unimplemented"); } @@ -811,6 +812,23 @@ private: return kj::str(typeName(type, kj::str("factory"))); } } + case schema::Type::INTERFACE: { + auto interfaceSchema = type.asInterface(); + auto node = interfaceSchema.getProto(); + if (node.getIsGeneric()) { + auto factoryArgs = getFactoryArguments(interfaceSchema, interfaceSchema); + return kj::strTree( + javaFullName(interfaceSchema), ".newFactory(", + kj::StringTree( + KJ_MAP(arg, factoryArgs) { + return kj::strTree(arg); + }, ","), + ")" + ).flatten(); + } else { + return kj::str(typeName(type, kj::str("factory"))); + } + } default: KJ_UNREACHABLE; } @@ -1030,8 +1048,8 @@ private: }; } else if (kind == FieldKind::INTERFACE) { - - auto factoryArg = kj::str(typeName(field.getType()), ".factory"); + + auto factoryArg = makeFactoryArg(field.getType()); auto clientType = kj::str(typeName(field.getType()), ".Client"); return FieldText { @@ -1627,10 +1645,88 @@ private: auto typeName = javaFullName(schema); + + kj::String genericParamTypes; + if (proto.getIsGeneric()) { + auto typeParams = getTypeParameters(schema); + genericParamTypes = kj::strTree( + "<", + kj::StringTree( + KJ_MAP(arg, typeParams) { + return kj::strTree(arg); + }, ", "), + ">").flatten(); + } + else { + genericParamTypes = kj::str(""); + } + + auto typeParamVec = getTypeParameters(schema); + bool hasTypeParams = typeParamVec.size() > 0; + + kj::StringTree readerTypeParamsTree; + kj::StringTree builderTypeParamsTree; + kj::StringTree factoryTypeParamsTree; + if (hasTypeParams) { + builderTypeParamsTree = kj::strTree( + "<", + kj::StringTree(KJ_MAP(p, typeParamVec) { + return kj::strTree(p, "_Builder"); + }, ", "), + ">"); + readerTypeParamsTree = kj::strTree( + "<", + kj::StringTree(KJ_MAP(p, typeParamVec) { + return kj::strTree(p, "_Reader"); + }, ", "), + ">"); + + factoryTypeParamsTree = kj::strTree( + "<", + kj::StringTree(KJ_MAP(p, typeParamVec) { + return kj::strTree(p, "_Builder, ", p, "_Reader"); + }, ", "), + ">"); + } + kj::String readerTypeParams = readerTypeParamsTree.flatten(); + auto readerTypeParamsInferred = (hasTypeParams ? "<>" : ""); + kj::String builderTypeParams = builderTypeParamsTree.flatten(); + kj::String factoryTypeParams = factoryTypeParamsTree.flatten(); + + kj::StringTree factoryArgs = kj::StringTree(KJ_MAP(p, typeParamVec) { + return kj::strTree("org.capnproto.PointerFactory<", p, "_Builder, ", p, "_Reader> ", p, "_Factory"); + }, ", "); + + kj::StringTree factoryMembers = kj::strTree(KJ_MAP(p, typeParamVec) { + return kj::strTree(spaces(indent), " final org.capnproto.PointerFactory<", p, "_Builder, ", p, "_Reader> ", p, "_Factory;\n"); + }); + + kj::String factoryRef = hasTypeParams + ? kj::str(kj::strTree("newFactory(", + kj::StringTree(KJ_MAP(p, typeParamVec) { + return kj::strTree(p, "_Factory"); + }, ", ") + , ")")) + : kj::str("factory"); + + return InterfaceText { kj::strTree( - spaces(indent), "public static class ", name, " {\n", - spaces(indent), " public static final class Factory extends org.capnproto.Capability.Factory {\n", + spaces(indent), "public static class ", name, genericParamTypes, " {\n", + + spaces(indent), " public static final class Factory", factoryTypeParams, "\n", + spaces(indent), " extends org.capnproto.Capability.Factory {\n", + factoryMembers.flatten(), + spaces(indent), " public Factory(", + factoryArgs.flatten(), + ") {\n", + KJ_MAP(p, typeParamVec) { + return kj::strTree(spaces(indent), " this.", p, "_Factory = ", p, "_Factory;\n"); + }, + spaces(indent), " }\n", + + + //spaces(indent), " public static final class Factory extends org.capnproto.Capability.Factory {\n", spaces(indent), " public final Client newClient(org.capnproto.ClientHook hook) {\n", spaces(indent), " return new Client(hook);\n", spaces(indent), " }\n", @@ -1712,8 +1808,7 @@ private: paramType = kj::str(titleCase, "Params"); genericParamType = kj::str(paramType); } else { - KJ_FAIL_REQUIRE("Generic interfaces not supported"); - //genericParamType = paramType; + genericParamType = kj::str(paramType); //genericParamType.addMemberTemplate(kj::str(titleCase, "Params"), nullptr); //paramType.addMemberTemplate(kj::str(titleCase, "Params"), // kj::heapArray(implicitParams.asPtr())); @@ -1734,8 +1829,7 @@ private: resultType = kj::str(titleCase, "Results"); genericResultType = kj::str(resultType); } else { - KJ_FAIL_REQUIRE("Generic interfaces not supported"); - //genericResultType = resultType; + genericResultType = kj::str(resultType); //genericResultType.addMemberTemplate(kj::str(titleCase, "Results"), nullptr); //resultType.addMemberTemplate(kj::str(titleCase, "Results"), // kj::heapArray(implicitParams.asPtr())); @@ -1761,6 +1855,28 @@ private: kj::String paramFactory = kj::str(shortParamType, ".factory"); kj::String resultFactory = kj::str(shortResultType, ".factory"); + if (paramProto.getIsGeneric()) { + auto paramFactoryArgs = getFactoryArguments(paramSchema, paramSchema); + paramFactory = paramFactoryArgs.size() == 0 + ? kj::str(shortParamType, ".factory") + : kj::strTree("newFactory(", + kj::StringTree(KJ_MAP(arg, paramFactoryArgs) { + return kj::strTree(arg); + }, ", "), + ")").flatten(); + } + + if (resultProto.getIsGeneric()) { + auto resultFactoryArgs = getFactoryArguments(resultSchema, paramSchema); + resultFactory = resultFactoryArgs.size() == 0 + ? kj::str(shortResultType, ".factory") + : kj::strTree("newFactory(", + kj::StringTree(KJ_MAP(arg, resultFactoryArgs) { + return kj::strTree(arg); + }, ", "), + ")").flatten(); + } + auto interfaceProto = method.getContainingInterface().getProto(); uint64_t interfaceId = interfaceProto.getId(); auto interfaceIdHex = kj::hex(interfaceId); diff --git a/runtime/src/test/java/org/capnproto/LocalCapabilityTest.java b/runtime/src/test/java/org/capnproto/LocalCapabilityTest.java deleted file mode 100644 index 716d9a1..0000000 --- a/runtime/src/test/java/org/capnproto/LocalCapabilityTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.capnproto; - -import org.capnproto.demo.Demo; -import org.junit.Assert; -import org.junit.Test; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -public class LocalCapabilityTest { - - @Test - public void testLocalServer() throws ExecutionException, InterruptedException { - var demo = new TestCap0Impl(); - var client = new Demo.TestCap0.Client(demo); - var request = client.testMethod0Request(); - var params = request.getParams(); - params.setParam0(4321); - var response = request.send(); - var results = response.get(); - Assert.assertEquals(params.getParam0(), results.getResult0()); - } - - @Test - public void testGenericServer() throws ExecutionException, InterruptedException { - var demo = new TestCap0Impl(); - var client = new Demo.TestCap0.Client(demo); - var request = client.testMethod0Request(); - var params = request.getParams(); - var response = request.send(); - var results = response.get(); - Assert.assertEquals(params.getParam0(), results.getResult0()); - } - - @Test - public void testLocalTwoStagePipeline() { - - var server0 = new Demo.Iface0.Server() { - boolean method0called = false; - - @Override - protected CompletableFuture method0(CallContext ctx) { - method0called = true; - return CompletableFuture.completedFuture(null); - } - }; - - var server1 = new Demo.Iface1.Server() { - @Override - protected CompletableFuture method1(CallContext ctx) { - ctx.getResults().setResult0(new Demo.Iface0.Client(server0)); - return CompletableFuture.completedFuture(null); - } - }; - - var iface1Client = new Demo.Iface1.Client(server1); - var request1 = iface1Client.method1Request(); - var response = request1.send(); - var iface0 = response.getResult0(); - var request0 = iface0.method0Request(); - var response0 = request0.send(); - response0.join(); - Assert.assertTrue(!response0.isCompletedExceptionally()); - Assert.assertTrue(server0.method0called); - } -}