twoparty rpc
This commit is contained in:
parent
f5e4630aef
commit
4a77f67819
23 changed files with 2017 additions and 122 deletions
|
@ -73,12 +73,19 @@ public final class AnyPointer {
|
||||||
return factory.fromPointerReader(this.segment, this.capTable, this.pointer, this.nestingLimit);
|
return factory.fromPointerReader(this.segment, this.capTable, this.pointer, this.nestingLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final Capability.Client getAsCapability() {
|
||||||
|
return new Capability.Client(
|
||||||
|
WireHelpers.readCapabilityPointer(this.segment, capTable, this.pointer, 0));
|
||||||
|
}
|
||||||
|
|
||||||
public final ClientHook getPipelinedCap(PipelineOp[] ops) {
|
public final ClientHook getPipelinedCap(PipelineOp[] ops) {
|
||||||
for (var op: ops) {
|
for (var op: ops) {
|
||||||
switch (op.type) {
|
switch (op.type) {
|
||||||
case NOOP:
|
case NOOP:
|
||||||
break;
|
break;
|
||||||
case GET_POINTER_FIELD:
|
case GET_POINTER_FIELD:
|
||||||
|
var index = op.pointerIndex;
|
||||||
|
// TODO getpointerfield
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import java.util.concurrent.CompletableFuture;
|
||||||
public class CallContext<Params, Results> {
|
public class CallContext<Params, Results> {
|
||||||
|
|
||||||
final CallContextHook hook;
|
final CallContextHook hook;
|
||||||
final FromPointerReader<Params> params;
|
private final FromPointerReader<Params> params;
|
||||||
final FromPointerBuilder<Results> results;
|
private final FromPointerBuilder<Results> results;
|
||||||
|
|
||||||
CallContext(FromPointerReader<Params> params,
|
CallContext(FromPointerReader<Params> params,
|
||||||
FromPointerBuilder<Results> results,
|
FromPointerBuilder<Results> results,
|
||||||
|
|
|
@ -25,7 +25,7 @@ public final class Capability {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Client(Throwable exc) {
|
public Client(Throwable exc) {
|
||||||
this(ClientHook.newBrokenCap(exc));
|
this(newBrokenCap(exc));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientHook getHook() {
|
public ClientHook getHook() {
|
||||||
|
@ -46,12 +46,16 @@ public final class Capability {
|
||||||
FromPointerReader<U> reader,
|
FromPointerReader<U> reader,
|
||||||
long interfaceId, short methodId) {
|
long interfaceId, short methodId) {
|
||||||
var request = hook.newCall(interfaceId, methodId);
|
var request = hook.newCall(interfaceId, methodId);
|
||||||
return new Request<T, U> (request.params, reader, request.hook);
|
return new Request<T, U> (builder, reader, request.params, request.hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Request<AnyPointer.Builder, AnyPointer.Reader> newCall(long interfaceId, short methodId) {
|
public Request<AnyPointer.Builder, AnyPointer.Reader> newCall(long interfaceId, short methodId) {
|
||||||
return hook.newCall(interfaceId, methodId);
|
return hook.newCall(interfaceId, methodId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ClientHook makeLocalClient(Capability.Server server) {
|
||||||
|
return server.makeLocalClient();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract static class Server {
|
public abstract static class Server {
|
||||||
|
@ -79,7 +83,7 @@ public final class Capability {
|
||||||
public Request<AnyPointer.Builder, AnyPointer.Reader> newCall(long interfaceId, short methodId) {
|
public Request<AnyPointer.Builder, AnyPointer.Reader> 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 Request<>(AnyPointer.factory, AnyPointer.factory, root, hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -99,9 +103,11 @@ public final class Capability {
|
||||||
return new LocalPipeline(ctx);
|
return new LocalPipeline(ctx);
|
||||||
});
|
});
|
||||||
|
|
||||||
pipelinePromise = ctx.onTailCall().applyToEither(pipelinePromise, pipeline -> {
|
var tailCall = ctx.onTailCall();
|
||||||
return pipeline;
|
// TODO implement tailCall
|
||||||
});
|
if (tailCall != null) {
|
||||||
|
pipelinePromise = tailCall.applyToEither(pipelinePromise, pipeline -> pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
return new VoidPromiseAndPipeline(forked, new QueuedPipeline(pipelinePromise));
|
return new VoidPromiseAndPipeline(forked, new QueuedPipeline(pipelinePromise));
|
||||||
}
|
}
|
||||||
|
@ -116,11 +122,11 @@ public final class Capability {
|
||||||
return BRAND;
|
return BRAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletableFuture<java.lang.Void> callInternal(long interfaceId, short methodId, CallContextHook context) {
|
CompletableFuture<?> callInternal(long interfaceId, short methodId, CallContextHook context) {
|
||||||
var result = dispatchCall(
|
var result = dispatchCall(
|
||||||
interfaceId,
|
interfaceId,
|
||||||
methodId,
|
methodId,
|
||||||
new CallContext(AnyPointer.factory, AnyPointer.factory, context));
|
new CallContext<>(AnyPointer.factory, AnyPointer.factory, context));
|
||||||
if (result.streaming) {
|
if (result.streaming) {
|
||||||
// TODO streaming
|
// TODO streaming
|
||||||
return null;
|
return null;
|
||||||
|
@ -141,11 +147,11 @@ public final class Capability {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class DispatchCallResult {
|
final class DispatchCallResult {
|
||||||
private final CompletableFuture<java.lang.Void> promise;
|
private final CompletableFuture<?> promise;
|
||||||
private final boolean streaming;
|
private final boolean streaming;
|
||||||
|
|
||||||
public DispatchCallResult(CompletableFuture<java.lang.Void> promise) {
|
public DispatchCallResult(CompletableFuture<?> promise) {
|
||||||
this.promise = promise;
|
this.promise = promise;
|
||||||
this.streaming = false;
|
this.streaming = false;
|
||||||
}
|
}
|
||||||
|
@ -155,7 +161,7 @@ public final class Capability {
|
||||||
this.streaming = false;
|
this.streaming = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchCallResult(CompletableFuture<java.lang.Void> promise, boolean isStreaming) {
|
DispatchCallResult(CompletableFuture<?> promise, boolean isStreaming) {
|
||||||
this.promise = promise;
|
this.promise = promise;
|
||||||
this.streaming = isStreaming;
|
this.streaming = isStreaming;
|
||||||
}
|
}
|
||||||
|
@ -201,10 +207,14 @@ public final class Capability {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ClientHook newLocalPromiseClient(CompletableFuture<ClientHook> promise) {
|
public static ClientHook newLocalPromiseClient(CompletableFuture<ClientHook> promise) {
|
||||||
return new QueuedClient(promise);
|
return new QueuedClient(promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PipelineHook newLocalPromisePipeline(CompletableFuture<PipelineHook> promise) {
|
||||||
|
return new QueuedPipeline(promise);
|
||||||
|
}
|
||||||
|
|
||||||
static class LocalRequest implements RequestHook {
|
static class LocalRequest implements RequestHook {
|
||||||
|
|
||||||
final MessageBuilder message = new MessageBuilder();
|
final MessageBuilder message = new MessageBuilder();
|
||||||
|
@ -315,4 +325,49 @@ public final class Capability {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ClientHook newBrokenCap(String reason) {
|
||||||
|
return newBrokenClient(reason, false, ClientHook.BROKEN_CAPABILITY_BRAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClientHook newBrokenCap(Throwable exc) {
|
||||||
|
return newBrokenClient(exc, false, ClientHook.BROKEN_CAPABILITY_BRAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClientHook newNullCap() {
|
||||||
|
return newBrokenClient(new RuntimeException("Called null capability"), true, ClientHook.NULL_CAPABILITY_BRAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
static private ClientHook newBrokenClient(String reason, boolean resolved, Object brand) {
|
||||||
|
return newBrokenClient(new RuntimeException(reason), resolved, brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
static private ClientHook newBrokenClient(Throwable exc, boolean resolved, Object brand) {
|
||||||
|
return new ClientHook() {
|
||||||
|
@Override
|
||||||
|
public Request<AnyPointer.Builder, AnyPointer.Reader> newCall(long interfaceId, short methodId) {
|
||||||
|
return Request.newBrokenRequest(exc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoidPromiseAndPipeline call(long interfaceId, short methodId, CallContextHook context) {
|
||||||
|
return new VoidPromiseAndPipeline(CompletableFuture.failedFuture(exc), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<ClientHook> whenMoreResolved() {
|
||||||
|
if (resolved) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return CompletableFuture.failedFuture(exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBrand() {
|
||||||
|
return brand;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,56 +43,13 @@ public interface ClientHook {
|
||||||
}
|
}
|
||||||
|
|
||||||
final class VoidPromiseAndPipeline {
|
final class VoidPromiseAndPipeline {
|
||||||
public final CompletableFuture<java.lang.Void> promise;
|
public final CompletableFuture<?> promise;
|
||||||
public final PipelineHook pipeline;
|
public final PipelineHook pipeline;
|
||||||
|
|
||||||
VoidPromiseAndPipeline(CompletableFuture<java.lang.Void> promise, PipelineHook pipeline) {
|
VoidPromiseAndPipeline(CompletableFuture<?> promise, PipelineHook pipeline) {
|
||||||
this.promise = promise;
|
this.promise = promise;
|
||||||
this.pipeline = pipeline;
|
this.pipeline = pipeline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ClientHook newBrokenCap(String reason) {
|
|
||||||
return newBrokenClient(reason, false, BROKEN_CAPABILITY_BRAND);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ClientHook newBrokenCap(Throwable exc) {
|
|
||||||
return newBrokenClient(exc, false, BROKEN_CAPABILITY_BRAND);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ClientHook newNullCap() {
|
|
||||||
return newBrokenClient(new RuntimeException("Called null capability"), true, NULL_CAPABILITY_BRAND);
|
|
||||||
}
|
|
||||||
|
|
||||||
static private ClientHook newBrokenClient(String reason, boolean resolved, Object brand) {
|
|
||||||
return newBrokenClient(new RuntimeException(reason), resolved, brand);
|
|
||||||
}
|
|
||||||
|
|
||||||
static private ClientHook newBrokenClient(Throwable exc, boolean resolved, Object brand) {
|
|
||||||
return new ClientHook() {
|
|
||||||
@Override
|
|
||||||
public Request<AnyPointer.Builder, AnyPointer.Reader> newCall(long interfaceId, short methodId) {
|
|
||||||
return Request.newBrokenRequest(exc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VoidPromiseAndPipeline call(long interfaceId, short methodId, CallContextHook context) {
|
|
||||||
return new VoidPromiseAndPipeline(CompletableFuture.failedFuture(exc), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompletableFuture<ClientHook> whenMoreResolved() {
|
|
||||||
if (resolved) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return CompletableFuture.failedFuture(exc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getBrand() {
|
|
||||||
return brand;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,14 @@ import java.util.PriorityQueue;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
class ExportTable<T> implements Iterable<T> {
|
abstract class ExportTable<T> implements Iterable<T> {
|
||||||
|
|
||||||
final HashMap<Integer, T> slots = new HashMap<>();
|
final HashMap<Integer, T> slots = new HashMap<>();
|
||||||
final Queue<Integer> freeIds = new PriorityQueue<>();
|
final Queue<Integer> freeIds = new PriorityQueue<>();
|
||||||
int max = 0;
|
int max = 0;
|
||||||
|
|
||||||
|
abstract T newExportable(int id);
|
||||||
|
|
||||||
public T find(int id) {
|
public T find(int id) {
|
||||||
return slots.get(id);
|
return slots.get(id);
|
||||||
}
|
}
|
||||||
|
@ -26,17 +28,12 @@ class ExportTable<T> implements Iterable<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int next(T value) {
|
public T next() {
|
||||||
if (freeIds.isEmpty()) {
|
int id = freeIds.isEmpty() ? max++ : freeIds.remove();
|
||||||
var id = max;
|
var value = newExportable(id);
|
||||||
max++;
|
var prev = slots.put(id, value);
|
||||||
slots.put(id, value);
|
assert prev == null;
|
||||||
return id;
|
return value;
|
||||||
} else {
|
|
||||||
var id = freeIds.remove();
|
|
||||||
slots.put(id, value);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,6 +5,6 @@ interface PipelineHook {
|
||||||
ClientHook getPipelinedCap(PipelineOp[] ops);
|
ClientHook getPipelinedCap(PipelineOp[] ops);
|
||||||
|
|
||||||
static PipelineHook newBrokenPipeline(Throwable exc) {
|
static PipelineHook newBrokenPipeline(Throwable exc) {
|
||||||
return ops -> ClientHook.newBrokenCap(exc);
|
return ops -> Capability.newBrokenCap(exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ class QueuedClient implements ClientHook {
|
||||||
this.setResolutionOp = promise.thenAccept(inner -> {
|
this.setResolutionOp = promise.thenAccept(inner -> {
|
||||||
this.redirect = inner;
|
this.redirect = inner;
|
||||||
}).exceptionally(exc -> {
|
}).exceptionally(exc -> {
|
||||||
this.redirect = ClientHook.newBrokenCap(exc);
|
this.redirect = Capability.newBrokenCap(exc);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ class QueuedClient implements ClientHook {
|
||||||
public Request<AnyPointer.Builder, AnyPointer.Reader> newCall(long interfaceId, short methodId) {
|
public Request<AnyPointer.Builder, AnyPointer.Reader> newCall(long interfaceId, short methodId) {
|
||||||
var hook = new Capability.LocalRequest(interfaceId, methodId, this);
|
var hook = new Capability.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 Request<>(AnyPointer.factory, AnyPointer.factory, root, hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,25 +4,29 @@ import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class Request<Params, Results> {
|
public class Request<Params, Results> {
|
||||||
|
|
||||||
final AnyPointer.Builder params;
|
AnyPointer.Builder params;
|
||||||
private final FromPointerReader<Results> results;
|
private final FromPointerBuilder<Params> paramsBuilder;
|
||||||
|
private final FromPointerReader<Results> resultsReader;
|
||||||
RequestHook hook;
|
RequestHook hook;
|
||||||
|
|
||||||
Request(AnyPointer.Builder params, FromPointerReader<Results> results, RequestHook hook) {
|
Request(FromPointerBuilder<Params> paramsBuilder,
|
||||||
|
FromPointerReader<Results> resultsReader,
|
||||||
|
AnyPointer.Builder params, RequestHook hook) {
|
||||||
|
this.paramsBuilder = paramsBuilder;
|
||||||
|
this.resultsReader = resultsReader;
|
||||||
this.params = params;
|
this.params = params;
|
||||||
this.results = results;
|
|
||||||
this.hook = hook;
|
this.hook = hook;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnyPointer.Builder params() {
|
Params params() {
|
||||||
return params;
|
return params.getAs(paramsBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletableFuture<Results> send() {
|
CompletableFuture<Results> send() {
|
||||||
var typelessPromise = hook.send();
|
var typelessPromise = hook.send();
|
||||||
hook = null; // prevent reuse
|
hook = null; // prevent reuse
|
||||||
return typelessPromise.getResponse().thenApply(response -> {
|
return typelessPromise.getResponse().thenApply(response -> {
|
||||||
return response.getAs(results);
|
return response.getAs(resultsReader);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +46,17 @@ public class Request<Params, Results> {
|
||||||
};
|
};
|
||||||
|
|
||||||
var root = message.getRoot(AnyPointer.factory);
|
var root = message.getRoot(AnyPointer.factory);
|
||||||
return new Request<T, U>(root, null, hook);
|
return new Request<T, U>(null, null, root, hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Request<AnyPointer.Builder, AnyPointer.Reader> newTypelessRequest(AnyPointer.Builder root, RequestHook hook) {
|
||||||
|
return new Request<>(AnyPointer.factory, AnyPointer.factory, root, hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
static <Params, Results> Request<Params, Results> fromTypeless(FromPointerBuilder<Params> params,
|
||||||
|
FromPointerReader<Results> results,
|
||||||
|
Request<AnyPointer.Builder, AnyPointer.Reader> typeless) {
|
||||||
|
return new Request<>(params, results, typeless.params(), typeless.hook);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,20 @@ package org.capnproto;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CompletionStage;
|
import java.util.concurrent.CompletionStage;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
final class RpcState {
|
final class RpcState {
|
||||||
|
|
||||||
static final class Question {
|
static final class Question {
|
||||||
|
final int id;
|
||||||
List<Integer> paramExports;
|
List<Integer> paramExports;
|
||||||
boolean isAwaitingReturn = false;
|
boolean isAwaitingReturn = false;
|
||||||
boolean isTailCall = false;
|
boolean isTailCall = false;
|
||||||
boolean skipFinish = false;
|
boolean skipFinish = false;
|
||||||
|
|
||||||
|
Question(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
CompletableFuture<RpcResponse> response = new CompletableFuture<>();
|
CompletableFuture<RpcResponse> response = new CompletableFuture<>();
|
||||||
|
|
||||||
void reject(Throwable exc) {
|
void reject(Throwable exc) {
|
||||||
|
@ -32,9 +37,14 @@ final class RpcState {
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class Export {
|
static final class Export {
|
||||||
|
final int id;
|
||||||
int refcount;
|
int refcount;
|
||||||
ClientHook clientHook;
|
ClientHook clientHook;
|
||||||
CompletionStage<?> resolveOp;
|
CompletionStage<?> resolveOp;
|
||||||
|
|
||||||
|
Export(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class Import {
|
static final class Import {
|
||||||
|
@ -45,11 +55,27 @@ final class RpcState {
|
||||||
}
|
}
|
||||||
|
|
||||||
final static class Embargo {
|
final static class Embargo {
|
||||||
CompletableFuture<java.lang.Void> fulfiller;
|
final int id;
|
||||||
|
CompletableFuture<?> disembargo;
|
||||||
|
|
||||||
|
Embargo(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ExportTable<Export> exports = new ExportTable<Export>();
|
private final ExportTable<Export> exports = new ExportTable<Export>() {
|
||||||
private final ExportTable<Question> questions = new ExportTable<Question>();
|
@Override
|
||||||
|
Export newExportable(int id) {
|
||||||
|
return new Export(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final ExportTable<Question> questions = new ExportTable<Question>() {
|
||||||
|
@Override
|
||||||
|
Question newExportable(int id) {
|
||||||
|
return new Question(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private final ImportTable<Answer> answers = new ImportTable<Answer>() {
|
private final ImportTable<Answer> answers = new ImportTable<Answer>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -65,25 +91,95 @@ final class RpcState {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final ExportTable<Embargo> embargos = new ExportTable<Embargo>();
|
private final ExportTable<Embargo> embargos = new ExportTable<Embargo>() {
|
||||||
|
@Override
|
||||||
|
Embargo newExportable(int id) {
|
||||||
|
return new Embargo(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private final HashMap<ClientHook, Integer> exportsByCap = new HashMap<>();
|
private final HashMap<ClientHook, Integer> exportsByCap = new HashMap<>();
|
||||||
private final VatNetwork.Connection connection;
|
private final VatNetwork.Connection connection;
|
||||||
private final Capability.Client bootstrapInterface;
|
private final Capability.Client bootstrapInterface;
|
||||||
private Throwable disconnected = null;
|
private Throwable disconnected = null;
|
||||||
|
private CompletableFuture<?> messageReady = CompletableFuture.completedFuture(null);
|
||||||
|
|
||||||
RpcState(VatNetwork.Connection connection, Capability.Client bootstrapInterface) {
|
RpcState(VatNetwork.Connection connection, Capability.Client bootstrapInterface) {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.bootstrapInterface = bootstrapInterface;
|
this.bootstrapInterface = bootstrapInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isDisconnected() {
|
final boolean isDisconnected() {
|
||||||
return this.disconnected != null;
|
return this.disconnected != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleMessage(IncomingRpcMessage message) throws RpcException {
|
final boolean isConnected() {
|
||||||
var reader = message.getBody().getAs(RpcProtocol.Message.factory);
|
return !isDisconnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientHook restore() {
|
||||||
|
var question = questions.next();
|
||||||
|
question.isAwaitingReturn = true;
|
||||||
|
question.paramExports = List.of();
|
||||||
|
var message = connection.newOutgoingMessage(64);
|
||||||
|
var builder = message.getBody().initAs(RpcProtocol.Message.factory).initBootstrap();
|
||||||
|
builder.setQuestionId(question.id);
|
||||||
|
message.send();
|
||||||
|
var pipeline = new RpcPipeline(question);
|
||||||
|
return pipeline.getPipelinedCap(new PipelineOp[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// run message loop once
|
||||||
|
final CompletableFuture<?> runOnce() {
|
||||||
|
|
||||||
|
if (isDisconnected()) {
|
||||||
|
return CompletableFuture.failedFuture(disconnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!messageReady.isDone()) {
|
||||||
|
return messageReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
messageReady = connection.receiveIncomingMessage().thenAccept(message -> {
|
||||||
|
try {
|
||||||
|
handleMessage(message);
|
||||||
|
}
|
||||||
|
catch (Exception exc) {
|
||||||
|
this.disconnected = exc;
|
||||||
|
}
|
||||||
|
}).exceptionally(exc -> {
|
||||||
|
this.disconnected = exc;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return messageReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
// run message loop until promise is completed
|
||||||
|
public final <T> CompletableFuture<T> messageLoop(CompletableFuture<T> done) {
|
||||||
|
if (done.isDone()) {
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDisconnected()) {
|
||||||
|
done.completeExceptionally(disconnected);
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection.receiveIncomingMessage().thenCompose(message -> {
|
||||||
|
try {
|
||||||
|
handleMessage(message);
|
||||||
|
}
|
||||||
|
catch (Exception exc) {
|
||||||
|
done.completeExceptionally(exc);
|
||||||
|
}
|
||||||
|
return messageLoop(done);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void handleMessage(IncomingRpcMessage message) throws RpcException {
|
||||||
|
var reader = message.getBody().getAs(RpcProtocol.Message.factory);
|
||||||
|
System.out.println(reader.which());
|
||||||
switch (reader.which()) {
|
switch (reader.which()) {
|
||||||
case UNIMPLEMENTED:
|
case UNIMPLEMENTED:
|
||||||
handleUnimplemented(reader.getUnimplemented());
|
handleUnimplemented(reader.getUnimplemented());
|
||||||
|
@ -194,7 +290,7 @@ final class RpcState {
|
||||||
answer.resultExports = writeDescriptors(capTableArray, payload, fds);
|
answer.resultExports = writeDescriptors(capTableArray, payload, fds);
|
||||||
answer.pipeline = ops -> ops.length == 0
|
answer.pipeline = ops -> ops.length == 0
|
||||||
? capHook
|
? capHook
|
||||||
: ClientHook.newBrokenCap("Invalid pipeline transform.");
|
: Capability.newBrokenCap("Invalid pipeline transform.");
|
||||||
|
|
||||||
response.send();
|
response.send();
|
||||||
|
|
||||||
|
@ -204,9 +300,148 @@ final class RpcState {
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleCall(IncomingRpcMessage message, RpcProtocol.Call.Reader call) {
|
void handleCall(IncomingRpcMessage message, RpcProtocol.Call.Reader call) {
|
||||||
|
var cap = getMessageTarget(call.getTarget());
|
||||||
|
if (cap == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean redirectResults;
|
||||||
|
switch (call.getSendResultsTo().which()) {
|
||||||
|
case CALLER:
|
||||||
|
redirectResults = false;
|
||||||
|
break;
|
||||||
|
case YOURSELF:
|
||||||
|
redirectResults = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert false: "Unsupported 'Call.sendResultsTo'.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload = call.getParams();
|
||||||
|
var capTableArray = receiveCaps(payload.getCapTable(), message.getAttachedFds());
|
||||||
|
var answerId = call.getQuestionId();
|
||||||
|
var cancel = new CompletableFuture<java.lang.Void>();
|
||||||
|
var context = new RpcCallContext(
|
||||||
|
answerId, message, capTableArray,
|
||||||
|
payload.getContent(), redirectResults, cancel,
|
||||||
|
call.getInterfaceId(), call.getMethodId());
|
||||||
|
|
||||||
|
{
|
||||||
|
var answer = answers.put(answerId);
|
||||||
|
assert !answer.active : "questionId is already in use";
|
||||||
|
if (answer.active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
answer.active = true;
|
||||||
|
answer.callContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pap = startCall(call.getInterfaceId(), call.getMethodId(), cap, context);
|
||||||
|
{
|
||||||
|
var answer = answers.find(answerId);
|
||||||
|
assert answer != null;
|
||||||
|
answer.pipeline = pap.pipeline;
|
||||||
|
|
||||||
|
if (redirectResults) {
|
||||||
|
answer.redirectedResults = pap.promise.thenApply(x -> {
|
||||||
|
return context.consumeRedirectedResponse();
|
||||||
|
});
|
||||||
|
// TODO cancellation deferral
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pap.promise.thenAccept(x -> {
|
||||||
|
context.sendReturn();
|
||||||
|
}).exceptionally(exc -> {
|
||||||
|
context.sendErrorReturn(exc);
|
||||||
|
// TODO wait on the cancellation...
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientHook.VoidPromiseAndPipeline startCall(long interfaceId, short methodId, ClientHook cap, RpcCallContext context) {
|
||||||
|
// TODO gateways...?
|
||||||
|
return cap.call(interfaceId, methodId, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleReturn(IncomingRpcMessage message, RpcProtocol.Return.Reader callReturn) {
|
void handleReturn(IncomingRpcMessage message, RpcProtocol.Return.Reader callReturn) {
|
||||||
|
var exportsToRelease = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
var question = questions.find(callReturn.getAnswerId());
|
||||||
|
assert question != null : "Invalid question ID in Return message.";
|
||||||
|
if (question == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert question.isAwaitingReturn: "Duplicate Return";
|
||||||
|
if (!question.isAwaitingReturn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
question.isAwaitingReturn = false;
|
||||||
|
if (callReturn.getReleaseParamCaps()) {
|
||||||
|
exportsToRelease.addAll(question.paramExports);
|
||||||
|
question.paramExports = List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert !callReturn.isTakeFromOtherQuestion(): "Not implemented";
|
||||||
|
if (callReturn.isTakeFromOtherQuestion()) {
|
||||||
|
// TODO process isTakeFromOtherQuestion...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (callReturn.which()) {
|
||||||
|
case RESULTS:
|
||||||
|
if (question.isTailCall) {
|
||||||
|
// TODO resultsSentElsewhere
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var payload = callReturn.getResults();
|
||||||
|
var capTable = receiveCaps(payload.getCapTable(), message.getAttachedFds());
|
||||||
|
var response = new RpcResponseImpl(question, message, capTable, payload.getContent());
|
||||||
|
question.answer(response);
|
||||||
|
break;
|
||||||
|
case EXCEPTION:
|
||||||
|
assert !question.isTailCall : "Tail call `Return` must set `resultsSentElsewhere`, not `exception`.";
|
||||||
|
if (question.isTailCall) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
question.reject(RpcException.toException(callReturn.getException()));
|
||||||
|
break;
|
||||||
|
case CANCELED:
|
||||||
|
assert false : "Return message falsely claims call was canceled.";
|
||||||
|
break;
|
||||||
|
case RESULTS_SENT_ELSEWHERE:
|
||||||
|
assert question.isTailCall : "`Return` had `resultsSentElsewhere` but this was not a tail call.";
|
||||||
|
if (!question.isTailCall) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Tail calls are fulfilled with a null pointer.
|
||||||
|
question.answer(() -> null);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAKE_FROM_OTHER_QUESTION:
|
||||||
|
var other = callReturn.getTakeFromOtherQuestion();
|
||||||
|
var answer = answers.find(other);
|
||||||
|
assert answer != null : "`Return.takeFromOtherQuestion` had invalid answer ID.";
|
||||||
|
if (answer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert answer.redirectedResults != null : "`Return.takeFromOtherQuestion` referenced a call that did not use `sendResultsTo.yourself`.";
|
||||||
|
if (answer.redirectedResults == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
question.response = answer.redirectedResults;
|
||||||
|
answer.redirectedResults = null;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert false : "Unknown 'Return' type.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleFinish(RpcProtocol.Finish.Reader finish) {
|
void handleFinish(RpcProtocol.Finish.Reader finish) {
|
||||||
|
@ -218,7 +453,6 @@ final class RpcState {
|
||||||
void handleDisembargo(RpcProtocol.Disembargo.Reader disembargo) {
|
void handleDisembargo(RpcProtocol.Disembargo.Reader disembargo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private List<Integer> writeDescriptors(ClientHook[] capTable, RpcProtocol.Payload.Builder payload, List<Integer> fds) {
|
private List<Integer> writeDescriptors(ClientHook[] capTable, RpcProtocol.Payload.Builder payload, List<Integer> fds) {
|
||||||
if (capTable.length == 0) {
|
if (capTable.length == 0) {
|
||||||
return List.of();
|
return List.of();
|
||||||
|
@ -271,21 +505,20 @@ final class RpcState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the first time we've seen this capability.
|
// This is the first time we've seen this capability.
|
||||||
var export = new Export();
|
var export = exports.next();
|
||||||
export.refcount = 1;
|
export.refcount = 1;
|
||||||
export.clientHook = inner;
|
export.clientHook = inner;
|
||||||
exportId = exports.next(export);
|
|
||||||
|
|
||||||
var wrapped = inner.whenMoreResolved();
|
var wrapped = inner.whenMoreResolved();
|
||||||
if (wrapped != null) {
|
if (wrapped != null) {
|
||||||
// This is a promise. Arrange for the `Resolve` message to be sent later.
|
// This is a promise. Arrange for the `Resolve` message to be sent later.
|
||||||
export.resolveOp = resolveExportedPromise(exportId, wrapped);
|
export.resolveOp = resolveExportedPromise(export.id, wrapped);
|
||||||
descriptor.setSenderPromise(exportId);
|
descriptor.setSenderPromise(export.id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
descriptor.setSenderHosted(exportId);
|
descriptor.setSenderHosted(export.id);
|
||||||
}
|
}
|
||||||
return exportId;
|
return export.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletionStage<?> resolveExportedPromise(int exportId, CompletionStage<ClientHook> promise) {
|
CompletionStage<?> resolveExportedPromise(int exportId, CompletionStage<ClientHook> promise) {
|
||||||
|
@ -394,7 +627,7 @@ final class RpcState {
|
||||||
case RECEIVER_HOSTED:
|
case RECEIVER_HOSTED:
|
||||||
var exp = exports.find(descriptor.getReceiverHosted());
|
var exp = exports.find(descriptor.getReceiverHosted());
|
||||||
if (exp == null) {
|
if (exp == null) {
|
||||||
return ClientHook.newBrokenCap("invalid 'receiverHosted' export ID");
|
return Capability.newBrokenCap("invalid 'receiverHosted' export ID");
|
||||||
}
|
}
|
||||||
if (exp.clientHook.getBrand() == this) {
|
if (exp.clientHook.getBrand() == this) {
|
||||||
// TODO Tribble 4-way race!
|
// TODO Tribble 4-way race!
|
||||||
|
@ -409,12 +642,12 @@ final class RpcState {
|
||||||
var ops = PipelineOp.ToPipelineOps(promisedAnswer);
|
var ops = PipelineOp.ToPipelineOps(promisedAnswer);
|
||||||
|
|
||||||
if (answer == null || !answer.active || answer.pipeline == null || ops == null) {
|
if (answer == null || !answer.active || answer.pipeline == null || ops == null) {
|
||||||
return ClientHook.newBrokenCap("invalid 'receiverAnswer'");
|
return Capability.newBrokenCap("invalid 'receiverAnswer'");
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = answer.pipeline.getPipelinedCap(ops);
|
var result = answer.pipeline.getPipelinedCap(ops);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
return ClientHook.newBrokenCap("Unrecognised pipeline ops");
|
return Capability.newBrokenCap("Unrecognised pipeline ops");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.getBrand() == this) {
|
if (result.getBrand() == this) {
|
||||||
|
@ -425,14 +658,13 @@ final class RpcState {
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
case THIRD_PARTY_HOSTED:
|
case THIRD_PARTY_HOSTED:
|
||||||
return ClientHook.newBrokenCap("Third party caps not supported");
|
return Capability.newBrokenCap("Third party caps not supported");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ClientHook.newBrokenCap("unknown CapDescriptor type");
|
return Capability.newBrokenCap("unknown CapDescriptor type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ClientHook importCap(int importId, boolean isPromise, Integer fd) {
|
private ClientHook importCap(int importId, boolean isPromise, Integer fd) {
|
||||||
// Receive a new import.
|
// Receive a new import.
|
||||||
|
|
||||||
|
@ -467,6 +699,39 @@ final class RpcState {
|
||||||
: cap;
|
: cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClientHook getMessageTarget(RpcProtocol.MessageTarget.Reader target) {
|
||||||
|
switch (target.which()) {
|
||||||
|
case IMPORTED_CAP:
|
||||||
|
var exp = exports.find(target.getImportedCap());
|
||||||
|
assert exp != null: "Message target is not a current export ID.";
|
||||||
|
return exp != null ? exp.clientHook : null;
|
||||||
|
|
||||||
|
case PROMISED_ANSWER:
|
||||||
|
var promisedAnswer = target.getPromisedAnswer();
|
||||||
|
var base = answers.find(promisedAnswer.getQuestionId());
|
||||||
|
assert base != null && base.active: "PromisedAnswer.questionId is not a current question.";
|
||||||
|
if (base == null || !base.active) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pipeline = base.pipeline;
|
||||||
|
if (pipeline == null) {
|
||||||
|
pipeline = PipelineHook.newBrokenPipeline(
|
||||||
|
RpcException.failed("Pipeline call on a request that returned no capabilities or was already closed."));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ops = PipelineOp.ToPipelineOps(promisedAnswer);
|
||||||
|
if (ops == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return pipeline.getPipelinedCap(ops);
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert false: "Unknown message target type. " + target.which();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ClientHook getInnermostClient(ClientHook client) {
|
ClientHook getInnermostClient(ClientHook client) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
var inner = client.getResolved();
|
var inner = client.getResolved();
|
||||||
|
@ -489,6 +754,79 @@ final class RpcState {
|
||||||
AnyPointer.Reader getResults();
|
AnyPointer.Reader getResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface RpcServerResponse {
|
||||||
|
AnyPointer.Builder getResultsBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RpcResponseImpl implements RpcResponse {
|
||||||
|
private final Question question;
|
||||||
|
private final IncomingRpcMessage message;
|
||||||
|
private final AnyPointer.Reader results;
|
||||||
|
|
||||||
|
RpcResponseImpl(Question question,
|
||||||
|
IncomingRpcMessage message,
|
||||||
|
List<ClientHook> capTable,
|
||||||
|
AnyPointer.Reader results) {
|
||||||
|
this.question = question;
|
||||||
|
this.message = message;
|
||||||
|
this.results = results.imbue(new ReaderCapabilityTable(capTable));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnyPointer.Reader getResults() {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RpcServerResponseImpl implements RpcServerResponse {
|
||||||
|
|
||||||
|
final OutgoingRpcMessage message;
|
||||||
|
final RpcProtocol.Payload.Builder payload;
|
||||||
|
final BuilderCapabilityTable capTable = new BuilderCapabilityTable();
|
||||||
|
|
||||||
|
RpcServerResponseImpl(OutgoingRpcMessage message, RpcProtocol.Payload.Builder payload) {
|
||||||
|
this.message = message;
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnyPointer.Builder getResultsBuilder() {
|
||||||
|
return payload.getContent().imbue(capTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> send() {
|
||||||
|
var capTable = this.capTable.getTable();
|
||||||
|
var fds = List.<Integer>of();
|
||||||
|
var exports = writeDescriptors(capTable, payload, fds);
|
||||||
|
// TODO process FDs
|
||||||
|
message.setFds(fds);
|
||||||
|
|
||||||
|
for (int ii = 0; ii < capTable.length; ++ii) {
|
||||||
|
var slot = capTable[ii];
|
||||||
|
if (slot != null) {
|
||||||
|
capTable[ii] = getInnermostClient(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message.send();
|
||||||
|
return exports;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class LocallyRedirectedRpcResponse implements RpcServerResponse, RpcResponse {
|
||||||
|
|
||||||
|
private final MessageBuilder message = new MessageBuilder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnyPointer.Builder getResultsBuilder() {
|
||||||
|
return message.getRoot(AnyPointer.factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnyPointer.Reader getResults() {
|
||||||
|
return getResultsBuilder().asReader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class RpcCallContext implements CallContextHook {
|
class RpcCallContext implements CallContextHook {
|
||||||
|
|
||||||
final int answerId;
|
final int answerId;
|
||||||
|
@ -500,9 +838,13 @@ final class RpcState {
|
||||||
final AnyPointer.Reader params;
|
final AnyPointer.Reader params;
|
||||||
|
|
||||||
// response
|
// response
|
||||||
RpcResponse response;
|
RpcServerResponse response;
|
||||||
RpcProtocol.Return.Builder returnMessage;
|
RpcProtocol.Return.Builder returnMessage;
|
||||||
boolean redirectResults = false;
|
boolean redirectResults = false;
|
||||||
|
boolean responseSent = false;
|
||||||
|
|
||||||
|
boolean cancelRequested = false;
|
||||||
|
boolean cancelAllowed = false;
|
||||||
|
|
||||||
final CompletableFuture<java.lang.Void> cancelled;
|
final CompletableFuture<java.lang.Void> cancelled;
|
||||||
|
|
||||||
|
@ -531,7 +873,20 @@ final class RpcState {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AnyPointer.Builder getResults() {
|
public AnyPointer.Builder getResults() {
|
||||||
return null;
|
if (response != null) {
|
||||||
|
return response.getResultsBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redirectResults || isDisconnected()) {
|
||||||
|
response = new LocallyRedirectedRpcResponse();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var message = connection.newOutgoingMessage(1024);
|
||||||
|
returnMessage = message.getBody().initAs(RpcProtocol.Message.factory).initReturn();
|
||||||
|
response = new RpcServerResponseImpl(message, returnMessage.getResults());
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.getResultsBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -552,6 +907,147 @@ final class RpcState {
|
||||||
public ClientHook.VoidPromiseAndPipeline directTailCall(RequestHook request) {
|
public ClientHook.VoidPromiseAndPipeline directTailCall(RequestHook request) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RpcResponse consumeRedirectedResponse() {
|
||||||
|
assert this.redirectResults;
|
||||||
|
|
||||||
|
if (this.response == null) {
|
||||||
|
getResults(); // force initialization of response
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((LocallyRedirectedRpcResponse)this.response);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendReturn() {
|
||||||
|
assert !redirectResults;
|
||||||
|
|
||||||
|
if (!this.cancelRequested && isDisconnected()) {
|
||||||
|
assert false: "Cancellation should have been requested on disconnect.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.response == null) {
|
||||||
|
getResults(); // force initialization
|
||||||
|
}
|
||||||
|
|
||||||
|
this.returnMessage.setAnswerId(this.answerId);
|
||||||
|
this.returnMessage.setReleaseParamCaps(false);
|
||||||
|
|
||||||
|
List<Integer> exports;
|
||||||
|
try {
|
||||||
|
exports = ((RpcServerResponseImpl)response).send();
|
||||||
|
}
|
||||||
|
catch (Throwable exc) {
|
||||||
|
this.responseSent = false;
|
||||||
|
sendErrorReturn(exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendErrorReturn(Throwable exc) {
|
||||||
|
assert !redirectResults;
|
||||||
|
|
||||||
|
if (!isFirstResponder()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isConnected()) {
|
||||||
|
var message = connection.newOutgoingMessage(1024);
|
||||||
|
var builder = message.getBody().initAs(RpcProtocol.Message.factory).initReturn();
|
||||||
|
builder.setAnswerId(this.answerId);
|
||||||
|
builder.setReleaseParamCaps(false);
|
||||||
|
RpcException.fromException(exc, builder.initException());
|
||||||
|
message.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanupAnswerTable(null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isFirstResponder() {
|
||||||
|
if (this.responseSent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.responseSent = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanupAnswerTable(List<Integer> resultExports, boolean shouldFreePipeline) {
|
||||||
|
if (this.cancelRequested) {
|
||||||
|
assert resultExports.size() == 0;
|
||||||
|
answers.erase(this.answerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var answer = answers.find(answerId);
|
||||||
|
answer.callContext = null;
|
||||||
|
answer.resultExports = resultExports;
|
||||||
|
|
||||||
|
if (shouldFreePipeline) {
|
||||||
|
assert resultExports.size() == 0;
|
||||||
|
answer.pipeline = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PipelineState {
|
||||||
|
WAITING, RESOLVED, BROKEN
|
||||||
|
}
|
||||||
|
|
||||||
|
class RpcPipeline implements PipelineHook {
|
||||||
|
|
||||||
|
private final Question question;
|
||||||
|
private PipelineState state = PipelineState.WAITING;
|
||||||
|
private RpcResponse resolved;
|
||||||
|
private Throwable broken;
|
||||||
|
|
||||||
|
final HashMap<List<PipelineOp>, ClientHook> clientMap = new HashMap<>();
|
||||||
|
final CompletionStage<RpcResponse> redirectLater;
|
||||||
|
final CompletionStage<java.lang.Void> resolveSelf;
|
||||||
|
|
||||||
|
RpcPipeline(Question question,
|
||||||
|
CompletionStage<RpcResponse> redirectLater) {
|
||||||
|
this.question = question;
|
||||||
|
this.redirectLater = redirectLater;
|
||||||
|
this.resolveSelf = this.redirectLater
|
||||||
|
.thenAccept(response -> {
|
||||||
|
this.state = PipelineState.RESOLVED;
|
||||||
|
this.resolved = response;
|
||||||
|
})
|
||||||
|
.exceptionally(exc -> {
|
||||||
|
this.state = PipelineState.BROKEN;
|
||||||
|
this.broken = exc;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RpcPipeline(Question question) {
|
||||||
|
// never resolves
|
||||||
|
this.question = question;
|
||||||
|
this.redirectLater = null;
|
||||||
|
this.resolveSelf = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientHook getPipelinedCap(PipelineOp[] ops) {
|
||||||
|
// TODO avoid conversion to/from ArrayList?
|
||||||
|
var key = new ArrayList<>(Arrays.<PipelineOp>asList(ops));
|
||||||
|
var hook = this.clientMap.computeIfAbsent(key, k -> {
|
||||||
|
switch (state) {
|
||||||
|
case WAITING:
|
||||||
|
if (redirectLater != null) {
|
||||||
|
// TODO implement redirect
|
||||||
|
assert false: "redirection not implemented";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new PipelineClient(question, ops);
|
||||||
|
case RESOLVED:
|
||||||
|
return resolved.getResults().getPipelinedCap(ops);
|
||||||
|
default:
|
||||||
|
return Capability.newBrokenCap(broken);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return hook;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class RpcClient implements ClientHook {
|
abstract class RpcClient implements ClientHook {
|
||||||
|
@ -566,13 +1062,130 @@ final class RpcState {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Request<AnyPointer.Builder, AnyPointer.Reader> newCall(long interfaceId, short methodId) {
|
public Request<AnyPointer.Builder, AnyPointer.Reader> newCall(long interfaceId, short methodId) {
|
||||||
return null;
|
return newCallNoIntercept(interfaceId, methodId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VoidPromiseAndPipeline call(long interfaceId, short methodId, CallContextHook context) {
|
public VoidPromiseAndPipeline call(long interfaceId, short methodId, CallContextHook context) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VoidPromiseAndPipeline callNoIntercept(long interfaceId, short methodId, CallContextHook context) {
|
||||||
|
var params = context.getParams();
|
||||||
|
var request = newCallNoIntercept(interfaceId, methodId);
|
||||||
|
var x = request.params;
|
||||||
|
context.allowCancellation();
|
||||||
|
return context.directTailCall(request.hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Request<AnyPointer.Builder, AnyPointer.Reader> newCallNoIntercept(long interfaceId, short methodId) {
|
||||||
|
if (isDisconnected()) {
|
||||||
|
return Request.newBrokenRequest(disconnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = new RpcRequest(this);
|
||||||
|
var callBuilder = request.getCall();
|
||||||
|
callBuilder.setInterfaceId(interfaceId);
|
||||||
|
callBuilder.setMethodId(methodId);
|
||||||
|
var root = request.getRoot();
|
||||||
|
return Request.newTypelessRequest(root, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RpcRequest implements RequestHook {
|
||||||
|
|
||||||
|
final RpcClient target;
|
||||||
|
final OutgoingRpcMessage message;
|
||||||
|
final BuilderCapabilityTable capTable = new BuilderCapabilityTable();
|
||||||
|
final RpcProtocol.Call.Builder callBuilder;
|
||||||
|
final AnyPointer.Builder paramsBuilder;
|
||||||
|
|
||||||
|
RpcRequest(RpcClient target) {
|
||||||
|
this.target = target;
|
||||||
|
this.message = connection.newOutgoingMessage(1024);
|
||||||
|
this.callBuilder = message.getBody().getAs(RpcProtocol.Message.factory).initCall();
|
||||||
|
this.paramsBuilder = callBuilder.getParams().getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
AnyPointer.Builder getRoot() {
|
||||||
|
return this.paramsBuilder;
|
||||||
|
}
|
||||||
|
RpcProtocol.Call.Builder getCall() {
|
||||||
|
return this.callBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RemotePromise<AnyPointer.Reader> send() {
|
||||||
|
if (isDisconnected()) {
|
||||||
|
return new RemotePromise<>(CompletableFuture.failedFuture(disconnected), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var redirect = this.target.writeTarget(this.callBuilder.getTarget());
|
||||||
|
if (redirect != null) {
|
||||||
|
var replacement = redirect.newCall(
|
||||||
|
this.callBuilder.getInterfaceId(), this.callBuilder.getMethodId());
|
||||||
|
replacement.params = paramsBuilder;
|
||||||
|
return replacement.hook.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
var question = sendInternal(false);
|
||||||
|
|
||||||
|
// The pipeline must get notified of resolution before the app does to maintain ordering.
|
||||||
|
var pipeline = new RpcPipeline(question, question.response);
|
||||||
|
|
||||||
|
// drive the message loop until the question is answered
|
||||||
|
var appPromise = messageLoop(question.response).thenApply(response -> {
|
||||||
|
var results = response.getResults();
|
||||||
|
return new Response(results, response);
|
||||||
|
});
|
||||||
|
|
||||||
|
return new RemotePromise<>(appPromise, pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
Question sendInternal(boolean isTailCall) {
|
||||||
|
// TODO refactor
|
||||||
|
var fds = List.<Integer>of();
|
||||||
|
var exports = writeDescriptors(capTable.getTable(), callBuilder.getParams(), fds);
|
||||||
|
message.setFds(fds);
|
||||||
|
var question = questions.next();
|
||||||
|
question.isAwaitingReturn = true;
|
||||||
|
question.isTailCall = isTailCall;
|
||||||
|
question.paramExports = exports;
|
||||||
|
|
||||||
|
callBuilder.setQuestionId(question.id);
|
||||||
|
if (isTailCall) {
|
||||||
|
callBuilder.getSendResultsTo().getYourself();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
message.send();
|
||||||
|
} catch (Exception exc) {
|
||||||
|
question.isAwaitingReturn = false;
|
||||||
|
question.skipFinish = true;
|
||||||
|
question.reject(exc);
|
||||||
|
}
|
||||||
|
return question;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getBrand() {
|
||||||
|
return RpcState.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class TailInfo {
|
||||||
|
int questionId;
|
||||||
|
CompletableFuture<java.lang.Void> promise;
|
||||||
|
PipelineHook pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
TailInfo tailSend() {
|
||||||
|
if (isDisconnected()) {
|
||||||
|
// Disconnected; fall back to a regular send() which will fail appropriately.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO implement tail-calls
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImportClient extends RpcClient {
|
class ImportClient extends RpcClient {
|
||||||
|
@ -715,14 +1328,13 @@ final class RpcState {
|
||||||
assert redirect == null;
|
assert redirect == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var embargo = new Embargo();
|
var embargo = embargos.next();
|
||||||
var embargoId = embargos.next(embargo);
|
disembargo.getContext().setSenderLoopback(embargo.id);
|
||||||
disembargo.getContext().setSenderLoopback(embargoId);
|
|
||||||
|
|
||||||
embargo.fulfiller = new CompletableFuture<>();
|
embargo.disembargo = new CompletableFuture<>();
|
||||||
|
|
||||||
final ClientHook finalReplacement = replacement;
|
final ClientHook finalReplacement = replacement;
|
||||||
var embargoPromise = embargo.fulfiller.thenApply(x -> {
|
var embargoPromise = embargo.disembargo.thenApply(x -> {
|
||||||
return finalReplacement;
|
return finalReplacement;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -766,4 +1378,40 @@ final class RpcState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PipelineClient extends RpcClient {
|
||||||
|
|
||||||
|
private final Question question;
|
||||||
|
private final PipelineOp[] ops;
|
||||||
|
|
||||||
|
PipelineClient(Question question, PipelineOp[] ops) {
|
||||||
|
this.question = question;
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoidPromiseAndPipeline call(long interfaceId, short methodId, CallContextHook context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<ClientHook> whenMoreResolved() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer writeDescriptor(RpcProtocol.CapDescriptor.Builder descriptor, List<Integer> fds) {
|
||||||
|
var promisedAnswer = descriptor.initReceiverAnswer();
|
||||||
|
promisedAnswer.setQuestionId(question.id);
|
||||||
|
PipelineOp.FromPipelineOps(ops, promisedAnswer);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientHook writeTarget(RpcProtocol.MessageTarget.Builder target) {
|
||||||
|
var builder = target.initPromisedAnswer();
|
||||||
|
builder.setQuestionId(question.id);
|
||||||
|
PipelineOp.FromPipelineOps(ops, builder);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,44 @@
|
||||||
package org.capnproto;
|
package org.capnproto;
|
||||||
|
|
||||||
public class RpcSystem {
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public abstract class RpcSystem<Network extends VatNetwork> {
|
||||||
|
|
||||||
|
final Network network;
|
||||||
|
final Capability.Client bootstrapInterface;
|
||||||
|
final Map<VatNetwork.Connection, RpcState> connections = new HashMap<>();
|
||||||
|
CompletableFuture<?> acceptCompleted = CompletableFuture.completedFuture(null);
|
||||||
|
|
||||||
|
public RpcSystem(Network network, Capability.Client bootstrapInterface) {
|
||||||
|
this.network = network;
|
||||||
|
this.bootstrapInterface = bootstrapInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void accept(VatNetwork.Connection connection) {
|
||||||
|
getConnectionState(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized RpcState getConnectionState(VatNetwork.Connection connection) {
|
||||||
|
return connections.computeIfAbsent(connection, key ->
|
||||||
|
new RpcState(key, bootstrapInterface));
|
||||||
|
}
|
||||||
|
|
||||||
|
public final CompletableFuture<?> runOnce() {
|
||||||
|
var done = acceptLoop();
|
||||||
|
for (var conn : connections.values()) {
|
||||||
|
done = CompletableFuture.anyOf(done, conn.runOnce());
|
||||||
|
}
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CompletableFuture<?> acceptLoop() {
|
||||||
|
if (this.acceptCompleted.isDone()) {
|
||||||
|
CompletableFuture<VatNetwork.Connection> accepted = this.network.baseAccept();
|
||||||
|
this.acceptCompleted = accepted.thenAccept(this::accept);
|
||||||
|
}
|
||||||
|
return this.acceptCompleted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
33
runtime/src/main/java/org/capnproto/TwoPartyClient.java
Normal file
33
runtime/src/main/java/org/capnproto/TwoPartyClient.java
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package org.capnproto;
|
||||||
|
|
||||||
|
import java.nio.channels.AsynchronousByteChannel;
|
||||||
|
|
||||||
|
public class TwoPartyClient {
|
||||||
|
|
||||||
|
private final TwoPartyVatNetwork network;
|
||||||
|
private final TwoPartyRpcSystem rpcSystem;
|
||||||
|
|
||||||
|
public TwoPartyClient(AsynchronousByteChannel channel) {
|
||||||
|
this(channel, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TwoPartyClient(AsynchronousByteChannel channel, Capability.Client bootstrapInterface) {
|
||||||
|
this(channel, bootstrapInterface, RpcTwoPartyProtocol.Side.CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TwoPartyClient(AsynchronousByteChannel channel,
|
||||||
|
Capability.Client bootstrapInterface,
|
||||||
|
RpcTwoPartyProtocol.Side side) {
|
||||||
|
this.network = new TwoPartyVatNetwork(channel, side);
|
||||||
|
this.rpcSystem = new TwoPartyRpcSystem(network, bootstrapInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Capability.Client bootstrap() {
|
||||||
|
var message = new MessageBuilder();
|
||||||
|
var vatId = message.getRoot(RpcTwoPartyProtocol.VatId.factory);
|
||||||
|
vatId.setSide(network.getSide() == RpcTwoPartyProtocol.Side.CLIENT
|
||||||
|
? RpcTwoPartyProtocol.Side.SERVER
|
||||||
|
: RpcTwoPartyProtocol.Side.CLIENT);
|
||||||
|
return rpcSystem.bootstrap(vatId.asReader());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,16 @@
|
||||||
package org.capnproto;
|
package org.capnproto;
|
||||||
|
|
||||||
public class TwoPartyRpcSystem extends RpcSystem {
|
public class TwoPartyRpcSystem
|
||||||
|
extends RpcSystem<TwoPartyVatNetwork> {
|
||||||
|
|
||||||
|
public TwoPartyRpcSystem(TwoPartyVatNetwork network, Capability.Client bootstrapInterface) {
|
||||||
|
super(network, bootstrapInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Capability.Client bootstrap(RpcTwoPartyProtocol.VatId.Reader vatId) {
|
||||||
|
var connection = this.network.baseConnect(vatId);
|
||||||
|
var state = getConnectionState(connection);
|
||||||
|
var hook = state.restore();
|
||||||
|
return new Capability.Client(hook);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
64
runtime/src/main/java/org/capnproto/TwoPartyServer.java
Normal file
64
runtime/src/main/java/org/capnproto/TwoPartyServer.java
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package org.capnproto;
|
||||||
|
|
||||||
|
import java.nio.channels.AsynchronousByteChannel;
|
||||||
|
import java.nio.channels.AsynchronousServerSocketChannel;
|
||||||
|
import java.nio.channels.AsynchronousSocketChannel;
|
||||||
|
import java.nio.channels.CompletionHandler;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public class TwoPartyServer {
|
||||||
|
|
||||||
|
private class AcceptedConnection {
|
||||||
|
final AsynchronousByteChannel channel;
|
||||||
|
final TwoPartyVatNetwork network;
|
||||||
|
final TwoPartyRpcSystem rpcSystem;
|
||||||
|
|
||||||
|
AcceptedConnection(Capability.Client bootstrapInterface, AsynchronousByteChannel channel) {
|
||||||
|
this.channel = channel;
|
||||||
|
this.network = new TwoPartyVatNetwork(channel, RpcTwoPartyProtocol.Side.SERVER);
|
||||||
|
this.rpcSystem = new TwoPartyRpcSystem(network, bootstrapInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<?> runOnce() {
|
||||||
|
return this.rpcSystem.runOnce();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Capability.Client bootstrapInterface;
|
||||||
|
private final List<AcceptedConnection> connections = new ArrayList<>();
|
||||||
|
private final List<AsynchronousServerSocketChannel> listeners = new ArrayList<>();
|
||||||
|
|
||||||
|
public TwoPartyServer(Capability.Client bootstrapInterface) {
|
||||||
|
this.bootstrapInterface = bootstrapInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void accept(AsynchronousByteChannel channel) {
|
||||||
|
var connection = new AcceptedConnection(this.bootstrapInterface, channel);
|
||||||
|
this.connections.add(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void listen(AsynchronousServerSocketChannel listener) {
|
||||||
|
listener.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
|
||||||
|
@Override
|
||||||
|
public void completed(AsynchronousSocketChannel channel, Object attachment) {
|
||||||
|
accept(channel);
|
||||||
|
listen(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failed(Throwable exc, Object attachment) {
|
||||||
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized CompletableFuture<?> runOnce() {
|
||||||
|
var done = new CompletableFuture<Object>();
|
||||||
|
for (var conn: connections) {
|
||||||
|
done = CompletableFuture.anyOf(done, conn.runOnce());
|
||||||
|
}
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,13 +3,18 @@ package org.capnproto;
|
||||||
import java.nio.channels.AsynchronousByteChannel;
|
import java.nio.channels.AsynchronousByteChannel;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
public class TwoPartyVatNetwork implements VatNetwork, VatNetwork.Connection {
|
public class TwoPartyVatNetwork
|
||||||
|
implements VatNetwork<RpcTwoPartyProtocol.VatId.Reader>, VatNetwork.Connection {
|
||||||
|
|
||||||
private CompletableFuture<?> writeCompleted = CompletableFuture.completedFuture(null);
|
private CompletableFuture<?> writeCompleted = CompletableFuture.completedFuture(null);
|
||||||
|
private final Executor executor = Executors.newSingleThreadExecutor();
|
||||||
private final AsynchronousByteChannel channel;
|
private final AsynchronousByteChannel channel;
|
||||||
private final RpcTwoPartyProtocol.Side side;
|
private final RpcTwoPartyProtocol.Side side;
|
||||||
private final MessageBuilder peerVatId = new MessageBuilder(4);
|
private final MessageBuilder peerVatId = new MessageBuilder(4);
|
||||||
|
private boolean accepted;
|
||||||
|
|
||||||
public TwoPartyVatNetwork(AsynchronousByteChannel channel, RpcTwoPartyProtocol.Side side) {
|
public TwoPartyVatNetwork(AsynchronousByteChannel channel, RpcTwoPartyProtocol.Side side) {
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
|
@ -28,6 +33,24 @@ public class TwoPartyVatNetwork implements VatNetwork, VatNetwork.Connection {
|
||||||
return peerVatId.getRoot(RpcTwoPartyProtocol.VatId.factory).asReader();
|
return peerVatId.getRoot(RpcTwoPartyProtocol.VatId.factory).asReader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Connection connect(RpcTwoPartyProtocol.VatId.Reader vatId) {
|
||||||
|
if (vatId.getSide() != side) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompletableFuture<Connection> accept() {
|
||||||
|
if (side == RpcTwoPartyProtocol.Side.SERVER & !accepted) {
|
||||||
|
accepted = true;
|
||||||
|
return CompletableFuture.completedFuture(this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// never completes
|
||||||
|
return new CompletableFuture<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutgoingRpcMessage newOutgoingMessage(int firstSegmentWordSize) {
|
public OutgoingRpcMessage newOutgoingMessage(int firstSegmentWordSize) {
|
||||||
return new OutgoingMessage(firstSegmentWordSize);
|
return new OutgoingMessage(firstSegmentWordSize);
|
||||||
|
@ -40,6 +63,16 @@ public class TwoPartyVatNetwork implements VatNetwork, VatNetwork.Connection {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Connection baseConnect(RpcTwoPartyProtocol.VatId.Reader hostId) {
|
||||||
|
return this.connect(hostId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Connection> baseAccept() {
|
||||||
|
return this.accept().thenApply(conn -> conn);
|
||||||
|
}
|
||||||
|
|
||||||
final class OutgoingMessage implements OutgoingRpcMessage {
|
final class OutgoingMessage implements OutgoingRpcMessage {
|
||||||
|
|
||||||
final MessageBuilder message;
|
final MessageBuilder message;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package org.capnproto;
|
package org.capnproto;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
public interface VatNetwork {
|
public interface VatNetwork<VatId> {
|
||||||
|
|
||||||
interface Connection {
|
interface Connection {
|
||||||
|
|
||||||
|
@ -10,4 +11,7 @@ public interface VatNetwork {
|
||||||
|
|
||||||
CompletableFuture<IncomingRpcMessage> receiveIncomingMessage();
|
CompletableFuture<IncomingRpcMessage> receiveIncomingMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connection baseConnect(VatId hostId);
|
||||||
|
CompletableFuture<Connection> baseAccept();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1332,16 +1332,16 @@ final class WireHelpers {
|
||||||
long ref = segment.get(refOffset);
|
long ref = segment.get(refOffset);
|
||||||
|
|
||||||
if (WirePointer.isNull(ref)) {
|
if (WirePointer.isNull(ref)) {
|
||||||
return ClientHook.newNullCap();
|
return Capability.newNullCap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WirePointer.kind(ref) != WirePointer.OTHER) {
|
if (WirePointer.kind(ref) != WirePointer.OTHER) {
|
||||||
return ClientHook.newBrokenCap("Calling capability extracted from a non-capability pointer.");
|
return Capability.newBrokenCap("Calling capability extracted from a non-capability pointer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var cap = capTable.extractCap(WirePointer.upper32Bits(ref));
|
var cap = capTable.extractCap(WirePointer.upper32Bits(ref));
|
||||||
if (cap == null) {
|
if (cap == null) {
|
||||||
return ClientHook.newBrokenCap("Calling invalid capability pointer.");
|
return Capability.newBrokenCap("Calling invalid capability pointer.");
|
||||||
}
|
}
|
||||||
return cap;
|
return cap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import org.junit.Test;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
public class RpcStateTest {
|
public class RpcStateTest {
|
||||||
|
|
||||||
|
@ -23,6 +25,7 @@ public class RpcStateTest {
|
||||||
|
|
||||||
class TestConnection implements VatNetwork.Connection {
|
class TestConnection implements VatNetwork.Connection {
|
||||||
|
|
||||||
|
Executor executor = Executors.newSingleThreadExecutor();
|
||||||
@Override
|
@Override
|
||||||
public OutgoingRpcMessage newOutgoingMessage(int firstSegmentWordSize) {
|
public OutgoingRpcMessage newOutgoingMessage(int firstSegmentWordSize) {
|
||||||
var message = new MessageBuilder();
|
var message = new MessageBuilder();
|
||||||
|
@ -59,7 +62,7 @@ public class RpcStateTest {
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
connection = new TestConnection();
|
connection = new TestConnection();
|
||||||
bootstrapInterface = new Capability.Client(ClientHook.newNullCap());
|
bootstrapInterface = new Capability.Client(Capability.newNullCap());
|
||||||
rpc = new RpcState(connection, bootstrapInterface);
|
rpc = new RpcState(connection, bootstrapInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
216
runtime/src/test/java/org/capnproto/TwoPartyTest.java
Normal file
216
runtime/src/test/java/org/capnproto/TwoPartyTest.java
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
package org.capnproto;
|
||||||
|
|
||||||
|
import org.capnproto.demo.Demo;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.AsynchronousServerSocketChannel;
|
||||||
|
import java.nio.channels.AsynchronousSocketChannel;
|
||||||
|
import java.nio.channels.CompletionHandler;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
class TestCap0 {
|
||||||
|
|
||||||
|
static final class Client extends org.capnproto.Capability.Client {
|
||||||
|
public Client() { super(); }
|
||||||
|
|
||||||
|
public Client(ClientHook hook) { super(hook); }
|
||||||
|
|
||||||
|
public Client(Capability.Client cap) { super(cap.getHook()); }
|
||||||
|
|
||||||
|
public Client(Capability.Server server) { super(server); }
|
||||||
|
|
||||||
|
public org.capnproto.Request<Demo.TestParams0.Builder, Demo.TestResults0.Reader> testMethod0Request() {
|
||||||
|
return newCall(Demo.TestParams0.factory, Demo.TestResults0.factory, 0xa65f4a3d7f622e6bL, (short) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public org.capnproto.Request<Demo.TestParams1.Builder, Demo.TestResults1.Reader> testMethod1Request() {
|
||||||
|
return newCall(Demo.TestParams1.factory, Demo.TestResults1.factory, 0xa65f4a3d7f622e6bL, (short) 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract class Server extends org.capnproto.Capability.Server {
|
||||||
|
|
||||||
|
public class TestMethod0Context extends CallContext<Demo.TestParams0.Reader, Demo.TestResults0.Builder> {
|
||||||
|
public TestMethod0Context(CallContextHook hook) {
|
||||||
|
super(Demo.TestParams0.factory, Demo.TestResults0.factory, hook);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestMethod1Context extends CallContext<Demo.TestParams1.Reader, Demo.TestResults1.Builder> {
|
||||||
|
public TestMethod1Context(CallContextHook hook) {
|
||||||
|
super(Demo.TestParams1.factory, Demo.TestResults1.factory, hook);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DispatchCallResult dispatchCall(long interfaceId, short methodId, CallContext<AnyPointer.Reader, AnyPointer.Builder> context) {
|
||||||
|
if (interfaceId == 0xa65f4a3d7f622e6bL) {
|
||||||
|
return dispatchCallInternal(methodId, context);
|
||||||
|
}
|
||||||
|
return internalUnimplemented(Demo.class.getName(), interfaceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DispatchCallResult dispatchCallInternal(short methodId, CallContext<AnyPointer.Reader, AnyPointer.Builder> ctx) {
|
||||||
|
switch (methodId) {
|
||||||
|
case 0:
|
||||||
|
return new DispatchCallResult(testMethod0(new TestMethod0Context(ctx.getHook())));
|
||||||
|
case 1:
|
||||||
|
return new DispatchCallResult(testMethod1(new TestMethod1Context(ctx.getHook())));
|
||||||
|
default:
|
||||||
|
return internalUnimplemented(Demo.class.getName(), 0xa27d3c231c7b9202L, methodId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<?> testMethod0(TestMethod0Context ctx) {
|
||||||
|
return CompletableFuture.failedFuture(RpcException.unimplemented("testMethod0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<?> testMethod1(TestMethod1Context ctx) {
|
||||||
|
return CompletableFuture.failedFuture(RpcException.unimplemented("testMethod1"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestCap1 {
|
||||||
|
|
||||||
|
static final class Client extends org.capnproto.Capability.Client {
|
||||||
|
public Client() { super(); }
|
||||||
|
|
||||||
|
public Client(ClientHook hook) { super(hook); }
|
||||||
|
|
||||||
|
public Client(Capability.Client cap) { super(cap.getHook()); }
|
||||||
|
|
||||||
|
public Client(Capability.Server server) { super(server); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract class Server extends org.capnproto.Capability.Server {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DispatchCallResult dispatchCall(long interfaceId, short methodId, CallContext<AnyPointer.Reader, AnyPointer.Builder> context) {
|
||||||
|
if (interfaceId == 0x81da3f8f6079c216L) {
|
||||||
|
return dispatchCallInternal(methodId, context);
|
||||||
|
}
|
||||||
|
return internalUnimplemented(Demo.class.getName(), interfaceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DispatchCallResult dispatchCallInternal(short methodId, CallContext<AnyPointer.Reader, AnyPointer.Builder> ctx) {
|
||||||
|
switch (methodId) {
|
||||||
|
default:
|
||||||
|
return internalUnimplemented(Demo.class.getName(), 0x81da3f8f6079c216L, methodId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestCap0Impl extends TestCap0.Server {
|
||||||
|
|
||||||
|
final TestCap1.Client testCap1 = new TestCap1.Client(new TestCap1Impl());
|
||||||
|
|
||||||
|
public CompletableFuture<?> testMethod0(TestCap0.Server.TestMethod0Context ctx) {
|
||||||
|
var params = ctx.getParams();
|
||||||
|
var results = ctx.getResults();
|
||||||
|
results.setResult0(params.getParam0());
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<?> testMethod1(TestCap0.Server.TestMethod1Context ctx) {
|
||||||
|
var params = ctx.getParams();
|
||||||
|
var results = ctx.getResults();
|
||||||
|
var res0 = results.getResult0();
|
||||||
|
res0.setAsCapability(testCap1);
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestCap1Impl extends TestCap1.Server {
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TwoPartyTest {
|
||||||
|
|
||||||
|
AsynchronousServerSocketChannel serverSocket;
|
||||||
|
AsynchronousSocketChannel clientSocket;
|
||||||
|
TwoPartyClient client;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
this.serverSocket = AsynchronousServerSocketChannel.open();
|
||||||
|
this.serverSocket.bind(null);
|
||||||
|
|
||||||
|
this.clientSocket = AsynchronousSocketChannel.open();
|
||||||
|
this.clientSocket.connect(this.serverSocket.getLocalAddress()).get();
|
||||||
|
|
||||||
|
this.client = new TwoPartyClient(clientSocket);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
this.clientSocket.close();
|
||||||
|
this.serverSocket.close();
|
||||||
|
this.client = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNullCap() {
|
||||||
|
|
||||||
|
var server = new TwoPartyServer(new Capability.Client());
|
||||||
|
server.listen(serverSocket);
|
||||||
|
var cap = this.client.bootstrap();
|
||||||
|
var resolved = cap.whenResolved();
|
||||||
|
resolved.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasic() throws ExecutionException, InterruptedException {
|
||||||
|
var capServer = new TestCap0Impl();
|
||||||
|
var server = new TwoPartyServer(new TestCap0.Client(capServer));
|
||||||
|
server.listen(serverSocket);
|
||||||
|
var demoClient = new TestCap0.Client(this.client.bootstrap());
|
||||||
|
var request = demoClient.testMethod0Request();
|
||||||
|
var params = request.params();
|
||||||
|
params.setParam0(4321);
|
||||||
|
var resultsPromise = request.send();
|
||||||
|
while (!resultsPromise.isDone()) {
|
||||||
|
CompletableFuture.anyOf(resultsPromise, server.runOnce()).join();
|
||||||
|
}
|
||||||
|
Assert.assertTrue(resultsPromise.isDone());
|
||||||
|
var results = resultsPromise.get();
|
||||||
|
Assert.assertEquals(params.getParam0(), results.getResult0());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReturnCap() throws ExecutionException, InterruptedException {
|
||||||
|
// send a capabilty back from the server to the client
|
||||||
|
var capServer = new TestCap0Impl();
|
||||||
|
var server = new TwoPartyServer(new TestCap0.Client(capServer));
|
||||||
|
server.listen(serverSocket);
|
||||||
|
var demoClient = new TestCap0.Client(this.client.bootstrap());
|
||||||
|
var request = demoClient.testMethod1Request();
|
||||||
|
var params = request.params();
|
||||||
|
var resultsPromise = request.send();
|
||||||
|
while (!resultsPromise.isDone()) {
|
||||||
|
CompletableFuture.anyOf(resultsPromise, server.runOnce()).join();
|
||||||
|
}
|
||||||
|
Assert.assertTrue(resultsPromise.isDone());
|
||||||
|
var results = resultsPromise.get();
|
||||||
|
var any = results.getResult0();
|
||||||
|
var cap1 = any.getAsCapability();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLocalServer() throws ExecutionException, InterruptedException {
|
||||||
|
var demo = new TestCap0Impl();
|
||||||
|
var client = new TestCap0.Client(demo);
|
||||||
|
var request = client.testMethod0Request();
|
||||||
|
var params = request.params();
|
||||||
|
params.setParam0(4321);
|
||||||
|
var results = request.send().get();
|
||||||
|
Assert.assertEquals(params.getParam0(), results.getResult0());
|
||||||
|
}
|
||||||
|
}
|
371
runtime/src/test/java/org/capnproto/demo/Demo.java
Normal file
371
runtime/src/test/java/org/capnproto/demo/Demo.java
Normal file
|
@ -0,0 +1,371 @@
|
||||||
|
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||||
|
// source: demoparams.capnp
|
||||||
|
|
||||||
|
package org.capnproto.demo;
|
||||||
|
|
||||||
|
public final class Demo {
|
||||||
|
public static class TestParams0 {
|
||||||
|
public static final org.capnproto.StructSize STRUCT_SIZE = new org.capnproto.StructSize((short)1,(short)0);
|
||||||
|
public static final class Factory extends org.capnproto.StructFactory<Builder, Reader> {
|
||||||
|
public Factory() {
|
||||||
|
}
|
||||||
|
public final Reader constructReader(org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) {
|
||||||
|
return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit);
|
||||||
|
}
|
||||||
|
public final Builder constructBuilder(org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) {
|
||||||
|
return new Builder(segment, data, pointers, dataSize, pointerCount);
|
||||||
|
}
|
||||||
|
public final org.capnproto.StructSize structSize() {
|
||||||
|
return TestParams0.STRUCT_SIZE;
|
||||||
|
}
|
||||||
|
public final Reader asReader(Builder builder) {
|
||||||
|
return builder.asReader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static final Factory factory = new Factory();
|
||||||
|
public static final org.capnproto.StructList.Factory<Builder,Reader> listFactory =
|
||||||
|
new org.capnproto.StructList.Factory<Builder, Reader>(factory);
|
||||||
|
public static final class Builder extends org.capnproto.StructBuilder {
|
||||||
|
Builder(org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){
|
||||||
|
super(segment, data, pointers, dataSize, pointerCount);
|
||||||
|
}
|
||||||
|
public final Reader asReader() {
|
||||||
|
return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff);
|
||||||
|
}
|
||||||
|
public final int getParam0() {
|
||||||
|
return _getIntField(0);
|
||||||
|
}
|
||||||
|
public final void setParam0(int value) {
|
||||||
|
_setIntField(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Reader extends org.capnproto.StructReader {
|
||||||
|
Reader(org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){
|
||||||
|
super(segment, data, pointers, dataSize, pointerCount, nestingLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getParam0() {
|
||||||
|
return _getIntField(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class TestResults0 {
|
||||||
|
public static final org.capnproto.StructSize STRUCT_SIZE = new org.capnproto.StructSize((short)1,(short)0);
|
||||||
|
public static final class Factory extends org.capnproto.StructFactory<Builder, Reader> {
|
||||||
|
public Factory() {
|
||||||
|
}
|
||||||
|
public final Reader constructReader(org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) {
|
||||||
|
return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit);
|
||||||
|
}
|
||||||
|
public final Builder constructBuilder(org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) {
|
||||||
|
return new Builder(segment, data, pointers, dataSize, pointerCount);
|
||||||
|
}
|
||||||
|
public final org.capnproto.StructSize structSize() {
|
||||||
|
return TestResults0.STRUCT_SIZE;
|
||||||
|
}
|
||||||
|
public final Reader asReader(Builder builder) {
|
||||||
|
return builder.asReader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static final Factory factory = new Factory();
|
||||||
|
public static final org.capnproto.StructList.Factory<Builder,Reader> listFactory =
|
||||||
|
new org.capnproto.StructList.Factory<Builder, Reader>(factory);
|
||||||
|
public static final class Builder extends org.capnproto.StructBuilder {
|
||||||
|
Builder(org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){
|
||||||
|
super(segment, data, pointers, dataSize, pointerCount);
|
||||||
|
}
|
||||||
|
public final Reader asReader() {
|
||||||
|
return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff);
|
||||||
|
}
|
||||||
|
public final int getResult0() {
|
||||||
|
return _getIntField(0);
|
||||||
|
}
|
||||||
|
public final void setResult0(int value) {
|
||||||
|
_setIntField(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Reader extends org.capnproto.StructReader {
|
||||||
|
Reader(org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){
|
||||||
|
super(segment, data, pointers, dataSize, pointerCount, nestingLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getResult0() {
|
||||||
|
return _getIntField(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class TestParams1 {
|
||||||
|
public static final org.capnproto.StructSize STRUCT_SIZE = new org.capnproto.StructSize((short)0,(short)1);
|
||||||
|
public static final class Factory extends org.capnproto.StructFactory<Builder, Reader> {
|
||||||
|
public Factory() {
|
||||||
|
}
|
||||||
|
public final Reader constructReader(org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) {
|
||||||
|
return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit);
|
||||||
|
}
|
||||||
|
public final Builder constructBuilder(org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) {
|
||||||
|
return new Builder(segment, data, pointers, dataSize, pointerCount);
|
||||||
|
}
|
||||||
|
public final org.capnproto.StructSize structSize() {
|
||||||
|
return TestParams1.STRUCT_SIZE;
|
||||||
|
}
|
||||||
|
public final Reader asReader(Builder builder) {
|
||||||
|
return builder.asReader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static final Factory factory = new Factory();
|
||||||
|
public static final org.capnproto.StructList.Factory<Builder,Reader> listFactory =
|
||||||
|
new org.capnproto.StructList.Factory<Builder, Reader>(factory);
|
||||||
|
public static final class Builder extends org.capnproto.StructBuilder {
|
||||||
|
Builder(org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){
|
||||||
|
super(segment, data, pointers, dataSize, pointerCount);
|
||||||
|
}
|
||||||
|
public final Reader asReader() {
|
||||||
|
return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff);
|
||||||
|
}
|
||||||
|
public final boolean hasParam0() {
|
||||||
|
return !_pointerFieldIsNull(0);
|
||||||
|
}
|
||||||
|
public org.capnproto.AnyPointer.Builder getParam0() {
|
||||||
|
return _getPointerField(org.capnproto.AnyPointer.factory, 0);
|
||||||
|
}
|
||||||
|
public org.capnproto.AnyPointer.Builder initParam0() {
|
||||||
|
return _initPointerField(org.capnproto.AnyPointer.factory, 0, 0);
|
||||||
|
}
|
||||||
|
public org.capnproto.AnyPointer.Builder initParam0(int size) {
|
||||||
|
return _initPointerField(org.capnproto.AnyPointer.factory, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Reader extends org.capnproto.StructReader {
|
||||||
|
Reader(org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){
|
||||||
|
super(segment, data, pointers, dataSize, pointerCount, nestingLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasParam0() {
|
||||||
|
return !_pointerFieldIsNull(0);
|
||||||
|
}
|
||||||
|
public org.capnproto.AnyPointer.Reader getParam0() {
|
||||||
|
return _getPointerField(org.capnproto.AnyPointer.factory, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class TestResults1 {
|
||||||
|
public static final org.capnproto.StructSize STRUCT_SIZE = new org.capnproto.StructSize((short)0,(short)1);
|
||||||
|
public static final class Factory extends org.capnproto.StructFactory<Builder, Reader> {
|
||||||
|
public Factory() {
|
||||||
|
}
|
||||||
|
public final Reader constructReader(org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) {
|
||||||
|
return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit);
|
||||||
|
}
|
||||||
|
public final Builder constructBuilder(org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) {
|
||||||
|
return new Builder(segment, data, pointers, dataSize, pointerCount);
|
||||||
|
}
|
||||||
|
public final org.capnproto.StructSize structSize() {
|
||||||
|
return TestResults1.STRUCT_SIZE;
|
||||||
|
}
|
||||||
|
public final Reader asReader(Builder builder) {
|
||||||
|
return builder.asReader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static final Factory factory = new Factory();
|
||||||
|
public static final org.capnproto.StructList.Factory<Builder,Reader> listFactory =
|
||||||
|
new org.capnproto.StructList.Factory<Builder, Reader>(factory);
|
||||||
|
public static final class Builder extends org.capnproto.StructBuilder {
|
||||||
|
Builder(org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){
|
||||||
|
super(segment, data, pointers, dataSize, pointerCount);
|
||||||
|
}
|
||||||
|
public final Reader asReader() {
|
||||||
|
return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff);
|
||||||
|
}
|
||||||
|
public final boolean hasResult0() {
|
||||||
|
return !_pointerFieldIsNull(0);
|
||||||
|
}
|
||||||
|
public org.capnproto.AnyPointer.Builder getResult0() {
|
||||||
|
return _getPointerField(org.capnproto.AnyPointer.factory, 0);
|
||||||
|
}
|
||||||
|
public org.capnproto.AnyPointer.Builder initResult0() {
|
||||||
|
return _initPointerField(org.capnproto.AnyPointer.factory, 0, 0);
|
||||||
|
}
|
||||||
|
public org.capnproto.AnyPointer.Builder initResult0(int size) {
|
||||||
|
return _initPointerField(org.capnproto.AnyPointer.factory, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Reader extends org.capnproto.StructReader {
|
||||||
|
Reader(org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){
|
||||||
|
super(segment, data, pointers, dataSize, pointerCount, nestingLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasResult0() {
|
||||||
|
return !_pointerFieldIsNull(0);
|
||||||
|
}
|
||||||
|
public org.capnproto.AnyPointer.Reader getResult0() {
|
||||||
|
return _getPointerField(org.capnproto.AnyPointer.factory, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static final class Schemas {
|
||||||
|
public static final org.capnproto.SegmentReader b_b301b4acd180f012 =
|
||||||
|
org.capnproto.GeneratedClassSupport.decodeRawBytes(
|
||||||
|
"\u0000\u0000\u0000\u0000\u0005\u0000\u0006\u0000" +
|
||||||
|
"\u0012\u00f0\u0080\u00d1\u00ac\u00b4\u0001\u00b3" +
|
||||||
|
"\u0011\u0000\u0000\u0000\u0001\u0000\u0001\u0000" +
|
||||||
|
"\u00c4\u0053\u0042\u00d6\u0097\u0077\u00b5\u0091" +
|
||||||
|
"\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0015\u0000\u0000\u0000\u00ea\u0000\u0000\u0000" +
|
||||||
|
"\u0021\u0000\u0000\u0000\u0007\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u001d\u0000\u0000\u0000\u003f\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0064\u0065\u006d\u006f\u0070\u0061\u0072\u0061" +
|
||||||
|
"\u006d\u0073\u002e\u0063\u0061\u0070\u006e\u0070" +
|
||||||
|
"\u003a\u0054\u0065\u0073\u0074\u0050\u0061\u0072" +
|
||||||
|
"\u0061\u006d\u0073\u0030\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000" +
|
||||||
|
"\u0004\u0000\u0000\u0000\u0003\u0000\u0004\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0001\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\r\u0000\u0000\u0000\u003a\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0008\u0000\u0000\u0000\u0003\u0000\u0001\u0000" +
|
||||||
|
"\u0014\u0000\u0000\u0000\u0002\u0000\u0001\u0000" +
|
||||||
|
"\u0070\u0061\u0072\u0061\u006d\u0030\u0000\u0000" +
|
||||||
|
"\u0004\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0004\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + "");
|
||||||
|
public static final org.capnproto.SegmentReader b_96a42e5421b52881 =
|
||||||
|
org.capnproto.GeneratedClassSupport.decodeRawBytes(
|
||||||
|
"\u0000\u0000\u0000\u0000\u0005\u0000\u0006\u0000" +
|
||||||
|
"\u0081\u0028\u00b5\u0021\u0054\u002e\u00a4\u0096" +
|
||||||
|
"\u0011\u0000\u0000\u0000\u0001\u0000\u0001\u0000" +
|
||||||
|
"\u00c4\u0053\u0042\u00d6\u0097\u0077\u00b5\u0091" +
|
||||||
|
"\u0000\u0000\u0007\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0015\u0000\u0000\u0000\u00f2\u0000\u0000\u0000" +
|
||||||
|
"\u0021\u0000\u0000\u0000\u0007\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u001d\u0000\u0000\u0000\u003f\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0064\u0065\u006d\u006f\u0070\u0061\u0072\u0061" +
|
||||||
|
"\u006d\u0073\u002e\u0063\u0061\u0070\u006e\u0070" +
|
||||||
|
"\u003a\u0054\u0065\u0073\u0074\u0052\u0065\u0073" +
|
||||||
|
"\u0075\u006c\u0074\u0073\u0030\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000" +
|
||||||
|
"\u0004\u0000\u0000\u0000\u0003\u0000\u0004\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0001\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\r\u0000\u0000\u0000\u0042\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0008\u0000\u0000\u0000\u0003\u0000\u0001\u0000" +
|
||||||
|
"\u0014\u0000\u0000\u0000\u0002\u0000\u0001\u0000" +
|
||||||
|
"\u0072\u0065\u0073\u0075\u006c\u0074\u0030\u0000" +
|
||||||
|
"\u0004\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0004\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + "");
|
||||||
|
public static final org.capnproto.SegmentReader b_e10363a8b6220957 =
|
||||||
|
org.capnproto.GeneratedClassSupport.decodeRawBytes(
|
||||||
|
"\u0000\u0000\u0000\u0000\u0005\u0000\u0006\u0000" +
|
||||||
|
"\u0057\u0009\"\u00b6\u00a8\u0063\u0003\u00e1" +
|
||||||
|
"\u0011\u0000\u0000\u0000\u0001\u0000\u0000\u0000" +
|
||||||
|
"\u00c4\u0053\u0042\u00d6\u0097\u0077\u00b5\u0091" +
|
||||||
|
"\u0001\u0000\u0007\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0015\u0000\u0000\u0000\u00ea\u0000\u0000\u0000" +
|
||||||
|
"\u0021\u0000\u0000\u0000\u0007\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u001d\u0000\u0000\u0000\u003f\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0064\u0065\u006d\u006f\u0070\u0061\u0072\u0061" +
|
||||||
|
"\u006d\u0073\u002e\u0063\u0061\u0070\u006e\u0070" +
|
||||||
|
"\u003a\u0054\u0065\u0073\u0074\u0050\u0061\u0072" +
|
||||||
|
"\u0061\u006d\u0073\u0031\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000" +
|
||||||
|
"\u0004\u0000\u0000\u0000\u0003\u0000\u0004\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0001\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\r\u0000\u0000\u0000\u003a\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0008\u0000\u0000\u0000\u0003\u0000\u0001\u0000" +
|
||||||
|
"\u0014\u0000\u0000\u0000\u0002\u0000\u0001\u0000" +
|
||||||
|
"\u0070\u0061\u0072\u0061\u006d\u0030\u0000\u0000" +
|
||||||
|
"\u0012\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0012\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + "");
|
||||||
|
public static final org.capnproto.SegmentReader b_99852ee4d45ddb3e =
|
||||||
|
org.capnproto.GeneratedClassSupport.decodeRawBytes(
|
||||||
|
"\u0000\u0000\u0000\u0000\u0005\u0000\u0006\u0000" +
|
||||||
|
"\u003e\u00db\u005d\u00d4\u00e4\u002e\u0085\u0099" +
|
||||||
|
"\u0011\u0000\u0000\u0000\u0001\u0000\u0000\u0000" +
|
||||||
|
"\u00c4\u0053\u0042\u00d6\u0097\u0077\u00b5\u0091" +
|
||||||
|
"\u0001\u0000\u0007\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0015\u0000\u0000\u0000\u00f2\u0000\u0000\u0000" +
|
||||||
|
"\u0021\u0000\u0000\u0000\u0007\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u001d\u0000\u0000\u0000\u003f\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0064\u0065\u006d\u006f\u0070\u0061\u0072\u0061" +
|
||||||
|
"\u006d\u0073\u002e\u0063\u0061\u0070\u006e\u0070" +
|
||||||
|
"\u003a\u0054\u0065\u0073\u0074\u0052\u0065\u0073" +
|
||||||
|
"\u0075\u006c\u0074\u0073\u0031\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000" +
|
||||||
|
"\u0004\u0000\u0000\u0000\u0003\u0000\u0004\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0001\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\r\u0000\u0000\u0000\u0042\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0008\u0000\u0000\u0000\u0003\u0000\u0001\u0000" +
|
||||||
|
"\u0014\u0000\u0000\u0000\u0002\u0000\u0001\u0000" +
|
||||||
|
"\u0072\u0065\u0073\u0075\u006c\u0074\u0030\u0000" +
|
||||||
|
"\u0012\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0012\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" +
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" + "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
12
runtime/src/test/java/org/capnproto/demo/democap.capnp
Normal file
12
runtime/src/test/java/org/capnproto/demo/democap.capnp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
@0xf29f4ba3b0a5a945;
|
||||||
|
|
||||||
|
using Params = import "demoparams.capnp";
|
||||||
|
|
||||||
|
interface TestCap0 {
|
||||||
|
testMethod0 @0 Params.TestParams0 -> Params.TestResults0;
|
||||||
|
testMethod1 @1 Params.TestParams1 -> Params.TestResults1;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TestCap1 {
|
||||||
|
}
|
||||||
|
|
190
runtime/src/test/java/org/capnproto/demo/democap.capnp.c++
Normal file
190
runtime/src/test/java/org/capnproto/demo/democap.capnp.c++
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||||
|
// source: democap.capnp
|
||||||
|
|
||||||
|
#include "democap.capnp.h"
|
||||||
|
|
||||||
|
namespace capnp {
|
||||||
|
namespace schemas {
|
||||||
|
static const ::capnp::_::AlignedData<40> b_a65f4a3d7f622e6b = {
|
||||||
|
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||||
|
107, 46, 98, 127, 61, 74, 95, 166,
|
||||||
|
14, 0, 0, 0, 3, 0, 0, 0,
|
||||||
|
69, 169, 165, 176, 163, 75, 159, 242,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
21, 0, 0, 0, 186, 0, 0, 0,
|
||||||
|
29, 0, 0, 0, 7, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
25, 0, 0, 0, 135, 0, 0, 0,
|
||||||
|
113, 0, 0, 0, 7, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
100, 101, 109, 111, 99, 97, 112, 46,
|
||||||
|
99, 97, 112, 110, 112, 58, 84, 101,
|
||||||
|
115, 116, 67, 97, 112, 48, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 1, 0,
|
||||||
|
8, 0, 0, 0, 3, 0, 5, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
18, 240, 128, 209, 172, 180, 1, 179,
|
||||||
|
129, 40, 181, 33, 84, 46, 164, 150,
|
||||||
|
49, 0, 0, 0, 98, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
41, 0, 0, 0, 7, 0, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
87, 9, 34, 182, 168, 99, 3, 225,
|
||||||
|
62, 219, 93, 212, 228, 46, 133, 153,
|
||||||
|
29, 0, 0, 0, 98, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
21, 0, 0, 0, 7, 0, 0, 0,
|
||||||
|
116, 101, 115, 116, 77, 101, 116, 104,
|
||||||
|
111, 100, 48, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 1, 0,
|
||||||
|
116, 101, 115, 116, 77, 101, 116, 104,
|
||||||
|
111, 100, 49, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 1, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 1, 0, }
|
||||||
|
};
|
||||||
|
::capnp::word const* const bp_a65f4a3d7f622e6b = b_a65f4a3d7f622e6b.words;
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
static const ::capnp::_::RawSchema* const d_a65f4a3d7f622e6b[] = {
|
||||||
|
&s_96a42e5421b52881,
|
||||||
|
&s_99852ee4d45ddb3e,
|
||||||
|
&s_b301b4acd180f012,
|
||||||
|
&s_e10363a8b6220957,
|
||||||
|
};
|
||||||
|
static const uint16_t m_a65f4a3d7f622e6b[] = {0, 1};
|
||||||
|
const ::capnp::_::RawSchema s_a65f4a3d7f622e6b = {
|
||||||
|
0xa65f4a3d7f622e6b, b_a65f4a3d7f622e6b.words, 40, d_a65f4a3d7f622e6b, m_a65f4a3d7f622e6b,
|
||||||
|
4, 2, nullptr, nullptr, nullptr, { &s_a65f4a3d7f622e6b, nullptr, nullptr, 0, 0, nullptr }
|
||||||
|
};
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
static const ::capnp::_::AlignedData<18> b_81da3f8f6079c216 = {
|
||||||
|
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||||
|
22, 194, 121, 96, 143, 63, 218, 129,
|
||||||
|
14, 0, 0, 0, 3, 0, 0, 0,
|
||||||
|
69, 169, 165, 176, 163, 75, 159, 242,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
21, 0, 0, 0, 186, 0, 0, 0,
|
||||||
|
29, 0, 0, 0, 7, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
25, 0, 0, 0, 7, 0, 0, 0,
|
||||||
|
25, 0, 0, 0, 7, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
100, 101, 109, 111, 99, 97, 112, 46,
|
||||||
|
99, 97, 112, 110, 112, 58, 84, 101,
|
||||||
|
115, 116, 67, 97, 112, 49, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 1, 0,
|
||||||
|
0, 0, 0, 0, 3, 0, 5, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 1, 0, }
|
||||||
|
};
|
||||||
|
::capnp::word const* const bp_81da3f8f6079c216 = b_81da3f8f6079c216.words;
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
const ::capnp::_::RawSchema s_81da3f8f6079c216 = {
|
||||||
|
0x81da3f8f6079c216, b_81da3f8f6079c216.words, 18, nullptr, nullptr,
|
||||||
|
0, 0, nullptr, nullptr, nullptr, { &s_81da3f8f6079c216, nullptr, nullptr, 0, 0, nullptr }
|
||||||
|
};
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
} // namespace schemas
|
||||||
|
} // namespace capnp
|
||||||
|
|
||||||
|
// =======================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
::capnp::Request< ::TestParams0, ::TestResults0>
|
||||||
|
TestCap0::Client::testMethod0Request(::kj::Maybe< ::capnp::MessageSize> sizeHint) {
|
||||||
|
return newCall< ::TestParams0, ::TestResults0>(
|
||||||
|
0xa65f4a3d7f622e6bull, 0, sizeHint);
|
||||||
|
}
|
||||||
|
::kj::Promise<void> TestCap0::Server::testMethod0(TestMethod0Context) {
|
||||||
|
return ::capnp::Capability::Server::internalUnimplemented(
|
||||||
|
"democap.capnp:TestCap0", "testMethod0",
|
||||||
|
0xa65f4a3d7f622e6bull, 0);
|
||||||
|
}
|
||||||
|
::capnp::Request< ::TestParams1, ::TestResults1>
|
||||||
|
TestCap0::Client::testMethod1Request(::kj::Maybe< ::capnp::MessageSize> sizeHint) {
|
||||||
|
return newCall< ::TestParams1, ::TestResults1>(
|
||||||
|
0xa65f4a3d7f622e6bull, 1, sizeHint);
|
||||||
|
}
|
||||||
|
::kj::Promise<void> TestCap0::Server::testMethod1(TestMethod1Context) {
|
||||||
|
return ::capnp::Capability::Server::internalUnimplemented(
|
||||||
|
"democap.capnp:TestCap0", "testMethod1",
|
||||||
|
0xa65f4a3d7f622e6bull, 1);
|
||||||
|
}
|
||||||
|
::capnp::Capability::Server::DispatchCallResult TestCap0::Server::dispatchCall(
|
||||||
|
uint64_t interfaceId, uint16_t methodId,
|
||||||
|
::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) {
|
||||||
|
switch (interfaceId) {
|
||||||
|
case 0xa65f4a3d7f622e6bull:
|
||||||
|
return dispatchCallInternal(methodId, context);
|
||||||
|
default:
|
||||||
|
return internalUnimplemented("democap.capnp:TestCap0", interfaceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::capnp::Capability::Server::DispatchCallResult TestCap0::Server::dispatchCallInternal(
|
||||||
|
uint16_t methodId,
|
||||||
|
::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) {
|
||||||
|
switch (methodId) {
|
||||||
|
case 0:
|
||||||
|
return {
|
||||||
|
testMethod0(::capnp::Capability::Server::internalGetTypedContext<
|
||||||
|
::TestParams0, ::TestResults0>(context)),
|
||||||
|
false
|
||||||
|
};
|
||||||
|
case 1:
|
||||||
|
return {
|
||||||
|
testMethod1(::capnp::Capability::Server::internalGetTypedContext<
|
||||||
|
::TestParams1, ::TestResults1>(context)),
|
||||||
|
false
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
(void)context;
|
||||||
|
return ::capnp::Capability::Server::internalUnimplemented(
|
||||||
|
"democap.capnp:TestCap0",
|
||||||
|
0xa65f4a3d7f622e6bull, methodId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
|
||||||
|
// TestCap0
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
constexpr ::capnp::Kind TestCap0::_capnpPrivate::kind;
|
||||||
|
constexpr ::capnp::_::RawSchema const* TestCap0::_capnpPrivate::schema;
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
::capnp::Capability::Server::DispatchCallResult TestCap1::Server::dispatchCall(
|
||||||
|
uint64_t interfaceId, uint16_t methodId,
|
||||||
|
::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) {
|
||||||
|
switch (interfaceId) {
|
||||||
|
case 0x81da3f8f6079c216ull:
|
||||||
|
return dispatchCallInternal(methodId, context);
|
||||||
|
default:
|
||||||
|
return internalUnimplemented("democap.capnp:TestCap1", interfaceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::capnp::Capability::Server::DispatchCallResult TestCap1::Server::dispatchCallInternal(
|
||||||
|
uint16_t methodId,
|
||||||
|
::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context) {
|
||||||
|
switch (methodId) {
|
||||||
|
default:
|
||||||
|
(void)context;
|
||||||
|
return ::capnp::Capability::Server::internalUnimplemented(
|
||||||
|
"democap.capnp:TestCap1",
|
||||||
|
0x81da3f8f6079c216ull, methodId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
|
||||||
|
// TestCap1
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
constexpr ::capnp::Kind TestCap1::_capnpPrivate::kind;
|
||||||
|
constexpr ::capnp::_::RawSchema const* TestCap1::_capnpPrivate::schema;
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
|
||||||
|
|
||||||
|
|
216
runtime/src/test/java/org/capnproto/demo/democap.capnp.h
Normal file
216
runtime/src/test/java/org/capnproto/demo/democap.capnp.h
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
// Generated by Cap'n Proto compiler, DO NOT EDIT
|
||||||
|
// source: democap.capnp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <capnp/generated-header-support.h>
|
||||||
|
#include <kj/windows-sanity.h>
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
#include <capnp/capability.h>
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
|
||||||
|
#if CAPNP_VERSION != 8000
|
||||||
|
#error "Version mismatch between generated code and library headers. You must use the same version of the Cap'n Proto compiler and library."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "demoparams.capnp.h"
|
||||||
|
|
||||||
|
namespace capnp {
|
||||||
|
namespace schemas {
|
||||||
|
|
||||||
|
CAPNP_DECLARE_SCHEMA(a65f4a3d7f622e6b);
|
||||||
|
CAPNP_DECLARE_SCHEMA(81da3f8f6079c216);
|
||||||
|
|
||||||
|
} // namespace schemas
|
||||||
|
} // namespace capnp
|
||||||
|
|
||||||
|
|
||||||
|
struct TestCap0 {
|
||||||
|
TestCap0() = delete;
|
||||||
|
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
class Client;
|
||||||
|
class Server;
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
|
||||||
|
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
struct _capnpPrivate {
|
||||||
|
CAPNP_DECLARE_INTERFACE_HEADER(a65f4a3d7f622e6b)
|
||||||
|
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||||
|
};
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TestCap1 {
|
||||||
|
TestCap1() = delete;
|
||||||
|
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
class Client;
|
||||||
|
class Server;
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
|
||||||
|
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
struct _capnpPrivate {
|
||||||
|
CAPNP_DECLARE_INTERFACE_HEADER(81da3f8f6079c216)
|
||||||
|
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||||
|
};
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
};
|
||||||
|
|
||||||
|
// =======================================================================================
|
||||||
|
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
class TestCap0::Client
|
||||||
|
: public virtual ::capnp::Capability::Client {
|
||||||
|
public:
|
||||||
|
typedef TestCap0 Calls;
|
||||||
|
typedef TestCap0 Reads;
|
||||||
|
|
||||||
|
Client(decltype(nullptr));
|
||||||
|
explicit Client(::kj::Own< ::capnp::ClientHook>&& hook);
|
||||||
|
template <typename _t, typename = ::kj::EnableIf< ::kj::canConvert<_t*, Server*>()>>
|
||||||
|
Client(::kj::Own<_t>&& server);
|
||||||
|
template <typename _t, typename = ::kj::EnableIf< ::kj::canConvert<_t*, Client*>()>>
|
||||||
|
Client(::kj::Promise<_t>&& promise);
|
||||||
|
Client(::kj::Exception&& exception);
|
||||||
|
Client(Client&) = default;
|
||||||
|
Client(Client&&) = default;
|
||||||
|
Client& operator=(Client& other);
|
||||||
|
Client& operator=(Client&& other);
|
||||||
|
|
||||||
|
::capnp::Request< ::TestParams0, ::TestResults0> testMethod0Request(
|
||||||
|
::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr);
|
||||||
|
::capnp::Request< ::TestParams1, ::TestResults1> testMethod1Request(
|
||||||
|
::kj::Maybe< ::capnp::MessageSize> sizeHint = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Client() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestCap0::Server
|
||||||
|
: public virtual ::capnp::Capability::Server {
|
||||||
|
public:
|
||||||
|
typedef TestCap0 Serves;
|
||||||
|
|
||||||
|
::capnp::Capability::Server::DispatchCallResult dispatchCall(
|
||||||
|
uint64_t interfaceId, uint16_t methodId,
|
||||||
|
::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context)
|
||||||
|
override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef ::capnp::CallContext< ::TestParams0, ::TestResults0> TestMethod0Context;
|
||||||
|
virtual ::kj::Promise<void> testMethod0(TestMethod0Context context);
|
||||||
|
typedef ::capnp::CallContext< ::TestParams1, ::TestResults1> TestMethod1Context;
|
||||||
|
virtual ::kj::Promise<void> testMethod1(TestMethod1Context context);
|
||||||
|
|
||||||
|
inline ::TestCap0::Client thisCap() {
|
||||||
|
return ::capnp::Capability::Server::thisCap()
|
||||||
|
.template castAs< ::TestCap0>();
|
||||||
|
}
|
||||||
|
|
||||||
|
::capnp::Capability::Server::DispatchCallResult dispatchCallInternal(
|
||||||
|
uint16_t methodId,
|
||||||
|
::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context);
|
||||||
|
};
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
class TestCap1::Client
|
||||||
|
: public virtual ::capnp::Capability::Client {
|
||||||
|
public:
|
||||||
|
typedef TestCap1 Calls;
|
||||||
|
typedef TestCap1 Reads;
|
||||||
|
|
||||||
|
Client(decltype(nullptr));
|
||||||
|
explicit Client(::kj::Own< ::capnp::ClientHook>&& hook);
|
||||||
|
template <typename _t, typename = ::kj::EnableIf< ::kj::canConvert<_t*, Server*>()>>
|
||||||
|
Client(::kj::Own<_t>&& server);
|
||||||
|
template <typename _t, typename = ::kj::EnableIf< ::kj::canConvert<_t*, Client*>()>>
|
||||||
|
Client(::kj::Promise<_t>&& promise);
|
||||||
|
Client(::kj::Exception&& exception);
|
||||||
|
Client(Client&) = default;
|
||||||
|
Client(Client&&) = default;
|
||||||
|
Client& operator=(Client& other);
|
||||||
|
Client& operator=(Client&& other);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Client() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestCap1::Server
|
||||||
|
: public virtual ::capnp::Capability::Server {
|
||||||
|
public:
|
||||||
|
typedef TestCap1 Serves;
|
||||||
|
|
||||||
|
::capnp::Capability::Server::DispatchCallResult dispatchCall(
|
||||||
|
uint64_t interfaceId, uint16_t methodId,
|
||||||
|
::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context)
|
||||||
|
override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
inline ::TestCap1::Client thisCap() {
|
||||||
|
return ::capnp::Capability::Server::thisCap()
|
||||||
|
.template castAs< ::TestCap1>();
|
||||||
|
}
|
||||||
|
|
||||||
|
::capnp::Capability::Server::DispatchCallResult dispatchCallInternal(
|
||||||
|
uint16_t methodId,
|
||||||
|
::capnp::CallContext< ::capnp::AnyPointer, ::capnp::AnyPointer> context);
|
||||||
|
};
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
|
||||||
|
// =======================================================================================
|
||||||
|
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
inline TestCap0::Client::Client(decltype(nullptr))
|
||||||
|
: ::capnp::Capability::Client(nullptr) {}
|
||||||
|
inline TestCap0::Client::Client(
|
||||||
|
::kj::Own< ::capnp::ClientHook>&& hook)
|
||||||
|
: ::capnp::Capability::Client(::kj::mv(hook)) {}
|
||||||
|
template <typename _t, typename>
|
||||||
|
inline TestCap0::Client::Client(::kj::Own<_t>&& server)
|
||||||
|
: ::capnp::Capability::Client(::kj::mv(server)) {}
|
||||||
|
template <typename _t, typename>
|
||||||
|
inline TestCap0::Client::Client(::kj::Promise<_t>&& promise)
|
||||||
|
: ::capnp::Capability::Client(::kj::mv(promise)) {}
|
||||||
|
inline TestCap0::Client::Client(::kj::Exception&& exception)
|
||||||
|
: ::capnp::Capability::Client(::kj::mv(exception)) {}
|
||||||
|
inline ::TestCap0::Client& TestCap0::Client::operator=(Client& other) {
|
||||||
|
::capnp::Capability::Client::operator=(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline ::TestCap0::Client& TestCap0::Client::operator=(Client&& other) {
|
||||||
|
::capnp::Capability::Client::operator=(kj::mv(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
#if !CAPNP_LITE
|
||||||
|
inline TestCap1::Client::Client(decltype(nullptr))
|
||||||
|
: ::capnp::Capability::Client(nullptr) {}
|
||||||
|
inline TestCap1::Client::Client(
|
||||||
|
::kj::Own< ::capnp::ClientHook>&& hook)
|
||||||
|
: ::capnp::Capability::Client(::kj::mv(hook)) {}
|
||||||
|
template <typename _t, typename>
|
||||||
|
inline TestCap1::Client::Client(::kj::Own<_t>&& server)
|
||||||
|
: ::capnp::Capability::Client(::kj::mv(server)) {}
|
||||||
|
template <typename _t, typename>
|
||||||
|
inline TestCap1::Client::Client(::kj::Promise<_t>&& promise)
|
||||||
|
: ::capnp::Capability::Client(::kj::mv(promise)) {}
|
||||||
|
inline TestCap1::Client::Client(::kj::Exception&& exception)
|
||||||
|
: ::capnp::Capability::Client(::kj::mv(exception)) {}
|
||||||
|
inline ::TestCap1::Client& TestCap1::Client::operator=(Client& other) {
|
||||||
|
::capnp::Capability::Client::operator=(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline ::TestCap1::Client& TestCap1::Client::operator=(Client&& other) {
|
||||||
|
::capnp::Capability::Client::operator=(kj::mv(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !CAPNP_LITE
|
||||||
|
|
23
runtime/src/test/java/org/capnproto/demo/demoparams.capnp
Normal file
23
runtime/src/test/java/org/capnproto/demo/demoparams.capnp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
@0x91b57797d64253c4;
|
||||||
|
|
||||||
|
using Java = import "/capnp/java.capnp";
|
||||||
|
$Java.package("org.capnproto.demo");
|
||||||
|
$Java.outerClassname("Demo");
|
||||||
|
|
||||||
|
struct TestParams0 {
|
||||||
|
param0 @0 :Int32;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestResults0 {
|
||||||
|
result0 @0 :Int32;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestParams1 {
|
||||||
|
param0 @0 :AnyPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestResults1 {
|
||||||
|
result0 @0 :AnyPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue