major refactor of RemotePromise and Pipeline
This commit is contained in:
parent
2d8fe31a59
commit
8eacc8cada
15 changed files with 580 additions and 302 deletions
|
@ -34,6 +34,7 @@
|
|||
#include <unistd.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <kj/main.h>
|
||||
#include <algorithm>
|
||||
|
@ -334,9 +335,23 @@ private:
|
|||
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:
|
||||
{
|
||||
auto elementType = type.asList().getElementType();
|
||||
|
@ -394,7 +409,12 @@ private:
|
|||
"_", kj::hex(brandParam->scopeId), "_", suffix);
|
||||
|
||||
} 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,
|
||||
LIST,
|
||||
INTERFACE,
|
||||
ANY_POINTER
|
||||
ANY_POINTER,
|
||||
BRAND_PARAMETER
|
||||
};
|
||||
|
||||
kj::StringTree makeEnumGetter(EnumSchema schema, uint offset, kj::String defaultMaskParam, int indent) {
|
||||
|
@ -753,7 +774,12 @@ private:
|
|||
"_", kj::hex(brandParam->scopeId), "_Factory");
|
||||
|
||||
} 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 : {
|
||||
|
@ -908,6 +934,7 @@ private:
|
|||
|
||||
auto typeBody = slot.getType();
|
||||
auto defaultBody = slot.getDefaultValue();
|
||||
|
||||
switch (typeBody.which()) {
|
||||
case schema::Type::VOID:
|
||||
kind = FieldKind::PRIMITIVE;
|
||||
|
@ -992,10 +1019,27 @@ private:
|
|||
kind = FieldKind::INTERFACE;
|
||||
break;
|
||||
case schema::Type::ANY_POINTER:
|
||||
kind = FieldKind::ANY_POINTER;
|
||||
if (defaultBody.hasAnyPointer()) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1050,7 +1094,8 @@ private:
|
|||
} else if (kind == FieldKind::INTERFACE) {
|
||||
|
||||
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 {
|
||||
kj::strTree(
|
||||
|
@ -1080,11 +1125,16 @@ private:
|
|||
unionDiscrim.set,
|
||||
spaces(indent), " _setPointerField(", factoryArg, ", ", offset, ", value);\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(
|
||||
spaces(indent), " public ", clientType, " get", titleCase, "() {\n",
|
||||
spaces(indent), " return new ", clientType, "(this.getPointerField((short)", offset, ").asCap());\n",
|
||||
spaces(indent), " default ", clientType, " get", titleCase, "() {\n",
|
||||
spaces(indent), " return new ", clientType, "(\n",
|
||||
spaces(indent), " this.typelessPipeline().getPointerField((short)", offset, ").asCap()\n",
|
||||
spaces(indent), " );\n",
|
||||
spaces(indent), " }\n"
|
||||
)
|
||||
};
|
||||
|
@ -1145,7 +1195,8 @@ private:
|
|||
|
||||
auto typeParamVec = getTypeParameters(field.getContainingStruct());
|
||||
auto factoryArg = makeFactoryArg(field.getType());
|
||||
|
||||
auto pipelineType = typeName(field.getType(), kj::str("Pipeline")).flatten();
|
||||
|
||||
return FieldText {
|
||||
kj::strTree(
|
||||
kj::mv(unionDiscrim.readerIsDef),
|
||||
|
@ -1194,6 +1245,12 @@ private:
|
|||
spaces(indent), " return ",
|
||||
"_initPointerField(", factoryArg, ",", offset, ", 0);\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) {
|
||||
|
@ -1374,8 +1431,6 @@ private:
|
|||
spaces(indent), " }\n")
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
};
|
||||
} else {
|
||||
KJ_UNREACHABLE;
|
||||
|
@ -1479,8 +1534,8 @@ private:
|
|||
",(short)", structNode.getPointerCount(), ");\n"),
|
||||
|
||||
spaces(indent), " public static final class Factory", factoryTypeParams, "\n",
|
||||
spaces(indent), " extends org.capnproto.StructFactory<Builder", builderTypeParams, ", Reader", readerTypeParams, ">\n",
|
||||
spaces(indent), " implements org.capnproto.PipelineFactory<Pipeline", readerTypeParams, "> {\n",
|
||||
spaces(indent), " extends org.capnproto.StructFactory<Builder", builderTypeParams, ", Reader", readerTypeParams, "> {\n",
|
||||
//spaces(indent), " implements org.capnproto.PipelineFactory<Pipeline", readerTypeParams, "> {\n",
|
||||
factoryMembers.flatten(),
|
||||
spaces(indent), " public Factory(",
|
||||
factoryArgs.flatten(),
|
||||
|
@ -1515,13 +1570,13 @@ private:
|
|||
(hasTypeParams ? kj::strTree("this") : kj::strTree()),
|
||||
");\n",
|
||||
spaces(indent), " }\n",
|
||||
spaces(indent), " public Pipeline", readerTypeParams, " newPipeline(org.capnproto.RemotePromise<org.capnproto.AnyPointer.Reader> promise) {\n",
|
||||
spaces(indent), " return new Pipeline", readerTypeParamsInferred, "(",
|
||||
kj::StringTree(KJ_MAP(p, typeParamVec) {
|
||||
return kj::strTree(p, "_Factory");
|
||||
}, ", "),
|
||||
(hasTypeParams ? ", ": ""), "promise);\n",
|
||||
spaces(indent), " }\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, "(",
|
||||
//kj::StringTree(KJ_MAP(p, typeParamVec) {
|
||||
// return kj::strTree(p, "_Factory");
|
||||
// }, ", "),
|
||||
//(hasTypeParams ? ", ": ""), "promise, typeless);\n",
|
||||
//spaces(indent), " }\n",
|
||||
|
||||
spaces(indent), " }\n",
|
||||
(hasTypeParams ?
|
||||
|
@ -1609,17 +1664,23 @@ private:
|
|||
spaces(indent), " }\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 Pipeline(",
|
||||
KJ_MAP(p, typeParamVec) {
|
||||
return kj::strTree("org.capnproto.PointerFactory<?,", p, "_Reader> ", p, "_Factory,");
|
||||
}, " org.capnproto.RemotePromise<org.capnproto.AnyPointer.Reader> remotePromise) {\n",
|
||||
spaces(indent), " super(org.capnproto.RemotePromise.fromTypeless(", factoryRef, ", remotePromise));\n",
|
||||
spaces(indent), " }\n",
|
||||
KJ_MAP(f, fieldTexts) { return kj::mv(f.pipelineMethodDecls); },
|
||||
//spaces(indent), " public interface Pipeline", readerTypeParams, " extends org.capnproto.RemotePromise<Reader", readerTypeParams, "> {\n",
|
||||
spaces(indent), " public interface Pipeline", readerTypeParams, " extends org.capnproto.PipelineBase {\n",
|
||||
//spaces(indent), " private final org.capnproto.PipelineImpl typeless;\n",
|
||||
//spaces(indent), " org.capnproto.AnyPointer.Pipeline getTypeless();\n",
|
||||
//spaces(indent), " public Pipeline(",
|
||||
//#KJ_MAP(p, typeParamVec) {
|
||||
// return kj::strTree("org.capnproto.PointerFactory<?,", p, "_Reader> ", p, "_Factory,");
|
||||
//}, " 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",
|
||||
"\n"),
|
||||
spaces(indent), "}\n"),
|
||||
|
||||
kj::strTree(),
|
||||
kj::strTree()
|
||||
|
@ -1633,36 +1694,64 @@ private:
|
|||
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,
|
||||
kj::Array<kj::StringTree> nestedTypeDecls, int indent) {
|
||||
|
||||
auto sp = spaces(indent);
|
||||
auto fullName = kj::str(scope, name);
|
||||
auto methods = KJ_MAP(m, schema.getMethods()) {
|
||||
return makeMethodText(fullName, m);
|
||||
return makeMethodText(fullName, m, indent+2);
|
||||
};
|
||||
|
||||
auto proto = schema.getProto();
|
||||
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::String genericParamTypes;
|
||||
if (proto.getIsGeneric()) {
|
||||
auto typeParams = getTypeParameters(schema);
|
||||
genericParamTypes = kj::strTree(
|
||||
"<",
|
||||
kj::StringTree(
|
||||
KJ_MAP(arg, typeParams) {
|
||||
return kj::strTree(arg);
|
||||
}, ", "),
|
||||
">").flatten();
|
||||
kj::Array<ExtendInfo> transitiveSuperclasses;
|
||||
{
|
||||
std::map<uint64_t, InterfaceSchema> map;
|
||||
getTransitiveSuperclasses(schema, map);
|
||||
map.erase(schema.getProto().getId());
|
||||
transitiveSuperclasses = KJ_MAP(entry, map) {
|
||||
return ExtendInfo {
|
||||
kj::str(javaFullName(entry.second, nullptr)),
|
||||
entry.second.getProto().getId()
|
||||
};
|
||||
};
|
||||
}
|
||||
else {
|
||||
genericParamTypes = kj::str("");
|
||||
}
|
||||
|
||||
|
||||
auto typeNameVec = javaFullName(schema);
|
||||
auto typeParamVec = getTypeParameters(schema);
|
||||
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 builderTypeParamsTree;
|
||||
|
@ -1701,6 +1790,10 @@ private:
|
|||
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::str(kj::strTree("newFactory(",
|
||||
kj::StringTree(KJ_MAP(p, typeParamVec) {
|
||||
|
@ -1712,65 +1805,99 @@ private:
|
|||
|
||||
return InterfaceText {
|
||||
kj::strTree(
|
||||
spaces(indent), "public static class ", name, genericParamTypes, " {\n",
|
||||
|
||||
spaces(indent), " public static final class Factory", factoryTypeParams, "\n",
|
||||
spaces(indent), " extends org.capnproto.Capability.Factory<Client> {\n",
|
||||
sp, "public static class ", name, genericParamTypes, " {\n",
|
||||
sp, " public static final class Factory", factoryTypeParams, "\n",
|
||||
sp, " extends org.capnproto.Capability.Factory<Client> {\n",
|
||||
factoryMembers.flatten(),
|
||||
spaces(indent), " public Factory(",
|
||||
sp, " public Factory(",
|
||||
factoryArgs.flatten(),
|
||||
") {\n",
|
||||
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",
|
||||
|
||||
|
||||
//spaces(indent), " public static final class Factory extends org.capnproto.Capability.Factory<Client> {\n",
|
||||
spaces(indent), " public final Client newClient(org.capnproto.ClientHook hook) {\n",
|
||||
spaces(indent), " return new Client(hook);\n",
|
||||
spaces(indent), " }\n",
|
||||
spaces(indent), " }\n",
|
||||
sp, " }\n",
|
||||
sp, " public final Client newClient(org.capnproto.ClientHook hook) {\n",
|
||||
sp, " return new Client(hook);\n",
|
||||
sp, " }\n",
|
||||
sp, " }\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",
|
||||
spaces(indent), " public static class Client extends org.capnproto.Capability.Client {\n",
|
||||
spaces(indent), " public Client() {}\n",
|
||||
spaces(indent), " public Client(org.capnproto.ClientHook hook) { super(hook); }\n",
|
||||
spaces(indent), " public Client(org.capnproto.Capability.Client cap) { super(cap); }\n",
|
||||
spaces(indent), " public Client(Server server) { super(server); }\n",
|
||||
spaces(indent), " public <T extends Client> Client(java.util.concurrent.CompletionStage<T> promise) {\n",
|
||||
spaces(indent), " super(promise);\n",
|
||||
spaces(indent), " }\n",
|
||||
sp, " public static class Client\n",
|
||||
(superclasses.size() == 0
|
||||
? kj::str(sp, " extends org.capnproto.Capability.Client ")
|
||||
: kj::str(
|
||||
KJ_MAP(s, superclasses) {
|
||||
return kj::strTree(sp, " extends ", s.typeName, ".Client ");
|
||||
})
|
||||
),
|
||||
"{\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",
|
||||
KJ_MAP(m, methods) { return kj::mv(m.clientDefs); },
|
||||
spaces(indent), " }\n",
|
||||
sp, " public static final class Methods {\n",
|
||||
KJ_MAP(m, methods) { return kj::mv(m.clientMethodDefs); },
|
||||
sp, " }\n",
|
||||
"\n",
|
||||
spaces(indent), " public static abstract class Server extends org.capnproto.Capability.Server {\n",
|
||||
spaces(indent), " protected org.capnproto.DispatchCallResult dispatchCall(\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",
|
||||
KJ_MAP(m, methods) { return kj::mv(m.clientCalls); },
|
||||
sp, " }\n",
|
||||
"\n",
|
||||
spaces(indent), " protected org.capnproto.DispatchCallResult dispatchCallInternal(short methodId, org.capnproto.CallContext<org.capnproto.AnyPointer.Reader, org.capnproto.AnyPointer.Builder> context) {\n",
|
||||
spaces(indent), " switch (methodId) {\n",
|
||||
sp, " public static abstract class Server\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); },
|
||||
spaces(indent), " default:\n",
|
||||
spaces(indent), " return org.capnproto.Capability.Server.result(\n",
|
||||
spaces(indent), " org.capnproto.Capability.Server.internalUnimplemented(\"", name, "\", 0x", hexId, "L, methodId));\n",
|
||||
spaces(indent), " }\n",
|
||||
spaces(indent), " }\n\n",
|
||||
sp, " default:\n",
|
||||
sp, " return org.capnproto.Capability.Server.result(\n",
|
||||
sp, " org.capnproto.Capability.Server.internalUnimplemented(\"", name, "\", 0x", hexId, "L, methodId));\n",
|
||||
sp, " }\n",
|
||||
sp, " }\n\n",
|
||||
KJ_MAP(m, methods) { return kj::mv(m.serverDefs); },
|
||||
spaces(indent), " }\n",
|
||||
spaces(indent), "\n",
|
||||
sp, " }\n",
|
||||
sp, "\n",
|
||||
KJ_MAP(n, nestedTypeDecls) { return kj::mv(n); },
|
||||
"\n",
|
||||
spaces(indent), "}\n",
|
||||
sp, "}\n",
|
||||
"\n")
|
||||
};
|
||||
}
|
||||
|
@ -1778,12 +1905,15 @@ private:
|
|||
// -----------------------------------------------------------------
|
||||
|
||||
struct MethodText {
|
||||
kj::StringTree clientDefs;
|
||||
kj::StringTree clientMethodDefs;
|
||||
kj::StringTree clientCalls;
|
||||
kj::StringTree serverDefs;
|
||||
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 methodName = proto.getName();
|
||||
auto titleCase = toTitleCase(methodName);
|
||||
|
@ -1876,7 +2006,10 @@ private:
|
|||
}, ", "),
|
||||
")").flatten();
|
||||
}
|
||||
|
||||
|
||||
auto paramBuilder = kj::str(shortParamType, ".Builder");
|
||||
auto resultReader = kj::str(shortResultType, ".Reader");
|
||||
|
||||
auto interfaceProto = method.getContainingInterface().getProto();
|
||||
uint64_t interfaceId = interfaceProto.getId();
|
||||
auto interfaceIdHex = kj::hex(interfaceId);
|
||||
|
@ -1884,45 +2017,80 @@ private:
|
|||
|
||||
if (isStreaming) {
|
||||
return MethodText {
|
||||
kj::strTree(
|
||||
" public org.capnproto.StreamingRequest<", shortParamType, ".Builder> ", methodName, "Request() {\n",
|
||||
" return newStreamingCall(", paramFactory, ", 0x", interfaceIdHex, "L, (short)", methodId, ");\n"
|
||||
" }\n"),
|
||||
// client method defs
|
||||
kj::strTree(),
|
||||
|
||||
// client call
|
||||
kj::strTree(
|
||||
" protected java.util.concurrent.CompletableFuture<java.lang.Void> ", identifierName, "(org.capnproto.StreamingCallContext<", shortParamType, ".Reader> context) {\n"
|
||||
" return org.capnproto.Capability.Server.internalUnimplemented(\n"
|
||||
" \"", interfaceProto.getDisplayName(), "\", \"", methodName, "\",\n"
|
||||
" 0x", interfaceIdHex, "L, (short)", methodId, ");\n"
|
||||
" }\n\n"),
|
||||
sp, "public org.capnproto.StreamingRequest<", shortParamType, ".Builder> ", methodName, "Request() {\n",
|
||||
sp, " return newStreamingCall(", paramFactory, ", 0x", interfaceIdHex, "L, (short)", methodId, ");\n",
|
||||
sp, "}\n"
|
||||
),
|
||||
|
||||
// server defs
|
||||
kj::strTree(
|
||||
" case ", methodId, ":\n",
|
||||
" return org.capnproto.Capability.Server.streamResult(\n",
|
||||
" this.", identifierName, "(org.capnproto.Capability.Server.internalGetTypedStreamingContext(\n"
|
||||
" ", paramFactory, ", context)));\n")
|
||||
sp, "protected java.util.concurrent.CompletableFuture<java.lang.Void> ", identifierName, "(org.capnproto.StreamingCallContext<", shortParamType, ".Reader> context) {\n",
|
||||
sp, " return org.capnproto.Capability.Server.internalUnimplemented(\n",
|
||||
sp, " \"", interfaceProto.getDisplayName(), "\", \"", methodName, "\",\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 {
|
||||
return MethodText {
|
||||
|
||||
// client method defs
|
||||
kj::strTree(
|
||||
" public org.capnproto.Request<", shortParamType, ".Builder, ", shortResultType, ".Pipeline> ", methodName, "Request() {\n",
|
||||
" return newCall(", paramFactory, ", ", shortResultType, ".factory, 0x", interfaceIdHex, "L, (short)", methodId, ");\n"
|
||||
" }\n"),
|
||||
sp, " public static final class ", methodName, " {\n",
|
||||
sp, " public interface Request extends org.capnproto.Request<", paramBuilder, "> {\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(
|
||||
" protected java.util.concurrent.CompletableFuture<java.lang.Void> ", identifierName, "(org.capnproto.CallContext<", shortParamType, ".Reader, ", shortResultType, ".Builder> context) {\n"
|
||||
" return org.capnproto.Capability.Server.internalUnimplemented(\n"
|
||||
" \"", interfaceProto.getDisplayName(), "\", \"", methodName, "\",\n"
|
||||
" 0x", interfaceIdHex, "L, (short)", methodId, ");\n"
|
||||
" }\n\n"),
|
||||
sp, "public Methods.", methodName, ".Request ", methodName, "Request() {\n",
|
||||
sp, " var result = newCall(0x", interfaceIdHex, "L, (short)", methodId, ");\n",
|
||||
sp, " return () -> result;\n",
|
||||
sp, "}\n"
|
||||
),
|
||||
|
||||
// server defs
|
||||
kj::strTree(
|
||||
" case ", methodId, ":\n",
|
||||
" return org.capnproto.Capability.Server.result (\n",
|
||||
" this.", identifierName, "(org.capnproto.Capability.Server.internalGetTypedContext(\n"
|
||||
" ", paramFactory, ", ", resultFactory, ", context)));\n")
|
||||
sp, "protected java.util.concurrent.CompletableFuture<java.lang.Void> ", identifierName, "(org.capnproto.CallContext<", shortParamType, ".Reader, ", shortResultType, ".Builder> context) {\n",
|
||||
sp, " return org.capnproto.Capability.Server.internalUnimplemented(\n",
|
||||
sp, " \"", interfaceProto.getDisplayName(), "\", \"", methodName, "\", 0x", interfaceIdHex, "L, (short)", methodId, ");\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")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,7 @@ package org.capnproto;
|
|||
|
||||
public final class AnyPointer {
|
||||
public static final class Factory
|
||||
implements PointerFactory<Builder, Reader>,
|
||||
PipelineFactory<Pipeline> {
|
||||
implements PointerFactory<Builder, Reader> {
|
||||
public final Reader fromPointerReader(SegmentReader segment, CapTableReader capTable, int pointer, int nestingLimit) {
|
||||
return new Reader(segment, capTable, pointer, nestingLimit);
|
||||
}
|
||||
|
@ -36,8 +35,8 @@ public final class AnyPointer {
|
|||
result.clear();
|
||||
return result;
|
||||
}
|
||||
public Pipeline newPipeline(RemotePromise<Reader> promise) {
|
||||
return new AnyPointer.Pipeline(promise);
|
||||
public Pipeline newPipeline(PipelineImpl typeless) {
|
||||
return new AnyPointer.Pipeline(typeless.hook, typeless.ops);
|
||||
}
|
||||
}
|
||||
public static final Factory factory = new Factory();
|
||||
|
@ -133,7 +132,7 @@ public final class AnyPointer {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
@ -146,15 +145,55 @@ public final class AnyPointer {
|
|||
}
|
||||
}
|
||||
|
||||
public static final class Pipeline
|
||||
extends org.capnproto.Pipeline<AnyPointer.Reader> {
|
||||
public static class Pipeline extends PipelineImpl implements PipelineBase {
|
||||
|
||||
public Pipeline(RemotePromise<AnyPointer.Reader> promise) {
|
||||
super(promise);
|
||||
public Pipeline(PipelineHook hook) {
|
||||
this(hook, new PipelineOp[0]);
|
||||
}
|
||||
|
||||
public Pipeline(RemotePromise<AnyPointer.Reader> promise, PipelineOp[] ops) {
|
||||
super(promise, ops);
|
||||
Pipeline(PipelineHook hook, PipelineOp[] 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ public class CallContext<Params, Results> {
|
|||
return this.hook.getResults().initAs(results);
|
||||
}
|
||||
|
||||
public final <SubParams, Results> CompletableFuture<java.lang.Void> tailCall(Request<SubParams, Results> tailRequest) {
|
||||
return this.hook.tailCall(tailRequest.hook);
|
||||
public final <SubParams> CompletableFuture<java.lang.Void> tailCall(Request<SubParams> tailRequest) {
|
||||
return this.hook.tailCall(tailRequest.getHook());
|
||||
}
|
||||
|
||||
public final void allowCancellation() {
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.capnproto;
|
|||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class Capability {
|
||||
|
||||
|
@ -13,7 +14,7 @@ public final class Capability {
|
|||
CapTableReader capTable;
|
||||
}
|
||||
|
||||
public static abstract class Factory<T extends Client>
|
||||
public static abstract class Factory<T extends ClientBase>
|
||||
implements FromPointerReader<T>,
|
||||
FromPointerBuilder<T>,
|
||||
SetPointerBuilder<T, T> {
|
||||
|
@ -44,37 +45,21 @@ public final class Capability {
|
|||
}
|
||||
}
|
||||
|
||||
public static class Client {
|
||||
|
||||
final ClientHook hook;
|
||||
|
||||
public Client() {
|
||||
this.hook = null;
|
||||
public static class CapabilityFactory extends Factory<Client> {
|
||||
@Override
|
||||
public Client newClient(ClientHook hook) {
|
||||
return new Client(hook);
|
||||
}
|
||||
}
|
||||
|
||||
public Client(Client other) {
|
||||
this.hook = other.hook;
|
||||
}
|
||||
public static final CapabilityFactory factory = new CapabilityFactory();
|
||||
|
||||
public Client(ClientHook hook) {
|
||||
this.hook = hook;
|
||||
}
|
||||
public interface ClientBase {
|
||||
|
||||
public Client(Server server) {
|
||||
this(makeLocalClient(server));
|
||||
}
|
||||
ClientHook getHook();
|
||||
|
||||
public <T extends Client> Client(CompletionStage<T> promise) {
|
||||
this(Capability.newLocalPromiseClient(
|
||||
promise.thenApply(client -> client.getHook())));
|
||||
}
|
||||
|
||||
public Client(Throwable exc) {
|
||||
this(newBrokenCap(exc));
|
||||
}
|
||||
|
||||
ClientHook getHook() {
|
||||
return this.hook;
|
||||
default CompletionStage<java.lang.Void> whenResolved() {
|
||||
return this.getHook().whenResolved();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,37 +75,72 @@ public final class Capability {
|
|||
* 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.
|
||||
*/
|
||||
public CompletableFuture<Integer> getFd() {
|
||||
var fd = this.hook.getFd();
|
||||
default CompletableFuture<Integer> getFd() {
|
||||
var fd = this.getHook().getFd();
|
||||
if (fd != null) {
|
||||
return CompletableFuture.completedFuture(fd);
|
||||
}
|
||||
var promise = this.hook.whenMoreResolved();
|
||||
var promise = this.getHook().whenMoreResolved();
|
||||
if (promise != null) {
|
||||
return promise.thenCompose(newHook -> new Client(newHook).getFd());
|
||||
}
|
||||
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) {
|
||||
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 {
|
||||
|
@ -136,12 +156,10 @@ public final class Capability {
|
|||
return new LocalClient(capServerSet);
|
||||
}
|
||||
|
||||
|
||||
private final class LocalClient implements ClientHook {
|
||||
private final CompletableFuture<java.lang.Void> resolveTask;
|
||||
private ClientHook resolved;
|
||||
private boolean blocked = false;
|
||||
private Exception brokenException;
|
||||
private final CapabilityServerSetBase capServerSet;
|
||||
|
||||
LocalClient() {
|
||||
|
@ -159,10 +177,10 @@ public final class Capability {
|
|||
}
|
||||
|
||||
@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 root = hook.message.getRoot(AnyPointer.factory);
|
||||
return new Request<>(root, AnyPointer.factory, hook);
|
||||
return new AnyPointer.Request(root, hook);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -173,7 +191,8 @@ public final class Capability {
|
|||
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 -> {
|
||||
ctx.releaseParams();
|
||||
|
@ -186,7 +205,7 @@ public final class Capability {
|
|||
}
|
||||
|
||||
return new VoidPromiseAndPipeline(
|
||||
promise.copy(),
|
||||
promise,
|
||||
new QueuedPipeline(pipelinePromise));
|
||||
}
|
||||
|
||||
|
@ -197,9 +216,15 @@ public final class Capability {
|
|||
|
||||
@Override
|
||||
public CompletableFuture<ClientHook> whenMoreResolved() {
|
||||
return this.resolved != null
|
||||
? CompletableFuture.completedFuture(this.resolved)
|
||||
: this.resolveTask.thenApply(x -> this.resolved);
|
||||
if (this.resolved != null) {
|
||||
return CompletableFuture.completedFuture(this.resolved);
|
||||
}
|
||||
else if (this.resolveTask != null) {
|
||||
return this.resolveTask.thenApply(x -> this.resolved);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -207,11 +232,10 @@ public final class Capability {
|
|||
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(
|
||||
interfaceId,
|
||||
methodId,
|
||||
new CallContext<>(AnyPointer.factory, AnyPointer.factory, context));
|
||||
interfaceId, methodId,
|
||||
new CallContext<>(AnyPointer.factory, AnyPointer.factory, ctx));
|
||||
if (result.isStreaming()) {
|
||||
// TODO streaming
|
||||
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() {
|
||||
return null;
|
||||
}
|
||||
|
@ -320,7 +361,7 @@ public final class Capability {
|
|||
});
|
||||
|
||||
assert promiseAndPipeline.pipeline != null;
|
||||
return new RemotePromise<>(promise, promiseAndPipeline.pipeline);
|
||||
return new RemotePromise<>(promise, new AnyPointer.Pipeline(promiseAndPipeline.pipeline));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -337,12 +378,12 @@ public final class Capability {
|
|||
}
|
||||
|
||||
private static final class LocalPipeline implements PipelineHook {
|
||||
private final CallContextHook context;
|
||||
private final CallContextHook ctx;
|
||||
private final AnyPointer.Reader results;
|
||||
|
||||
LocalPipeline(CallContextHook context) {
|
||||
this.context = context;
|
||||
this.results = context.getResults().asReader();
|
||||
LocalPipeline(CallContextHook ctx) {
|
||||
this.ctx = ctx;
|
||||
this.results = ctx.getResults().asReader();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -439,13 +480,14 @@ public final class Capability {
|
|||
static private ClientHook newBrokenClient(Throwable exc, boolean resolved, Object brand) {
|
||||
return new ClientHook() {
|
||||
@Override
|
||||
public Request<AnyPointer.Builder, AnyPointer.Pipeline> newCall(long interfaceId, short methodId) {
|
||||
return Request.newBrokenRequest(exc);
|
||||
public AnyPointer.Request newCall(long interfaceId, short methodId) {
|
||||
var broken = Request.newBrokenRequest(AnyPointer.factory, exc);
|
||||
return new AnyPointer.Request(broken.getParams(), broken.getHook());
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
|
@ -514,10 +556,10 @@ public final class Capability {
|
|||
}
|
||||
|
||||
@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 root = hook.message.getRoot(AnyPointer.factory);
|
||||
return new Request<>(root, AnyPointer.factory, hook);
|
||||
return new AnyPointer.Request(root, hook);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,7 +8,7 @@ public interface ClientHook {
|
|||
Object NULL_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);
|
||||
|
||||
|
@ -46,7 +46,7 @@ public interface ClientHook {
|
|||
/**
|
||||
* Repeatedly calls whenMoreResolved() until it returns nullptr.
|
||||
*/
|
||||
default CompletionStage<java.lang.Void> whenResolved() {
|
||||
default CompletableFuture<java.lang.Void> whenResolved() {
|
||||
var promise = whenMoreResolved();
|
||||
return promise != null
|
||||
? promise.thenCompose(ClientHook::whenResolved)
|
||||
|
@ -77,13 +77,14 @@ public interface ClientHook {
|
|||
}
|
||||
|
||||
final class VoidPromiseAndPipeline {
|
||||
|
||||
public final CompletableFuture<java.lang.Void> promise;
|
||||
public final PipelineHook pipeline;
|
||||
|
||||
VoidPromiseAndPipeline(CompletableFuture<java.lang.Void> promise, PipelineHook pipeline) {
|
||||
VoidPromiseAndPipeline(CompletableFuture<java.lang.Void> promise,
|
||||
PipelineHook pipeline) {
|
||||
this.promise = promise;
|
||||
this.pipeline = pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
5
runtime/src/main/java/org/capnproto/PipelineBase.java
Normal file
5
runtime/src/main/java/org/capnproto/PipelineBase.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package org.capnproto;
|
||||
|
||||
public interface PipelineBase {
|
||||
AnyPointer.Pipeline typelessPipeline();
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
package org.capnproto;
|
||||
|
||||
public interface PipelineFactory<Pipeline> {
|
||||
Pipeline newPipeline(RemotePromise<AnyPointer.Reader> promise);
|
||||
Pipeline newPipeline(RemotePromise<AnyPointer.Reader> promise, PipelineImpl typeless);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.capnproto;
|
||||
|
||||
public interface PipelineHook {
|
||||
|
||||
ClientHook getPipelinedCap(PipelineOp[] ops);
|
||||
|
||||
static PipelineHook newBrokenPipeline(Throwable exc) {
|
||||
|
|
32
runtime/src/main/java/org/capnproto/PipelineImpl.java
Normal file
32
runtime/src/main/java/org/capnproto/PipelineImpl.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -1,19 +1,35 @@
|
|||
package org.capnproto;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
public class RemotePromise<Results>
|
||||
extends CompletableFutureWrapper<Results> {
|
||||
|
||||
final CompletableFuture<Response<Results>> response;
|
||||
final PipelineHook hook;
|
||||
private final CompletableFuture<Response<Results>> response;
|
||||
private final AnyPointer.Pipeline pipeline;
|
||||
|
||||
RemotePromise(CompletableFuture<Response<Results>> promise,
|
||||
PipelineHook hook) {
|
||||
super(promise.thenApply(response -> response.getResults()));
|
||||
public RemotePromise(FromPointerReader<Results> factory,
|
||||
RemotePromise<AnyPointer.Reader> other) {
|
||||
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.hook = hook;
|
||||
this.pipeline = pipeline;
|
||||
}
|
||||
|
||||
public AnyPointer.Pipeline pipeline() {
|
||||
return this.pipeline;
|
||||
}
|
||||
|
||||
public static <R> RemotePromise<R> fromTypeless(
|
||||
|
@ -21,7 +37,7 @@ public class RemotePromise<Results>
|
|||
RemotePromise<AnyPointer.Reader> typeless) {
|
||||
var promise = typeless.response.thenApply(
|
||||
response -> Response.fromTypeless(resultsFactory, response));
|
||||
return new RemotePromise<>(promise, typeless.hook);
|
||||
return new RemotePromise<>(promise, typeless.pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,31 +2,22 @@ package org.capnproto;
|
|||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class Request<Params, Results> {
|
||||
public interface Request<Params> {
|
||||
|
||||
protected Params params;
|
||||
private PipelineFactory<Results> pipelineFactory;
|
||||
RequestHook hook;
|
||||
FromPointerBuilder<Params> getParamsFactory();
|
||||
|
||||
public Request(Params params,
|
||||
PipelineFactory<Results> pipelineFactory,
|
||||
RequestHook hook) {
|
||||
this.params = params;
|
||||
this.pipelineFactory = pipelineFactory;
|
||||
this.hook = hook;
|
||||
default Params getParams() {
|
||||
return this.getTypelessRequest().getParams().getAs(this.getParamsFactory());
|
||||
}
|
||||
|
||||
public Params getParams() {
|
||||
return params;
|
||||
default RequestHook getHook() {
|
||||
return this.getTypelessRequest().getHook();
|
||||
}
|
||||
|
||||
public Results send() {
|
||||
var typelessPromise = this.hook.send();
|
||||
this.hook = null; // prevent reuse
|
||||
return pipelineFactory.newPipeline(typelessPromise);
|
||||
}
|
||||
Request<AnyPointer.Builder> getTypelessRequest();
|
||||
|
||||
static <P, R> Request<P, R> newBrokenRequest(Throwable exc) {
|
||||
static <Params> Request<Params> newBrokenRequest(FromPointerBuilder<Params> paramsFactory,
|
||||
Throwable exc) {
|
||||
|
||||
final MessageBuilder message = new MessageBuilder();
|
||||
|
||||
|
@ -48,13 +39,32 @@ public class Request<Params, Results> {
|
|||
};
|
||||
|
||||
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(
|
||||
FromPointerBuilder<P> paramsFactory,
|
||||
PipelineFactory<R> pipelineFactory,
|
||||
Request<AnyPointer.Builder, AnyPointer.Pipeline> typeless) {
|
||||
return new Request<>(typeless.params.getAs(paramsFactory), pipelineFactory, typeless.hook);
|
||||
static <Params> Request<Params> fromTypeless(
|
||||
FromPointerBuilder<Params> paramsFactory,
|
||||
Request<AnyPointer.Builder> typeless) {
|
||||
return new Request<>() {
|
||||
@Override
|
||||
public FromPointerBuilder<Params> getParamsFactory() {
|
||||
return paramsFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request<AnyPointer.Builder> getTypelessRequest() {
|
||||
return typeless;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package org.capnproto;
|
||||
|
||||
public class Response<Results> {
|
||||
public final class Response<Results> {
|
||||
|
||||
private Results results;
|
||||
private ResponseHook hook;
|
||||
private final Results results;
|
||||
private final ResponseHook hook;
|
||||
|
||||
public Response(Results results,
|
||||
ResponseHook hook) {
|
||||
|
@ -15,6 +15,10 @@ public class Response<Results> {
|
|||
return this.results;
|
||||
}
|
||||
|
||||
public ResponseHook getHook() {
|
||||
return this.hook;
|
||||
}
|
||||
|
||||
static <R> Response<R> fromTypeless(FromPointerReader<R> resultsFactory,
|
||||
Response<AnyPointer.Reader> typeless) {
|
||||
return new Response<>(typeless.getResults().getAs(resultsFactory), typeless.hook);
|
||||
|
|
|
@ -5,13 +5,13 @@ import java.util.Map;
|
|||
|
||||
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> serverReturnTypes = new HashMap<>();
|
||||
|
||||
void addSchema(long schemaId, Schema.Node.Reader node) {
|
||||
/*void addSchema(long schemaId, Schema.Node.Reader node) {
|
||||
this.schemas.put(schemaId, node);
|
||||
}
|
||||
}*/
|
||||
|
||||
private void setReturnType(RpcTwoPartyProtocol.Side side, int schemaId, long schema) {
|
||||
switch (side) {
|
||||
|
@ -68,7 +68,7 @@ public class RpcDumper {
|
|||
var payload = call.getParams();
|
||||
var params = payload.getContent();
|
||||
var sendResultsTo = call.getSendResultsTo();
|
||||
|
||||
/*
|
||||
var schema = this.schemas.get(iface);
|
||||
if (schema != null) {
|
||||
interfaceName = schema.getDisplayName().toString();
|
||||
|
@ -91,7 +91,7 @@ public class RpcDumper {
|
|||
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
yield sender.name() + "(" + call.getQuestionId() + "): call " +
|
||||
call.getTarget() + " <- " + interfaceName + "." +
|
||||
|
|
|
@ -1532,7 +1532,7 @@ final class RpcState {
|
|||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
|
@ -1545,7 +1545,7 @@ final class RpcState {
|
|||
var params = context.getParams();
|
||||
var request = newCallNoIntercept(interfaceId, methodId);
|
||||
context.allowCancellation();
|
||||
return context.directTailCall(request.hook);
|
||||
return context.directTailCall(request.getHook());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1553,9 +1553,9 @@ final class RpcState {
|
|||
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()) {
|
||||
return Request.newBrokenRequest(disconnected);
|
||||
return Request.newBrokenRequest(AnyPointer.factory, disconnected);
|
||||
}
|
||||
|
||||
var request = new RpcRequest(this);
|
||||
|
@ -1563,7 +1563,7 @@ final class RpcState {
|
|||
callBuilder.setInterfaceId(interfaceId);
|
||||
callBuilder.setMethodId(methodId);
|
||||
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());
|
||||
if (redirect != null) {
|
||||
var replacement = redirect.newCall(
|
||||
var redirected = redirect.newCall(
|
||||
this.callBuilder.getInterfaceId(), this.callBuilder.getMethodId());
|
||||
replacement.params = paramsBuilder;
|
||||
return replacement.hook.send();
|
||||
//replacement.params = paramsBuilder;
|
||||
var replacement = new AnyPointer.Request(paramsBuilder, redirected.getHook());
|
||||
return replacement.send();
|
||||
}
|
||||
|
||||
final var question = sendInternal(false);
|
||||
|
@ -1624,7 +1625,7 @@ final class RpcState {
|
|||
var loop = CompletableFuture.anyOf(
|
||||
getMessageLoop(), appPromise).thenCompose(x -> appPromise);
|
||||
|
||||
return new RemotePromise<>(loop, pipeline);
|
||||
return new RemotePromise<>(loop, new AnyPointer.Pipeline(pipeline));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue