major refactor of RemotePromise and Pipeline

This commit is contained in:
Vaci Koblizek 2020-10-30 18:16:49 +00:00
parent 2d8fe31a59
commit 8eacc8cada
15 changed files with 580 additions and 302 deletions

View file

@ -34,6 +34,7 @@
#include <unistd.h> #include <unistd.h>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <map>
#include <set> #include <set>
#include <kj/main.h> #include <kj/main.h>
#include <algorithm> #include <algorithm>
@ -334,9 +335,23 @@ private:
return kj::strTree(javaFullName(type.asStruct()), ".", suffix); return kj::strTree(javaFullName(type.asStruct()), ".", suffix);
} }
} }
case schema::Type::INTERFACE:
return javaFullName(type.asInterface()); case schema::Type::INTERFACE: {
auto interfaceSchema = type.asInterface();
if (interfaceSchema.getProto().getIsGeneric()) {
auto typeArgs = getTypeArguments(interfaceSchema, interfaceSchema, kj::str(suffix));
return kj::strTree(
javaFullName(interfaceSchema), ".", suffix, "<",
kj::StringTree(KJ_MAP(arg, typeArgs){
return kj::strTree(arg);
}, ", "),
">"
);
} else {
return kj::strTree(javaFullName(type.asInterface()), ".", suffix);
}
}
case schema::Type::LIST: case schema::Type::LIST:
{ {
auto elementType = type.asList().getElementType(); auto elementType = type.asList().getElementType();
@ -394,7 +409,12 @@ private:
"_", kj::hex(brandParam->scopeId), "_", suffix); "_", kj::hex(brandParam->scopeId), "_", suffix);
} else { } else {
return kj::strTree("org.capnproto.AnyPointer.", suffix); switch (type.whichAnyPointerKind()) {
case schema::Type::AnyPointer::Unconstrained::CAPABILITY:
return kj::strTree("org.capnproto.Capability.", suffix);
default:
return kj::strTree("org.capnproto.AnyPointer.", suffix);
}
} }
} }
} }
@ -721,7 +741,8 @@ private:
STRUCT, STRUCT,
LIST, LIST,
INTERFACE, INTERFACE,
ANY_POINTER ANY_POINTER,
BRAND_PARAMETER
}; };
kj::StringTree makeEnumGetter(EnumSchema schema, uint offset, kj::String defaultMaskParam, int indent) { kj::StringTree makeEnumGetter(EnumSchema schema, uint offset, kj::String defaultMaskParam, int indent) {
@ -753,7 +774,12 @@ private:
"_", kj::hex(brandParam->scopeId), "_Factory"); "_", kj::hex(brandParam->scopeId), "_Factory");
} else { } else {
return kj::str("org.capnproto.AnyPointer.factory"); switch (type.whichAnyPointerKind()) {
case schema::Type::AnyPointer::Unconstrained::CAPABILITY:
return kj::str("org.capnproto.Capability.factory");
default:
return kj::str("org.capnproto.AnyPointer.factory");
}
} }
} }
case schema::Type::STRUCT : { case schema::Type::STRUCT : {
@ -908,6 +934,7 @@ private:
auto typeBody = slot.getType(); auto typeBody = slot.getType();
auto defaultBody = slot.getDefaultValue(); auto defaultBody = slot.getDefaultValue();
switch (typeBody.which()) { switch (typeBody.which()) {
case schema::Type::VOID: case schema::Type::VOID:
kind = FieldKind::PRIMITIVE; kind = FieldKind::PRIMITIVE;
@ -992,10 +1019,27 @@ private:
kind = FieldKind::INTERFACE; kind = FieldKind::INTERFACE;
break; break;
case schema::Type::ANY_POINTER: case schema::Type::ANY_POINTER:
kind = FieldKind::ANY_POINTER;
if (defaultBody.hasAnyPointer()) { if (defaultBody.hasAnyPointer()) {
defaultOffset = field.getDefaultValueSchemaOffset(); defaultOffset = field.getDefaultValueSchemaOffset();
} }
if (field.getType().getBrandParameter() != nullptr && false) {
kind = FieldKind::BRAND_PARAMETER;
} else {
kind = FieldKind::ANY_POINTER;
switch (field.getType().whichAnyPointerKind()) {
case schema::Type::AnyPointer::Unconstrained::ANY_KIND:
kind = FieldKind::ANY_POINTER;
break;
case schema::Type::AnyPointer::Unconstrained::STRUCT:
kind = FieldKind::STRUCT;
break;
case schema::Type::AnyPointer::Unconstrained::LIST:
kind = FieldKind::LIST;
case schema::Type::AnyPointer::Unconstrained::CAPABILITY:
kind = FieldKind::INTERFACE;
break;
}
}
break; break;
} }
@ -1050,7 +1094,8 @@ private:
} else if (kind == FieldKind::INTERFACE) { } else if (kind == FieldKind::INTERFACE) {
auto factoryArg = makeFactoryArg(field.getType()); auto factoryArg = makeFactoryArg(field.getType());
auto clientType = kj::str(typeName(field.getType()), ".Client"); auto clientType = typeName(field.getType(), kj::str("Client")).flatten();
auto serverType = typeName(field.getType(), kj::str("Server")).flatten();
return FieldText { return FieldText {
kj::strTree( kj::strTree(
@ -1080,11 +1125,16 @@ private:
unionDiscrim.set, unionDiscrim.set,
spaces(indent), " _setPointerField(", factoryArg, ", ", offset, ", value);\n", spaces(indent), " _setPointerField(", factoryArg, ", ", offset, ", value);\n",
spaces(indent), " }\n", spaces(indent), " }\n",
"\n"), spaces(indent), " public void set", titleCase, "(", serverType, " value) {\n",
spaces(indent), " this.set", titleCase, "(new ", clientType, "(value));\n",
spaces(indent), " }\n"
),
kj::strTree( kj::strTree(
spaces(indent), " public ", clientType, " get", titleCase, "() {\n", spaces(indent), " default ", clientType, " get", titleCase, "() {\n",
spaces(indent), " return new ", clientType, "(this.getPointerField((short)", offset, ").asCap());\n", spaces(indent), " return new ", clientType, "(\n",
spaces(indent), " this.typelessPipeline().getPointerField((short)", offset, ").asCap()\n",
spaces(indent), " );\n",
spaces(indent), " }\n" spaces(indent), " }\n"
) )
}; };
@ -1145,7 +1195,8 @@ private:
auto typeParamVec = getTypeParameters(field.getContainingStruct()); auto typeParamVec = getTypeParameters(field.getContainingStruct());
auto factoryArg = makeFactoryArg(field.getType()); auto factoryArg = makeFactoryArg(field.getType());
auto pipelineType = typeName(field.getType(), kj::str("Pipeline")).flatten();
return FieldText { return FieldText {
kj::strTree( kj::strTree(
kj::mv(unionDiscrim.readerIsDef), kj::mv(unionDiscrim.readerIsDef),
@ -1194,6 +1245,12 @@ private:
spaces(indent), " return ", spaces(indent), " return ",
"_initPointerField(", factoryArg, ",", offset, ", 0);\n", "_initPointerField(", factoryArg, ",", offset, ", 0);\n",
spaces(indent), " }\n"), spaces(indent), " }\n"),
kj::strTree(
spaces(indent), " default ", pipelineType, " get", titleCase, "() {\n",
spaces(indent), " var pipeline = this.typelessPipeline().getPointerField((short)", offset, ");\n",
spaces(indent), " return () -> pipeline;\n",
spaces(indent), " }\n")
}; };
} else if (kind == FieldKind::BLOB) { } else if (kind == FieldKind::BLOB) {
@ -1374,8 +1431,6 @@ private:
spaces(indent), " }\n") spaces(indent), " }\n")
) )
), ),
}; };
} else { } else {
KJ_UNREACHABLE; KJ_UNREACHABLE;
@ -1479,8 +1534,8 @@ private:
",(short)", structNode.getPointerCount(), ");\n"), ",(short)", structNode.getPointerCount(), ");\n"),
spaces(indent), " public static final class Factory", factoryTypeParams, "\n", spaces(indent), " public static final class Factory", factoryTypeParams, "\n",
spaces(indent), " extends org.capnproto.StructFactory<Builder", builderTypeParams, ", Reader", readerTypeParams, ">\n", spaces(indent), " extends org.capnproto.StructFactory<Builder", builderTypeParams, ", Reader", readerTypeParams, "> {\n",
spaces(indent), " implements org.capnproto.PipelineFactory<Pipeline", readerTypeParams, "> {\n", //spaces(indent), " implements org.capnproto.PipelineFactory<Pipeline", readerTypeParams, "> {\n",
factoryMembers.flatten(), factoryMembers.flatten(),
spaces(indent), " public Factory(", spaces(indent), " public Factory(",
factoryArgs.flatten(), factoryArgs.flatten(),
@ -1515,13 +1570,13 @@ private:
(hasTypeParams ? kj::strTree("this") : kj::strTree()), (hasTypeParams ? kj::strTree("this") : kj::strTree()),
");\n", ");\n",
spaces(indent), " }\n", spaces(indent), " }\n",
spaces(indent), " public Pipeline", readerTypeParams, " newPipeline(org.capnproto.RemotePromise<org.capnproto.AnyPointer.Reader> promise) {\n", //spaces(indent), " public Pipeline", readerTypeParams, " newPipeline(org.capnproto.RemotePromise<org.capnproto.AnyPointer.Reader> promise, org.capnproto.PipelineImpl typeless) {\n",
spaces(indent), " return new Pipeline", readerTypeParamsInferred, "(", //spaces(indent), " return new Pipeline", readerTypeParamsInferred, "(",
kj::StringTree(KJ_MAP(p, typeParamVec) { //kj::StringTree(KJ_MAP(p, typeParamVec) {
return kj::strTree(p, "_Factory"); // return kj::strTree(p, "_Factory");
}, ", "), // }, ", "),
(hasTypeParams ? ", ": ""), "promise);\n", //(hasTypeParams ? ", ": ""), "promise, typeless);\n",
spaces(indent), " }\n", //spaces(indent), " }\n",
spaces(indent), " }\n", spaces(indent), " }\n",
(hasTypeParams ? (hasTypeParams ?
@ -1609,17 +1664,23 @@ private:
spaces(indent), " }\n"), spaces(indent), " }\n"),
KJ_MAP(n, nestedTypeDecls) { return kj::mv(n); }, KJ_MAP(n, nestedTypeDecls) { return kj::mv(n); },
spaces(indent), " public static class Pipeline", readerTypeParams, " extends org.capnproto.Pipeline<Reader", readerTypeParams, "> {\n", //spaces(indent), " public interface Pipeline", readerTypeParams, " extends org.capnproto.RemotePromise<Reader", readerTypeParams, "> {\n",
spaces(indent), " public Pipeline(", spaces(indent), " public interface Pipeline", readerTypeParams, " extends org.capnproto.PipelineBase {\n",
KJ_MAP(p, typeParamVec) { //spaces(indent), " private final org.capnproto.PipelineImpl typeless;\n",
return kj::strTree("org.capnproto.PointerFactory<?,", p, "_Reader> ", p, "_Factory,"); //spaces(indent), " org.capnproto.AnyPointer.Pipeline getTypeless();\n",
}, " org.capnproto.RemotePromise<org.capnproto.AnyPointer.Reader> remotePromise) {\n", //spaces(indent), " public Pipeline(",
spaces(indent), " super(org.capnproto.RemotePromise.fromTypeless(", factoryRef, ", remotePromise));\n", //#KJ_MAP(p, typeParamVec) {
spaces(indent), " }\n", // return kj::strTree("org.capnproto.PointerFactory<?,", p, "_Reader> ", p, "_Factory,");
KJ_MAP(f, fieldTexts) { return kj::mv(f.pipelineMethodDecls); }, //}, " org.capnproto.RemotePromise<org.capnproto.AnyPointer.Reader> remotePromise,\n",
//spaces(indent), " org.capnproto.PipelineImpl typelessPipeline) {\n",
//spaces(indent), " super(org.capnproto.RemotePromise.fromTypeless(", factoryRef, ", remotePromise));\n",
//spaces(indent), " this.typeless = typelessPipeline;\n",
//spaces(indent), " }\n",
KJ_MAP(f, fieldTexts) {
return kj::mv(f.pipelineMethodDecls);
},
spaces(indent), " }\n", spaces(indent), " }\n",
spaces(indent), "}\n", spaces(indent), "}\n"),
"\n"),
kj::strTree(), kj::strTree(),
kj::strTree() kj::strTree()
@ -1633,36 +1694,64 @@ private:
kj::StringTree clientServerDefs; kj::StringTree clientServerDefs;
}; };
struct ExtendInfo {
kj::String typeName;
uint64_t id;
};
void getTransitiveSuperclasses(InterfaceSchema schema, std::map<uint64_t, InterfaceSchema>& map) {
if (map.insert(std::make_pair(schema.getProto().getId(), schema)).second) {
for (auto sup: schema.getSuperclasses()) {
getTransitiveSuperclasses(sup, map);
}
}
}
InterfaceText makeInterfaceText(kj::StringPtr scope, kj::StringPtr name, InterfaceSchema schema, InterfaceText makeInterfaceText(kj::StringPtr scope, kj::StringPtr name, InterfaceSchema schema,
kj::Array<kj::StringTree> nestedTypeDecls, int indent) { kj::Array<kj::StringTree> nestedTypeDecls, int indent) {
auto sp = spaces(indent);
auto fullName = kj::str(scope, name); auto fullName = kj::str(scope, name);
auto methods = KJ_MAP(m, schema.getMethods()) { auto methods = KJ_MAP(m, schema.getMethods()) {
return makeMethodText(fullName, m); return makeMethodText(fullName, m, indent+2);
}; };
auto proto = schema.getProto(); auto proto = schema.getProto();
auto hexId = kj::hex(proto.getId()); auto hexId = kj::hex(proto.getId());
auto typeName = javaFullName(schema); auto superclasses = KJ_MAP(superclass, schema.getSuperclasses()) {
return ExtendInfo {
kj::str(javaFullName(superclass, nullptr)),
superclass.getProto().getId()
};
};
kj::Array<ExtendInfo> transitiveSuperclasses;
kj::String genericParamTypes; {
if (proto.getIsGeneric()) { std::map<uint64_t, InterfaceSchema> map;
auto typeParams = getTypeParameters(schema); getTransitiveSuperclasses(schema, map);
genericParamTypes = kj::strTree( map.erase(schema.getProto().getId());
"<", transitiveSuperclasses = KJ_MAP(entry, map) {
kj::StringTree( return ExtendInfo {
KJ_MAP(arg, typeParams) { kj::str(javaFullName(entry.second, nullptr)),
return kj::strTree(arg); entry.second.getProto().getId()
}, ", "), };
">").flatten(); };
} }
else {
genericParamTypes = kj::str(""); auto typeNameVec = javaFullName(schema);
}
auto typeParamVec = getTypeParameters(schema); auto typeParamVec = getTypeParameters(schema);
bool hasTypeParams = typeParamVec.size() > 0; bool hasTypeParams = typeParamVec.size() > 0;
kj::String genericParamTypes = proto.getIsGeneric()
? kj::strTree("<",
kj::StringTree(
KJ_MAP(arg, typeParamVec) {
return kj::strTree(arg);
}, ", "),
">").flatten()
: kj::str();
kj::StringTree readerTypeParamsTree; kj::StringTree readerTypeParamsTree;
kj::StringTree builderTypeParamsTree; kj::StringTree builderTypeParamsTree;
@ -1701,6 +1790,10 @@ private:
return kj::strTree(spaces(indent), " final org.capnproto.PointerFactory<", p, "_Builder, ", p, "_Reader> ", p, "_Factory;\n"); return kj::strTree(spaces(indent), " final org.capnproto.PointerFactory<", p, "_Builder, ", p, "_Reader> ", p, "_Factory;\n");
}); });
auto factoryConstructorParams = kj::StringTree(KJ_MAP(p, typeParamVec) {
return kj::strTree(p, "_Factory");
}, ", ").flatten();
kj::String factoryRef = hasTypeParams kj::String factoryRef = hasTypeParams
? kj::str(kj::strTree("newFactory(", ? kj::str(kj::strTree("newFactory(",
kj::StringTree(KJ_MAP(p, typeParamVec) { kj::StringTree(KJ_MAP(p, typeParamVec) {
@ -1712,65 +1805,99 @@ private:
return InterfaceText { return InterfaceText {
kj::strTree( kj::strTree(
spaces(indent), "public static class ", name, genericParamTypes, " {\n", sp, "public static class ", name, genericParamTypes, " {\n",
sp, " public static final class Factory", factoryTypeParams, "\n",
spaces(indent), " public static final class Factory", factoryTypeParams, "\n", sp, " extends org.capnproto.Capability.Factory<Client> {\n",
spaces(indent), " extends org.capnproto.Capability.Factory<Client> {\n",
factoryMembers.flatten(), factoryMembers.flatten(),
spaces(indent), " public Factory(", sp, " public Factory(",
factoryArgs.flatten(), factoryArgs.flatten(),
") {\n", ") {\n",
KJ_MAP(p, typeParamVec) { KJ_MAP(p, typeParamVec) {
return kj::strTree(spaces(indent), " this.", p, "_Factory = ", p, "_Factory;\n"); return kj::strTree(sp, " this.", p, "_Factory = ", p, "_Factory;\n");
}, },
spaces(indent), " }\n", sp, " }\n",
sp, " public final Client newClient(org.capnproto.ClientHook hook) {\n",
sp, " return new Client(hook);\n",
//spaces(indent), " public static final class Factory extends org.capnproto.Capability.Factory<Client> {\n", sp, " }\n",
spaces(indent), " public final Client newClient(org.capnproto.ClientHook hook) {\n", sp, " }\n",
spaces(indent), " return new Client(hook);\n",
spaces(indent), " }\n",
spaces(indent), " }\n",
"\n", "\n",
spaces(indent), " public static final Factory factory = new Factory();\n", (hasTypeParams
? kj::strTree(
sp, " public static final ", factoryTypeParams, "Factory", factoryTypeParams, "\n",
sp, " newFactory(", factoryArgs.flatten(), ") {\n",
sp, " return new Factory<>(", factoryConstructorParams, ");\n",
sp, " }\n"
)
: kj::strTree(
sp, " public static final Factory factory = new Factory();\n"
)
),
"\n", "\n",
spaces(indent), " public static class Client extends org.capnproto.Capability.Client {\n", sp, " public static class Client\n",
spaces(indent), " public Client() {}\n", (superclasses.size() == 0
spaces(indent), " public Client(org.capnproto.ClientHook hook) { super(hook); }\n", ? kj::str(sp, " extends org.capnproto.Capability.Client ")
spaces(indent), " public Client(org.capnproto.Capability.Client cap) { super(cap); }\n", : kj::str(
spaces(indent), " public Client(Server server) { super(server); }\n", KJ_MAP(s, superclasses) {
spaces(indent), " public <T extends Client> Client(java.util.concurrent.CompletionStage<T> promise) {\n", return kj::strTree(sp, " extends ", s.typeName, ".Client ");
spaces(indent), " super(promise);\n", })
spaces(indent), " }\n", ),
"{\n",
sp, " public Client() {}\n",
sp, " public Client(org.capnproto.ClientHook hook) { super(hook); }\n",
sp, " public Client(org.capnproto.Capability.Client cap) { super(cap); }\n",
sp, " public Client(Server server) { super(server); }\n",
sp, " public <T extends Client> Client(java.util.concurrent.CompletionStage<T> promise) {\n",
sp, " super(promise);\n",
sp, " }\n",
"\n", "\n",
KJ_MAP(m, methods) { return kj::mv(m.clientDefs); }, sp, " public static final class Methods {\n",
spaces(indent), " }\n", KJ_MAP(m, methods) { return kj::mv(m.clientMethodDefs); },
sp, " }\n",
"\n", "\n",
spaces(indent), " public static abstract class Server extends org.capnproto.Capability.Server {\n", KJ_MAP(m, methods) { return kj::mv(m.clientCalls); },
spaces(indent), " protected org.capnproto.DispatchCallResult dispatchCall(\n", sp, " }\n",
spaces(indent), " long interfaceId, short methodId,\n",
spaces(indent), " org.capnproto.CallContext<org.capnproto.AnyPointer.Reader, org.capnproto.AnyPointer.Builder> context) {\n",
spaces(indent), " if (interfaceId == 0x", hexId, "L) {\n",
spaces(indent), " return dispatchCallInternal(methodId, context);\n",
spaces(indent), " }\n",
spaces(indent), " return org.capnproto.Capability.Server.result(\n",
spaces(indent), " org.capnproto.Capability.Server.internalUnimplemented(\"", name, "\", interfaceId));\n",
spaces(indent), " }\n",
"\n", "\n",
spaces(indent), " protected org.capnproto.DispatchCallResult dispatchCallInternal(short methodId, org.capnproto.CallContext<org.capnproto.AnyPointer.Reader, org.capnproto.AnyPointer.Builder> context) {\n", sp, " public static abstract class Server\n",
spaces(indent), " switch (methodId) {\n", (superclasses.size() == 0
? kj::str(sp, " extends org.capnproto.Capability.Server ")
: kj::str(
KJ_MAP(s, superclasses) {
return kj::strTree(sp, " extends ", s.typeName, ".Server ");
})
),
"{\n",
sp, " protected org.capnproto.DispatchCallResult dispatchCall(\n",
sp, " long interfaceId, short methodId,\n",
sp, " org.capnproto.CallContext<org.capnproto.AnyPointer.Reader, org.capnproto.AnyPointer.Builder> context) {\n",
sp, " if (interfaceId == 0x", hexId, "L) {\n",
sp, " return this.dispatchCallInternal(methodId, context);\n",
sp, " }\n",
KJ_MAP(s, transitiveSuperclasses) {
return kj::strTree(
sp, " else if (interfaceId == 0x", kj::hex(s.id), "L) {\n",
sp, " return super.dispatchCall(interfaceId, methodId, context);\n",
sp, " }\n");
},
sp, " else {\n",
sp, " return org.capnproto.Capability.Server.result(\n",
sp, " org.capnproto.Capability.Server.internalUnimplemented(\"", name, "\", interfaceId));\n",
sp, " }\n",
sp, " }\n",
"\n",
sp, " private org.capnproto.DispatchCallResult dispatchCallInternal(short methodId, org.capnproto.CallContext<org.capnproto.AnyPointer.Reader, org.capnproto.AnyPointer.Builder> context) {\n",
sp, " switch (methodId) {\n",
KJ_MAP(m, methods) { return kj::mv(m.dispatchCase); }, KJ_MAP(m, methods) { return kj::mv(m.dispatchCase); },
spaces(indent), " default:\n", sp, " default:\n",
spaces(indent), " return org.capnproto.Capability.Server.result(\n", sp, " return org.capnproto.Capability.Server.result(\n",
spaces(indent), " org.capnproto.Capability.Server.internalUnimplemented(\"", name, "\", 0x", hexId, "L, methodId));\n", sp, " org.capnproto.Capability.Server.internalUnimplemented(\"", name, "\", 0x", hexId, "L, methodId));\n",
spaces(indent), " }\n", sp, " }\n",
spaces(indent), " }\n\n", sp, " }\n\n",
KJ_MAP(m, methods) { return kj::mv(m.serverDefs); }, KJ_MAP(m, methods) { return kj::mv(m.serverDefs); },
spaces(indent), " }\n", sp, " }\n",
spaces(indent), "\n", sp, "\n",
KJ_MAP(n, nestedTypeDecls) { return kj::mv(n); }, KJ_MAP(n, nestedTypeDecls) { return kj::mv(n); },
"\n", "\n",
spaces(indent), "}\n", sp, "}\n",
"\n") "\n")
}; };
} }
@ -1778,12 +1905,15 @@ private:
// ----------------------------------------------------------------- // -----------------------------------------------------------------
struct MethodText { struct MethodText {
kj::StringTree clientDefs; kj::StringTree clientMethodDefs;
kj::StringTree clientCalls;
kj::StringTree serverDefs; kj::StringTree serverDefs;
kj::StringTree dispatchCase; kj::StringTree dispatchCase;
}; };
MethodText makeMethodText(kj::StringPtr interfaceName, InterfaceSchema::Method method) { MethodText makeMethodText(kj::StringPtr interfaceName, InterfaceSchema::Method method, int indent = 0) {
auto sp = spaces(indent);
auto proto = method.getProto(); auto proto = method.getProto();
auto methodName = proto.getName(); auto methodName = proto.getName();
auto titleCase = toTitleCase(methodName); auto titleCase = toTitleCase(methodName);
@ -1876,7 +2006,10 @@ private:
}, ", "), }, ", "),
")").flatten(); ")").flatten();
} }
auto paramBuilder = kj::str(shortParamType, ".Builder");
auto resultReader = kj::str(shortResultType, ".Reader");
auto interfaceProto = method.getContainingInterface().getProto(); auto interfaceProto = method.getContainingInterface().getProto();
uint64_t interfaceId = interfaceProto.getId(); uint64_t interfaceId = interfaceProto.getId();
auto interfaceIdHex = kj::hex(interfaceId); auto interfaceIdHex = kj::hex(interfaceId);
@ -1884,45 +2017,80 @@ private:
if (isStreaming) { if (isStreaming) {
return MethodText { return MethodText {
kj::strTree( // client method defs
" public org.capnproto.StreamingRequest<", shortParamType, ".Builder> ", methodName, "Request() {\n", kj::strTree(),
" return newStreamingCall(", paramFactory, ", 0x", interfaceIdHex, "L, (short)", methodId, ");\n"
" }\n"),
// client call
kj::strTree( kj::strTree(
" protected java.util.concurrent.CompletableFuture<java.lang.Void> ", identifierName, "(org.capnproto.StreamingCallContext<", shortParamType, ".Reader> context) {\n" sp, "public org.capnproto.StreamingRequest<", shortParamType, ".Builder> ", methodName, "Request() {\n",
" return org.capnproto.Capability.Server.internalUnimplemented(\n" sp, " return newStreamingCall(", paramFactory, ", 0x", interfaceIdHex, "L, (short)", methodId, ");\n",
" \"", interfaceProto.getDisplayName(), "\", \"", methodName, "\",\n" sp, "}\n"
" 0x", interfaceIdHex, "L, (short)", methodId, ");\n" ),
" }\n\n"),
// server defs
kj::strTree( kj::strTree(
" case ", methodId, ":\n", sp, "protected java.util.concurrent.CompletableFuture<java.lang.Void> ", identifierName, "(org.capnproto.StreamingCallContext<", shortParamType, ".Reader> context) {\n",
" return org.capnproto.Capability.Server.streamResult(\n", sp, " return org.capnproto.Capability.Server.internalUnimplemented(\n",
" this.", identifierName, "(org.capnproto.Capability.Server.internalGetTypedStreamingContext(\n" sp, " \"", interfaceProto.getDisplayName(), "\", \"", methodName, "\",\n",
" ", paramFactory, ", context)));\n") sp, " 0x", interfaceIdHex, "L, (short)", methodId, ");\n",
sp, "}\n"
),
// dispatch
kj::strTree(
sp, "case ", methodId, ":\n",
sp, " return org.capnproto.Capability.Server.streamResult(\n",
sp, " this.", identifierName, "(org.capnproto.Capability.Server.internalGetTypedStreamingContext(\n",
sp, " ", paramFactory, ", context)));\n"
)
}; };
} else { } else {
return MethodText { return MethodText {
// client method defs
kj::strTree( kj::strTree(
" public org.capnproto.Request<", shortParamType, ".Builder, ", shortResultType, ".Pipeline> ", methodName, "Request() {\n", sp, " public static final class ", methodName, " {\n",
" return newCall(", paramFactory, ", ", shortResultType, ".factory, 0x", interfaceIdHex, "L, (short)", methodId, ");\n" sp, " public interface Request extends org.capnproto.Request<", paramBuilder, "> {\n",
" }\n"), sp, " default org.capnproto.FromPointerBuilder<", paramBuilder, "> getParamsFactory() {\n",
sp, " return ", paramFactory, ";\n",
sp, " }\n",
sp, " default Response send() {\n",
sp, " return new Response(this.getHook().send());\n",
sp, " }\n",
sp, " }\n",
sp, " public static final class Response\n",
sp, " extends org.capnproto.RemotePromise<", resultReader, ">\n",
sp, " implements ", shortResultType, ".Pipeline {\n",
sp, " public Response(org.capnproto.RemotePromise<org.capnproto.AnyPointer.Reader> response) {\n",
sp, " super(", resultFactory, ", response);\n",
sp, " }\n",
sp, " public org.capnproto.AnyPointer.Pipeline typelessPipeline() {\n",
sp, " return this.pipeline();\n",
sp, " }\n",
sp, " }\n",
sp, " }\n"
),
// client call
kj::strTree( kj::strTree(
" protected java.util.concurrent.CompletableFuture<java.lang.Void> ", identifierName, "(org.capnproto.CallContext<", shortParamType, ".Reader, ", shortResultType, ".Builder> context) {\n" sp, "public Methods.", methodName, ".Request ", methodName, "Request() {\n",
" return org.capnproto.Capability.Server.internalUnimplemented(\n" sp, " var result = newCall(0x", interfaceIdHex, "L, (short)", methodId, ");\n",
" \"", interfaceProto.getDisplayName(), "\", \"", methodName, "\",\n" sp, " return () -> result;\n",
" 0x", interfaceIdHex, "L, (short)", methodId, ");\n" sp, "}\n"
" }\n\n"), ),
// server defs
kj::strTree( kj::strTree(
" case ", methodId, ":\n", sp, "protected java.util.concurrent.CompletableFuture<java.lang.Void> ", identifierName, "(org.capnproto.CallContext<", shortParamType, ".Reader, ", shortResultType, ".Builder> context) {\n",
" return org.capnproto.Capability.Server.result (\n", sp, " return org.capnproto.Capability.Server.internalUnimplemented(\n",
" this.", identifierName, "(org.capnproto.Capability.Server.internalGetTypedContext(\n" sp, " \"", interfaceProto.getDisplayName(), "\", \"", methodName, "\", 0x", interfaceIdHex, "L, (short)", methodId, ");\n",
" ", paramFactory, ", ", resultFactory, ", context)));\n") sp, "}\n"),
// dispatch
kj::strTree(
sp, "case ", methodId, ":\n",
sp, " return org.capnproto.Capability.Server.result(\n",
sp, " this.", identifierName, "(org.capnproto.Capability.Server.internalGetTypedContext(\n",
sp, " ", paramFactory, ", ", resultFactory, ", context)));\n")
}; };
} }
} }

View file

@ -23,8 +23,7 @@ package org.capnproto;
public final class AnyPointer { public final class AnyPointer {
public static final class Factory public static final class Factory
implements PointerFactory<Builder, Reader>, implements PointerFactory<Builder, Reader> {
PipelineFactory<Pipeline> {
public final Reader fromPointerReader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) { public final Reader fromPointerReader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) {
return new Reader(segment, capTable, pointer, nestingLimit); return new Reader(segment, capTable, pointer, nestingLimit);
} }
@ -36,8 +35,8 @@ public final class AnyPointer {
result.clear(); result.clear();
return result; return result;
} }
public Pipeline newPipeline(RemotePromise<Reader> promise) { public Pipeline newPipeline(PipelineImpl typeless) {
return new AnyPointer.Pipeline(promise); return new AnyPointer.Pipeline(typeless.hook, typeless.ops);
} }
} }
public static final Factory factory = new Factory(); public static final Factory factory = new Factory();
@ -133,7 +132,7 @@ public final class AnyPointer {
} }
final void setAsCap(Capability.Client cap) { final void setAsCap(Capability.Client cap) {
WireHelpers.setCapabilityPointer(this.segment, capTable, this.pointer, cap.hook); WireHelpers.setCapabilityPointer(this.segment, capTable, this.pointer, cap.getHook());
} }
public final Reader asReader() { public final Reader asReader() {
@ -146,15 +145,55 @@ public final class AnyPointer {
} }
} }
public static final class Pipeline public static class Pipeline extends PipelineImpl implements PipelineBase {
extends org.capnproto.Pipeline<AnyPointer.Reader> {
public Pipeline(RemotePromise<AnyPointer.Reader> promise) { public Pipeline(PipelineHook hook) {
super(promise); this(hook, new PipelineOp[0]);
} }
public Pipeline(RemotePromise<AnyPointer.Reader> promise, PipelineOp[] ops) { Pipeline(PipelineHook hook, PipelineOp[] ops) {
super(promise, ops); super(hook, ops);
}
@Override
public Pipeline typelessPipeline() {
return this;
}
}
public static final class Request
implements org.capnproto.Request<Builder> {
private final AnyPointer.Builder params;
private final RequestHook requestHook;
Request(AnyPointer.Builder params, RequestHook requestHook) {
this.params = params;
this.requestHook = requestHook;
}
@Override
public AnyPointer.Builder getParams() {
return this.params;
}
@Override
public org.capnproto.Request<Builder> getTypelessRequest() {
return this;
}
@Override
public RequestHook getHook() {
return this.requestHook;
}
@Override
public FromPointerBuilder<Builder> getParamsFactory() {
return AnyPointer.factory;
}
public RemotePromise<Reader> send() {
return this.getHook().send();
} }
} }
} }

View file

@ -32,8 +32,8 @@ public class CallContext<Params, Results> {
return this.hook.getResults().initAs(results); return this.hook.getResults().initAs(results);
} }
public final <SubParams, Results> CompletableFuture<java.lang.Void> tailCall(Request<SubParams, Results> tailRequest) { public final <SubParams> CompletableFuture<java.lang.Void> tailCall(Request<SubParams> tailRequest) {
return this.hook.tailCall(tailRequest.hook); return this.hook.tailCall(tailRequest.getHook());
} }
public final void allowCancellation() { public final void allowCancellation() {

View file

@ -2,6 +2,7 @@ package org.capnproto;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage; import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
public final class Capability { public final class Capability {
@ -13,7 +14,7 @@ public final class Capability {
CapTableReader capTable; CapTableReader capTable;
} }
public static abstract class Factory<T extends Client> public static abstract class Factory<T extends ClientBase>
implements FromPointerReader<T>, implements FromPointerReader<T>,
FromPointerBuilder<T>, FromPointerBuilder<T>,
SetPointerBuilder<T, T> { SetPointerBuilder<T, T> {
@ -44,37 +45,21 @@ public final class Capability {
} }
} }
public static class Client { public static class CapabilityFactory extends Factory<Client> {
@Override
final ClientHook hook; public Client newClient(ClientHook hook) {
return new Client(hook);
public Client() {
this.hook = null;
} }
}
public Client(Client other) { public static final CapabilityFactory factory = new CapabilityFactory();
this.hook = other.hook;
}
public Client(ClientHook hook) { public interface ClientBase {
this.hook = hook;
}
public Client(Server server) { ClientHook getHook();
this(makeLocalClient(server));
}
public <T extends Client> Client(CompletionStage<T> promise) { default CompletionStage<java.lang.Void> whenResolved() {
this(Capability.newLocalPromiseClient( return this.getHook().whenResolved();
promise.thenApply(client -> client.getHook())));
}
public Client(Throwable exc) {
this(newBrokenCap(exc));
}
ClientHook getHook() {
return this.hook;
} }
/** /**
@ -90,37 +75,72 @@ public final class Capability {
* The file descriptor will remain open at least as long as the {@link Client} remains alive. * The file descriptor will remain open at least as long as the {@link Client} remains alive.
* If you need it to last longer, you will need to `dup()` it. * If you need it to last longer, you will need to `dup()` it.
*/ */
public CompletableFuture<Integer> getFd() { default CompletableFuture<Integer> getFd() {
var fd = this.hook.getFd(); var fd = this.getHook().getFd();
if (fd != null) { if (fd != null) {
return CompletableFuture.completedFuture(fd); return CompletableFuture.completedFuture(fd);
} }
var promise = this.hook.whenMoreResolved(); var promise = this.getHook().whenMoreResolved();
if (promise != null) { if (promise != null) {
return promise.thenCompose(newHook -> new Client(newHook).getFd()); return promise.thenCompose(newHook -> new Client(newHook).getFd());
} }
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
/*
default <Params, Results>
Request<Params, Results> newCall(FromPointerBuilder<Params> paramsFactory,
FromPointerReader<Results> resultsFactory,
long interfaceId, short methodId) {
return Request.fromTypeless(paramsFactory, resultsFactory, this.getHook().newCall(interfaceId, methodId));
}*/
default Request<AnyPointer.Builder> newCall(long interfaceId, short methodId) {
return this.getHook().newCall(interfaceId, methodId);
}
default <T> StreamingRequest<T> newStreamingCall(FromPointerBuilder<T> paramsBuilder,
long interfaceId, short methodId) {
var request = getHook().newCall(interfaceId, methodId);
return new StreamingRequest<> (paramsBuilder, request.getParams(), request.getHook());
}
}
public static class Client implements ClientBase {
private final ClientHook hook;
public Client() {
this(newNullCap());
}
public Client(Client other) {
this(other.hook);
}
public Client(Server server) {
this(makeLocalClient(server));
}
public Client(ClientHook hook) {
this.hook = hook;
}
public <T extends Client> Client(CompletionStage<T> promise) {
this(Capability.newLocalPromiseClient(
promise.thenApply(client -> client.getHook())));
}
public Client(Throwable exc) {
this(newBrokenCap(exc));
}
public ClientHook getHook() {
return this.hook;
}
private static ClientHook makeLocalClient(Server server) { private static ClientHook makeLocalClient(Server server) {
return server.makeLocalClient(); return server.makeLocalClient();
} }
CompletionStage<java.lang.Void> whenResolved() {
return this.hook.whenResolved();
}
protected <P, R> Request<P, R> newCall(FromPointerBuilder<P> paramsFactory,
PipelineFactory<R> pipelineFactory,
long interfaceId, short methodId) {
return Request.fromTypeless(paramsFactory, pipelineFactory, hook.newCall(interfaceId, methodId));
}
protected <T> StreamingRequest<T> newStreamingCall(FromPointerBuilder<T> paramsBuilder,
long interfaceId, short methodId) {
var request = hook.newCall(interfaceId, methodId);
return new StreamingRequest<> (paramsBuilder, request.getParams(), request.hook);
}
} }
public abstract static class Server { public abstract static class Server {
@ -136,12 +156,10 @@ public final class Capability {
return new LocalClient(capServerSet); return new LocalClient(capServerSet);
} }
private final class LocalClient implements ClientHook { private final class LocalClient implements ClientHook {
private final CompletableFuture<java.lang.Void> resolveTask; private final CompletableFuture<java.lang.Void> resolveTask;
private ClientHook resolved; private ClientHook resolved;
private boolean blocked = false; private boolean blocked = false;
private Exception brokenException;
private final CapabilityServerSetBase capServerSet; private final CapabilityServerSetBase capServerSet;
LocalClient() { LocalClient() {
@ -159,10 +177,10 @@ public final class Capability {
} }
@Override @Override
public Request<AnyPointer.Builder, AnyPointer.Pipeline> newCall(long interfaceId, short methodId) { public AnyPointer.Request newCall(long interfaceId, short methodId) {
var hook = new LocalRequest(interfaceId, methodId, this); var hook = new LocalRequest(interfaceId, methodId, this);
var root = hook.message.getRoot(AnyPointer.factory); var root = hook.message.getRoot(AnyPointer.factory);
return new Request<>(root, AnyPointer.factory, hook); return new AnyPointer.Request(root, hook);
} }
@Override @Override
@ -173,7 +191,8 @@ public final class Capability {
return null; return null;
} }
var promise = callInternal(interfaceId, methodId, ctx); var promise = this.whenResolved().thenCompose(
x -> this.callInternal(interfaceId, methodId, ctx));
CompletableFuture<PipelineHook> pipelinePromise = promise.thenApply(x -> { CompletableFuture<PipelineHook> pipelinePromise = promise.thenApply(x -> {
ctx.releaseParams(); ctx.releaseParams();
@ -186,7 +205,7 @@ public final class Capability {
} }
return new VoidPromiseAndPipeline( return new VoidPromiseAndPipeline(
promise.copy(), promise,
new QueuedPipeline(pipelinePromise)); new QueuedPipeline(pipelinePromise));
} }
@ -197,9 +216,15 @@ public final class Capability {
@Override @Override
public CompletableFuture<ClientHook> whenMoreResolved() { public CompletableFuture<ClientHook> whenMoreResolved() {
return this.resolved != null if (this.resolved != null) {
? CompletableFuture.completedFuture(this.resolved) return CompletableFuture.completedFuture(this.resolved);
: this.resolveTask.thenApply(x -> this.resolved); }
else if (this.resolveTask != null) {
return this.resolveTask.thenApply(x -> this.resolved);
}
else {
return null;
}
} }
@Override @Override
@ -207,11 +232,10 @@ public final class Capability {
return BRAND; return BRAND;
} }
CompletableFuture<java.lang.Void> callInternal(long interfaceId, short methodId, CallContextHook context) { CompletableFuture<java.lang.Void> callInternal(long interfaceId, short methodId, CallContextHook ctx) {
var result = dispatchCall( var result = dispatchCall(
interfaceId, interfaceId, methodId,
methodId, new CallContext<>(AnyPointer.factory, AnyPointer.factory, ctx));
new CallContext<>(AnyPointer.factory, AnyPointer.factory, context));
if (result.isStreaming()) { if (result.isStreaming()) {
// TODO streaming // TODO streaming
return null; return null;
@ -233,6 +257,23 @@ public final class Capability {
} }
} }
/**
* If this returns non-null, then it is a promise which, when resolved, points to a new
* capability to which future calls can be sent. Use this in cases where an object implementation
* might discover a more-optimized path some time after it starts.
*
* Implementing this (and returning non-null) will cause the capability to be advertised as a
* promise at the RPC protocol level. Once the promise returned by shortenPath() resolves, the
* remote client will receive a `Resolve` message updating it to point at the new destination.
*
* `shortenPath()` can also be used as a hack to shut up the client. If shortenPath() returns
* a promise that resolves to an exception, then the client will be notified that the capability
* is now broken. Assuming the client is using a correct RPC implemnetation, this should cause
* all further calls initiated by the client to this capability to immediately fail client-side,
* sparing the server's bandwidth.
*
* The default implementation always returns null.
*/
public CompletableFuture<Client> shortenPath() { public CompletableFuture<Client> shortenPath() {
return null; return null;
} }
@ -320,7 +361,7 @@ public final class Capability {
}); });
assert promiseAndPipeline.pipeline != null; assert promiseAndPipeline.pipeline != null;
return new RemotePromise<>(promise, promiseAndPipeline.pipeline); return new RemotePromise<>(promise, new AnyPointer.Pipeline(promiseAndPipeline.pipeline));
} }
@Override @Override
@ -337,12 +378,12 @@ public final class Capability {
} }
private static final class LocalPipeline implements PipelineHook { private static final class LocalPipeline implements PipelineHook {
private final CallContextHook context; private final CallContextHook ctx;
private final AnyPointer.Reader results; private final AnyPointer.Reader results;
LocalPipeline(CallContextHook context) { LocalPipeline(CallContextHook ctx) {
this.context = context; this.ctx = ctx;
this.results = context.getResults().asReader(); this.results = ctx.getResults().asReader();
} }
@Override @Override
@ -439,13 +480,14 @@ public final class Capability {
static private ClientHook newBrokenClient(Throwable exc, boolean resolved, Object brand) { static private ClientHook newBrokenClient(Throwable exc, boolean resolved, Object brand) {
return new ClientHook() { return new ClientHook() {
@Override @Override
public Request<AnyPointer.Builder, AnyPointer.Pipeline> newCall(long interfaceId, short methodId) { public AnyPointer.Request newCall(long interfaceId, short methodId) {
return Request.newBrokenRequest(exc); var broken = Request.newBrokenRequest(AnyPointer.factory, exc);
return new AnyPointer.Request(broken.getParams(), broken.getHook());
} }
@Override @Override
public VoidPromiseAndPipeline call(long interfaceId, short methodId, CallContextHook context) { public VoidPromiseAndPipeline call(long interfaceId, short methodId, CallContextHook context) {
return new VoidPromiseAndPipeline(CompletableFuture.failedFuture(exc), null); return new VoidPromiseAndPipeline(CompletableFuture.failedFuture(exc), PipelineHook.newBrokenPipeline(exc));
} }
@Override @Override
@ -514,10 +556,10 @@ public final class Capability {
} }
@Override @Override
public Request<AnyPointer.Builder, AnyPointer.Pipeline> newCall(long interfaceId, short methodId) { public AnyPointer.Request newCall(long interfaceId, short methodId) {
var hook = new LocalRequest(interfaceId, methodId, this); var hook = new LocalRequest(interfaceId, methodId, this);
var root = hook.message.getRoot(AnyPointer.factory); var root = hook.message.getRoot(AnyPointer.factory);
return new Request<>(root, AnyPointer.factory, hook); return new AnyPointer.Request(root, hook);
} }
@Override @Override

View file

@ -8,7 +8,7 @@ public interface ClientHook {
Object NULL_CAPABILITY_BRAND = new Object(); Object NULL_CAPABILITY_BRAND = new Object();
Object BROKEN_CAPABILITY_BRAND = new Object(); Object BROKEN_CAPABILITY_BRAND = new Object();
Request<AnyPointer.Builder, AnyPointer.Pipeline> newCall(long interfaceId, short methodId); Request<AnyPointer.Builder> newCall(long interfaceId, short methodId);
VoidPromiseAndPipeline call(long interfaceId, short methodId, CallContextHook context); VoidPromiseAndPipeline call(long interfaceId, short methodId, CallContextHook context);
@ -46,7 +46,7 @@ public interface ClientHook {
/** /**
* Repeatedly calls whenMoreResolved() until it returns nullptr. * Repeatedly calls whenMoreResolved() until it returns nullptr.
*/ */
default CompletionStage<java.lang.Void> whenResolved() { default CompletableFuture<java.lang.Void> whenResolved() {
var promise = whenMoreResolved(); var promise = whenMoreResolved();
return promise != null return promise != null
? promise.thenCompose(ClientHook::whenResolved) ? promise.thenCompose(ClientHook::whenResolved)
@ -77,13 +77,14 @@ public interface ClientHook {
} }
final class VoidPromiseAndPipeline { final class VoidPromiseAndPipeline {
public final CompletableFuture<java.lang.Void> promise; public final CompletableFuture<java.lang.Void> promise;
public final PipelineHook pipeline; public final PipelineHook pipeline;
VoidPromiseAndPipeline(CompletableFuture<java.lang.Void> promise, PipelineHook pipeline) { VoidPromiseAndPipeline(CompletableFuture<java.lang.Void> promise,
PipelineHook pipeline) {
this.promise = promise; this.promise = promise;
this.pipeline = pipeline; this.pipeline = pipeline;
} }
} }
} }

View file

@ -1,41 +0,0 @@
package org.capnproto;
public class Pipeline<Results>
extends RemotePromise<Results> {
protected final PipelineOp[] ops;
protected PipelineHook hook;
public Pipeline(RemotePromise<Results> remotePromise) {
this(remotePromise, new PipelineOp[0]);
}
public Pipeline(RemotePromise<Results> remotePromise, PipelineOp[] ops) {
super(remotePromise.response, remotePromise.hook);
this.ops = ops;
this.hook = remotePromise.hook;
}
public PipelineHook getHook() {
return hook;
}
Pipeline<Results> noop() {
return new Pipeline<>(this, this.ops.clone());
}
public ClientHook asCap() {
return this.hook.getPipelinedCap(this.ops);
}
public Pipeline<Results> 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, newOps);
}
}

View file

@ -0,0 +1,5 @@
package org.capnproto;
public interface PipelineBase {
AnyPointer.Pipeline typelessPipeline();
}

View file

@ -1,5 +1,5 @@
package org.capnproto; package org.capnproto;
public interface PipelineFactory<Pipeline> { public interface PipelineFactory<Pipeline> {
Pipeline newPipeline(RemotePromise<AnyPointer.Reader> promise); Pipeline newPipeline(RemotePromise<AnyPointer.Reader> promise, PipelineImpl typeless);
} }

View file

@ -1,6 +1,7 @@
package org.capnproto; package org.capnproto;
public interface PipelineHook { public interface PipelineHook {
ClientHook getPipelinedCap(PipelineOp[] ops); ClientHook getPipelinedCap(PipelineOp[] ops);
static PipelineHook newBrokenPipeline(Throwable exc) { static PipelineHook newBrokenPipeline(Throwable exc) {

View file

@ -0,0 +1,32 @@
package org.capnproto;
public class PipelineImpl {
protected final PipelineHook hook;
protected final PipelineOp[] ops;
public PipelineImpl(PipelineHook hook) {
this(hook, new PipelineOp[0]);
}
public PipelineImpl(PipelineHook hook, PipelineOp[] ops) {
this.hook = hook;
this.ops = ops;
}
PipelineImpl noop() {
return new PipelineImpl(this.hook, this.ops.clone());
}
public ClientHook asCap() {
return this.hook.getPipelinedCap(ops);
}
public AnyPointer.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 AnyPointer.Pipeline(this.hook, newOps);
}
}

View file

@ -1,19 +1,35 @@
package org.capnproto; package org.capnproto;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
public class RemotePromise<Results> public class RemotePromise<Results>
extends CompletableFutureWrapper<Results> { extends CompletableFutureWrapper<Results> {
final CompletableFuture<Response<Results>> response; private final CompletableFuture<Response<Results>> response;
final PipelineHook hook; private final AnyPointer.Pipeline pipeline;
RemotePromise(CompletableFuture<Response<Results>> promise, public RemotePromise(FromPointerReader<Results> factory,
PipelineHook hook) { RemotePromise<AnyPointer.Reader> other) {
super(promise.thenApply(response -> response.getResults())); super(other.thenApply(response -> response.getAs(factory)));
this.response = other.response.thenApply(
response -> new Response<>(
response.getResults().getAs(factory),
response.getHook()));
this.pipeline = other.pipeline;
}
public RemotePromise(CompletableFuture<Response<Results>> promise,
AnyPointer.Pipeline pipeline) {
super(promise.thenApply(response -> {
//System.out.println("Got a response for remote promise " + promise.toString());
return response.getResults();
}));
this.response = promise; this.response = promise;
this.hook = hook; this.pipeline = pipeline;
}
public AnyPointer.Pipeline pipeline() {
return this.pipeline;
} }
public static <R> RemotePromise<R> fromTypeless( public static <R> RemotePromise<R> fromTypeless(
@ -21,7 +37,7 @@ public class RemotePromise<Results>
RemotePromise<AnyPointer.Reader> typeless) { RemotePromise<AnyPointer.Reader> typeless) {
var promise = typeless.response.thenApply( var promise = typeless.response.thenApply(
response -> Response.fromTypeless(resultsFactory, response)); response -> Response.fromTypeless(resultsFactory, response));
return new RemotePromise<>(promise, typeless.hook); return new RemotePromise<>(promise, typeless.pipeline);
} }
} }

View file

@ -2,31 +2,22 @@ package org.capnproto;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class Request<Params, Results> { public interface Request<Params> {
protected Params params; FromPointerBuilder<Params> getParamsFactory();
private PipelineFactory<Results> pipelineFactory;
RequestHook hook;
public Request(Params params, default Params getParams() {
PipelineFactory<Results> pipelineFactory, return this.getTypelessRequest().getParams().getAs(this.getParamsFactory());
RequestHook hook) {
this.params = params;
this.pipelineFactory = pipelineFactory;
this.hook = hook;
} }
public Params getParams() { default RequestHook getHook() {
return params; return this.getTypelessRequest().getHook();
} }
public Results send() { Request<AnyPointer.Builder> getTypelessRequest();
var typelessPromise = this.hook.send();
this.hook = null; // prevent reuse
return pipelineFactory.newPipeline(typelessPromise);
}
static <P, R> Request<P, R> newBrokenRequest(Throwable exc) { static <Params> Request<Params> newBrokenRequest(FromPointerBuilder<Params> paramsFactory,
Throwable exc) {
final MessageBuilder message = new MessageBuilder(); final MessageBuilder message = new MessageBuilder();
@ -48,13 +39,32 @@ public class Request<Params, Results> {
}; };
var root = message.getRoot(AnyPointer.factory); var root = message.getRoot(AnyPointer.factory);
return new Request<P, R>(null, null, hook); return new Request<>() {
@Override
public FromPointerBuilder<Params> getParamsFactory() {
return paramsFactory;
}
@Override
public Request<AnyPointer.Builder> getTypelessRequest() {
return null;
}
};
} }
static <P, R> Request<P, R> fromTypeless( static <Params> Request<Params> fromTypeless(
FromPointerBuilder<P> paramsFactory, FromPointerBuilder<Params> paramsFactory,
PipelineFactory<R> pipelineFactory, Request<AnyPointer.Builder> typeless) {
Request<AnyPointer.Builder, AnyPointer.Pipeline> typeless) { return new Request<>() {
return new Request<>(typeless.params.getAs(paramsFactory), pipelineFactory, typeless.hook); @Override
public FromPointerBuilder<Params> getParamsFactory() {
return paramsFactory;
}
@Override
public Request<AnyPointer.Builder> getTypelessRequest() {
return typeless;
}
};
} }
} }

View file

@ -1,9 +1,9 @@
package org.capnproto; package org.capnproto;
public class Response<Results> { public final class Response<Results> {
private Results results; private final Results results;
private ResponseHook hook; private final ResponseHook hook;
public Response(Results results, public Response(Results results,
ResponseHook hook) { ResponseHook hook) {
@ -15,6 +15,10 @@ public class Response<Results> {
return this.results; return this.results;
} }
public ResponseHook getHook() {
return this.hook;
}
static <R> Response<R> fromTypeless(FromPointerReader<R> resultsFactory, static <R> Response<R> fromTypeless(FromPointerReader<R> resultsFactory,
Response<AnyPointer.Reader> typeless) { Response<AnyPointer.Reader> typeless) {
return new Response<>(typeless.getResults().getAs(resultsFactory), typeless.hook); return new Response<>(typeless.getResults().getAs(resultsFactory), typeless.hook);

View file

@ -5,13 +5,13 @@ import java.util.Map;
public class RpcDumper { public class RpcDumper {
private final Map<Long, Schema.Node.Reader> schemas = new HashMap<>(); //private final Map<Long, Schema.Node.Reader> schemas = new HashMap<>();
private final Map<Integer, Long> clientReturnTypes = new HashMap<>(); private final Map<Integer, Long> clientReturnTypes = new HashMap<>();
private final Map<Integer, Long> serverReturnTypes = new HashMap<>(); private final Map<Integer, Long> serverReturnTypes = new HashMap<>();
void addSchema(long schemaId, Schema.Node.Reader node) { /*void addSchema(long schemaId, Schema.Node.Reader node) {
this.schemas.put(schemaId, node); this.schemas.put(schemaId, node);
} }*/
private void setReturnType(RpcTwoPartyProtocol.Side side, int schemaId, long schema) { private void setReturnType(RpcTwoPartyProtocol.Side side, int schemaId, long schema) {
switch (side) { switch (side) {
@ -68,7 +68,7 @@ public class RpcDumper {
var payload = call.getParams(); var payload = call.getParams();
var params = payload.getContent(); var params = payload.getContent();
var sendResultsTo = call.getSendResultsTo(); var sendResultsTo = call.getSendResultsTo();
/*
var schema = this.schemas.get(iface); var schema = this.schemas.get(iface);
if (schema != null) { if (schema != null) {
interfaceName = schema.getDisplayName().toString(); interfaceName = schema.getDisplayName().toString();
@ -91,7 +91,7 @@ public class RpcDumper {
} }
} }
} }*/
yield sender.name() + "(" + call.getQuestionId() + "): call " + yield sender.name() + "(" + call.getQuestionId() + "): call " +
call.getTarget() + " <- " + interfaceName + "." + call.getTarget() + " <- " + interfaceName + "." +

View file

@ -1532,7 +1532,7 @@ final class RpcState {
} }
@Override @Override
public Request<AnyPointer.Builder, AnyPointer.Pipeline> newCall(long interfaceId, short methodId) { public Request<AnyPointer.Builder> newCall(long interfaceId, short methodId) {
return newCallNoIntercept(interfaceId, methodId); return newCallNoIntercept(interfaceId, methodId);
} }
@ -1545,7 +1545,7 @@ final class RpcState {
var params = context.getParams(); var params = context.getParams();
var request = newCallNoIntercept(interfaceId, methodId); var request = newCallNoIntercept(interfaceId, methodId);
context.allowCancellation(); context.allowCancellation();
return context.directTailCall(request.hook); return context.directTailCall(request.getHook());
} }
@Override @Override
@ -1553,9 +1553,9 @@ final class RpcState {
return RpcState.this; return RpcState.this;
} }
private Request<AnyPointer.Builder, AnyPointer.Pipeline> newCallNoIntercept(long interfaceId, short methodId) { private Request<AnyPointer.Builder> newCallNoIntercept(long interfaceId, short methodId) {
if (isDisconnected()) { if (isDisconnected()) {
return Request.newBrokenRequest(disconnected); return Request.newBrokenRequest(AnyPointer.factory, disconnected);
} }
var request = new RpcRequest(this); var request = new RpcRequest(this);
@ -1563,7 +1563,7 @@ final class RpcState {
callBuilder.setInterfaceId(interfaceId); callBuilder.setInterfaceId(interfaceId);
callBuilder.setMethodId(methodId); callBuilder.setMethodId(methodId);
var root = request.getRoot(); var root = request.getRoot();
return new Request<>(root, AnyPointer.factory, request); return new AnyPointer.Request(root, request);
} }
} }
@ -1605,10 +1605,11 @@ final class RpcState {
var redirect = this.target.writeTarget(this.callBuilder.getTarget()); var redirect = this.target.writeTarget(this.callBuilder.getTarget());
if (redirect != null) { if (redirect != null) {
var replacement = redirect.newCall( var redirected = redirect.newCall(
this.callBuilder.getInterfaceId(), this.callBuilder.getMethodId()); this.callBuilder.getInterfaceId(), this.callBuilder.getMethodId());
replacement.params = paramsBuilder; //replacement.params = paramsBuilder;
return replacement.hook.send(); var replacement = new AnyPointer.Request(paramsBuilder, redirected.getHook());
return replacement.send();
} }
final var question = sendInternal(false); final var question = sendInternal(false);
@ -1624,7 +1625,7 @@ final class RpcState {
var loop = CompletableFuture.anyOf( var loop = CompletableFuture.anyOf(
getMessageLoop(), appPromise).thenCompose(x -> appPromise); getMessageLoop(), appPromise).thenCompose(x -> appPromise);
return new RemotePromise<>(loop, pipeline); return new RemotePromise<>(loop, new AnyPointer.Pipeline(pipeline));
} }
@Override @Override