1// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
2// Licensed under the MIT License:
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21
22#pragma once
23
24#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
25#pragma GCC system_header
26#endif
27
28#if CAPNP_LITE
29#error "RPC APIs, including this header, are not available in lite mode."
30#endif
31
32#include <kj/async.h>
33#include <kj/vector.h>
34#include "raw-schema.h"
35#include "any.h"
36#include "pointer-helpers.h"
37
38namespace capnp {
39
40template <typename Results>
41class Response;
42
43template <typename T>
44class RemotePromise: public kj::Promise<Response<T>>, public T::Pipeline {
45 // A Promise which supports pipelined calls. T is typically a struct type. T must declare
46 // an inner "mix-in" type "Pipeline" which implements pipelining; RemotePromise simply
47 // multiply-inherits that type along with Promise<Response<T>>. T::Pipeline must be movable,
48 // but does not need to be copyable (i.e. just like Promise<T>).
49 //
50 // The promise is for an owned pointer so that the RPC system can allocate the MessageReader
51 // itself.
52
53public:
54 inline RemotePromise(kj::Promise<Response<T>>&& promise, typename T::Pipeline&& pipeline)
55 : kj::Promise<Response<T>>(kj::mv(promise)),
56 T::Pipeline(kj::mv(pipeline)) {}
57 inline RemotePromise(decltype(nullptr))
58 : kj::Promise<Response<T>>(nullptr),
59 T::Pipeline(nullptr) {}
60 KJ_DISALLOW_COPY(RemotePromise);
61 RemotePromise(RemotePromise&& other) = default;
62 RemotePromise& operator=(RemotePromise&& other) = default;
63
64 static RemotePromise<T> reducePromise(kj::Promise<RemotePromise>&& promise);
65 // Hook for KJ so that Promise<RemotePromise<T>> automatically reduces to RemotePromise<T>.
66};
67
68class LocalClient;
69namespace _ { // private
70extern const RawSchema NULL_INTERFACE_SCHEMA; // defined in schema.c++
71class CapabilityServerSetBase;
72} // namespace _ (private)
73
74struct Capability {
75 // A capability without type-safe methods. Typed capability clients wrap `Client` and typed
76 // capability servers subclass `Server` to dispatch to the regular, typed methods.
77
78 class Client;
79 class Server;
80
81 struct _capnpPrivate {
82 struct IsInterface;
83 static constexpr uint64_t typeId = 0x3;
84 static constexpr Kind kind = Kind::INTERFACE;
85 static constexpr _::RawSchema const* schema = &_::NULL_INTERFACE_SCHEMA;
86
87 static const _::RawBrandedSchema* brand() {
88 return &_::NULL_INTERFACE_SCHEMA.defaultBrand;
89 }
90 };
91};
92
93// =======================================================================================
94// Capability clients
95
96class RequestHook;
97class ResponseHook;
98class PipelineHook;
99class ClientHook;
100
101template <typename Params, typename Results>
102class Request: public Params::Builder {
103 // A call that hasn't been sent yet. This class extends a Builder for the call's "Params"
104 // structure with a method send() that actually sends it.
105 //
106 // Given a Cap'n Proto method `foo(a :A, b :B): C`, the generated client interface will have
107 // a method `Request<FooParams, C> fooRequest()` (as well as a convenience method
108 // `RemotePromise<C> foo(A::Reader a, B::Reader b)`).
109
110public:
111 inline Request(typename Params::Builder builder, kj::Own<RequestHook>&& hook)
112 : Params::Builder(builder), hook(kj::mv(hook)) {}
113 inline Request(decltype(nullptr)): Params::Builder(nullptr) {}
114
115 RemotePromise<Results> send() KJ_WARN_UNUSED_RESULT;
116 // Send the call and return a promise for the results.
117
118private:
119 kj::Own<RequestHook> hook;
120
121 friend class Capability::Client;
122 friend struct DynamicCapability;
123 template <typename, typename>
124 friend class CallContext;
125 friend class RequestHook;
126};
127
128template <typename Results>
129class Response: public Results::Reader {
130 // A completed call. This class extends a Reader for the call's answer structure. The Response
131 // is move-only -- once it goes out-of-scope, the underlying message will be freed.
132
133public:
134 inline Response(typename Results::Reader reader, kj::Own<ResponseHook>&& hook)
135 : Results::Reader(reader), hook(kj::mv(hook)) {}
136
137private:
138 kj::Own<ResponseHook> hook;
139
140 template <typename, typename>
141 friend class Request;
142 friend class ResponseHook;
143};
144
145class Capability::Client {
146 // Base type for capability clients.
147
148public:
149 typedef Capability Reads;
150 typedef Capability Calls;
151
152 Client(decltype(nullptr));
153 // If you need to declare a Client before you have anything to assign to it (perhaps because
154 // the assignment is going to occur in an if/else scope), you can start by initializing it to
155 // `nullptr`. The resulting client is not meant to be called and throws exceptions from all
156 // methods.
157
158 template <typename T, typename = kj::EnableIf<kj::canConvert<T*, Capability::Server*>()>>
159 Client(kj::Own<T>&& server);
160 // Make a client capability that wraps the given server capability. The server's methods will
161 // only be executed in the given EventLoop, regardless of what thread calls the client's methods.
162
163 template <typename T, typename = kj::EnableIf<kj::canConvert<T*, Client*>()>>
164 Client(kj::Promise<T>&& promise);
165 // Make a client from a promise for a future client. The resulting client queues calls until the
166 // promise resolves.
167
168 Client(kj::Exception&& exception);
169 // Make a broken client that throws the given exception from all calls.
170
171 Client(Client& other);
172 Client& operator=(Client& other);
173 // Copies by reference counting. Warning: This refcounting is not thread-safe. All copies of
174 // the client must remain in one thread.
175
176 Client(Client&&) = default;
177 Client& operator=(Client&&) = default;
178 // Move constructor avoids reference counting.
179
180 explicit Client(kj::Own<ClientHook>&& hook);
181 // For use by the RPC implementation: Wrap a ClientHook.
182
183 template <typename T>
184 typename T::Client castAs();
185 // Reinterpret the capability as implementing the given interface. Note that no error will occur
186 // here if the capability does not actually implement this interface, but later method calls will
187 // fail. It's up to the application to decide how indicate that additional interfaces are
188 // supported.
189 //
190 // TODO(perf): GCC 4.8 / Clang 3.3: rvalue-qualified version for better performance.
191
192 template <typename T>
193 typename T::Client castAs(InterfaceSchema schema);
194 // Dynamic version. `T` must be `DynamicCapability`, and you must `#include <capnp/dynamic.h>`.
195
196 kj::Promise<void> whenResolved();
197 // If the capability is actually only a promise, the returned promise resolves once the
198 // capability itself has resolved to its final destination (or propagates the exception if
199 // the capability promise is rejected). This is mainly useful for error-checking in the case
200 // where no calls are being made. There is no reason to wait for this before making calls; if
201 // the capability does not resolve, the call results will propagate the error.
202
203 Request<AnyPointer, AnyPointer> typelessRequest(
204 uint64_t interfaceId, uint16_t methodId,
205 kj::Maybe<MessageSize> sizeHint);
206 // Make a request without knowing the types of the params or results. You specify the type ID
207 // and method number manually.
208
209 // TODO(someday): method(s) for Join
210
211protected:
212 Client() = default;
213
214 template <typename Params, typename Results>
215 Request<Params, Results> newCall(uint64_t interfaceId, uint16_t methodId,
216 kj::Maybe<MessageSize> sizeHint);
217
218private:
219 kj::Own<ClientHook> hook;
220
221 static kj::Own<ClientHook> makeLocalClient(kj::Own<Capability::Server>&& server);
222
223 template <typename, Kind>
224 friend struct _::PointerHelpers;
225 friend struct DynamicCapability;
226 friend class Orphanage;
227 friend struct DynamicStruct;
228 friend struct DynamicList;
229 template <typename, Kind>
230 friend struct List;
231 friend class _::CapabilityServerSetBase;
232 friend class ClientHook;
233};
234
235// =======================================================================================
236// Capability servers
237
238class CallContextHook;
239
240template <typename Params, typename Results>
241class CallContext: public kj::DisallowConstCopy {
242 // Wrapper around CallContextHook with a specific return type.
243 //
244 // Methods of this class may only be called from within the server's event loop, not from other
245 // threads.
246 //
247 // The CallContext becomes invalid as soon as the call reports completion.
248
249public:
250 explicit CallContext(CallContextHook& hook);
251
252 typename Params::Reader getParams();
253 // Get the params payload.
254
255 void releaseParams();
256 // Release the params payload. getParams() will throw an exception after this is called.
257 // Releasing the params may allow the RPC system to free up buffer space to handle other
258 // requests. Long-running asynchronous methods should try to call this as early as is
259 // convenient.
260
261 typename Results::Builder getResults(kj::Maybe<MessageSize> sizeHint = nullptr);
262 typename Results::Builder initResults(kj::Maybe<MessageSize> sizeHint = nullptr);
263 void setResults(typename Results::Reader value);
264 void adoptResults(Orphan<Results>&& value);
265 Orphanage getResultsOrphanage(kj::Maybe<MessageSize> sizeHint = nullptr);
266 // Manipulate the results payload. The "Return" message (part of the RPC protocol) will
267 // typically be allocated the first time one of these is called. Some RPC systems may
268 // allocate these messages in a limited space (such as a shared memory segment), therefore the
269 // application should delay calling these as long as is convenient to do so (but don't delay
270 // if doing so would require extra copies later).
271 //
272 // `sizeHint` indicates a guess at the message size. This will usually be used to decide how
273 // much space to allocate for the first message segment (don't worry: only space that is actually
274 // used will be sent on the wire). If omitted, the system decides. The message root pointer
275 // should not be included in the size. So, if you are simply going to copy some existing message
276 // directly into the results, just call `.totalSize()` and pass that in.
277
278 template <typename SubParams>
279 kj::Promise<void> tailCall(Request<SubParams, Results>&& tailRequest);
280 // Resolve the call by making a tail call. `tailRequest` is a request that has been filled in
281 // but not yet sent. The context will send the call, then fill in the results with the result
282 // of the call. If tailCall() is used, {get,init,set,adopt}Results (above) *must not* be called.
283 //
284 // The RPC implementation may be able to optimize a tail call to another machine such that the
285 // results never actually pass through this machine. Even if no such optimization is possible,
286 // `tailCall()` may allow pipelined calls to be forwarded optimistically to the new call site.
287 //
288 // In general, this should be the last thing a method implementation calls, and the promise
289 // returned from `tailCall()` should then be returned by the method implementation.
290
291 void allowCancellation();
292 // Indicate that it is OK for the RPC system to discard its Promise for this call's result if
293 // the caller cancels the call, thereby transitively canceling any asynchronous operations the
294 // call implementation was performing. This is not done by default because it could represent a
295 // security risk: applications must be carefully written to ensure that they do not end up in
296 // a bad state if an operation is canceled at an arbitrary point. However, for long-running
297 // method calls that hold significant resources, prompt cancellation is often useful.
298 //
299 // Keep in mind that asynchronous cancellation cannot occur while the method is synchronously
300 // executing on a local thread. The method must perform an asynchronous operation or call
301 // `EventLoop::current().evalLater()` to yield control.
302 //
303 // Note: You might think that we should offer `onCancel()` and/or `isCanceled()` methods that
304 // provide notification when the caller cancels the request without forcefully killing off the
305 // promise chain. Unfortunately, this composes poorly with promise forking: the canceled
306 // path may be just one branch of a fork of the result promise. The other branches still want
307 // the call to continue. Promise forking is used within the Cap'n Proto implementation -- in
308 // particular each pipelined call forks the result promise. So, if a caller made a pipelined
309 // call and then dropped the original object, the call should not be canceled, but it would be
310 // excessively complicated for the framework to avoid notififying of cancellation as long as
311 // pipelined calls still exist.
312
313private:
314 CallContextHook* hook;
315
316 friend class Capability::Server;
317 friend struct DynamicCapability;
318};
319
320class Capability::Server {
321 // Objects implementing a Cap'n Proto interface must subclass this. Typically, such objects
322 // will instead subclass a typed Server interface which will take care of implementing
323 // dispatchCall().
324
325public:
326 typedef Capability Serves;
327
328 virtual kj::Promise<void> dispatchCall(uint64_t interfaceId, uint16_t methodId,
329 CallContext<AnyPointer, AnyPointer> context) = 0;
330 // Call the given method. `params` is the input struct, and should be released as soon as it
331 // is no longer needed. `context` may be used to allocate the output struct and deal with
332 // cancellation.
333
334 // TODO(someday): Method which can optionally be overridden to implement Join when the object is
335 // a proxy.
336
337protected:
338 inline Capability::Client thisCap();
339 // Get a capability pointing to this object, much like the `this` keyword.
340 //
341 // The effect of this method is undefined if:
342 // - No capability client has been created pointing to this object. (This is always the case in
343 // the server's constructor.)
344 // - The capability client pointing at this object has been destroyed. (This is always the case
345 // in the server's destructor.)
346 // - Multiple capability clients have been created around the same server (possible if the server
347 // is refcounted, which is not recommended since the client itself provides refcounting).
348
349 template <typename Params, typename Results>
350 CallContext<Params, Results> internalGetTypedContext(
351 CallContext<AnyPointer, AnyPointer> typeless);
352 kj::Promise<void> internalUnimplemented(const char* actualInterfaceName,
353 uint64_t requestedTypeId);
354 kj::Promise<void> internalUnimplemented(const char* interfaceName,
355 uint64_t typeId, uint16_t methodId);
356 kj::Promise<void> internalUnimplemented(const char* interfaceName, const char* methodName,
357 uint64_t typeId, uint16_t methodId);
358
359private:
360 ClientHook* thisHook = nullptr;
361 friend class LocalClient;
362};
363
364// =======================================================================================
365
366class ReaderCapabilityTable: private _::CapTableReader {
367 // Class which imbues Readers with the ability to read capabilities.
368 //
369 // In Cap'n Proto format, the encoding of a capability pointer is simply an integer index into
370 // an external table. Since these pointers fundamentally point outside the message, a
371 // MessageReader by default has no idea what they point at, and therefore reading capabilities
372 // from such a reader will throw exceptions.
373 //
374 // In order to be able to read capabilities, you must first attach a capability table, using
375 // this class. By "imbuing" a Reader, you get a new Reader which will interpret capability
376 // pointers by treating them as indexes into the ReaderCapabilityTable.
377 //
378 // Note that when using Cap'n Proto's RPC system, this is handled automatically.
379
380public:
381 explicit ReaderCapabilityTable(kj::Array<kj::Maybe<kj::Own<ClientHook>>> table);
382 KJ_DISALLOW_COPY(ReaderCapabilityTable);
383
384 template <typename T>
385 T imbue(T reader);
386 // Return a reader equivalent to `reader` except that when reading capability-valued fields,
387 // the capabilities are looked up in this table.
388
389private:
390 kj::Array<kj::Maybe<kj::Own<ClientHook>>> table;
391
392 kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) override;
393};
394
395class BuilderCapabilityTable: private _::CapTableBuilder {
396 // Class which imbues Builders with the ability to read and write capabilities.
397 //
398 // This is much like ReaderCapabilityTable, except for builders. The table starts out empty,
399 // but capabilities can be added to it over time.
400
401public:
402 BuilderCapabilityTable();
403 KJ_DISALLOW_COPY(BuilderCapabilityTable);
404
405 inline kj::ArrayPtr<kj::Maybe<kj::Own<ClientHook>>> getTable() { return table; }
406
407 template <typename T>
408 T imbue(T builder);
409 // Return a builder equivalent to `builder` except that when reading capability-valued fields,
410 // the capabilities are looked up in this table.
411
412private:
413 kj::Vector<kj::Maybe<kj::Own<ClientHook>>> table;
414
415 kj::Maybe<kj::Own<ClientHook>> extractCap(uint index) override;
416 uint injectCap(kj::Own<ClientHook>&& cap) override;
417 void dropCap(uint index) override;
418};
419
420// =======================================================================================
421
422namespace _ { // private
423
424class CapabilityServerSetBase {
425public:
426 Capability::Client addInternal(kj::Own<Capability::Server>&& server, void* ptr);
427 kj::Promise<void*> getLocalServerInternal(Capability::Client& client);
428};
429
430} // namespace _ (private)
431
432template <typename T>
433class CapabilityServerSet: private _::CapabilityServerSetBase {
434 // Allows a server to recognize its own capabilities when passed back to it, and obtain the
435 // underlying Server objects associated with them.
436 //
437 // All objects in the set must have the same interface type T. The objects may implement various
438 // interfaces derived from T (and in fact T can be `capnp::Capability` to accept all objects),
439 // but note that if you compile with RTTI disabled then you will not be able to down-cast through
440 // virtual inheritance, and all inheritance between server interfaces is virtual. So, with RTTI
441 // disabled, you will likely need to set T to be the most-derived Cap'n Proto interface type,
442 // and you server class will need to be directly derived from that, so that you can use
443 // static_cast (or kj::downcast) to cast to it after calling getLocalServer(). (If you compile
444 // with RTTI, then you can freely dynamic_cast and ignore this issue!)
445
446public:
447 CapabilityServerSet() = default;
448 KJ_DISALLOW_COPY(CapabilityServerSet);
449
450 typename T::Client add(kj::Own<typename T::Server>&& server);
451 // Create a new capability Client for the given Server and also add this server to the set.
452
453 kj::Promise<kj::Maybe<typename T::Server&>> getLocalServer(typename T::Client& client);
454 // Given a Client pointing to a server previously passed to add(), return the corresponding
455 // Server. This returns a promise because if the input client is itself a promise, this must
456 // wait for it to resolve. Keep in mind that the server will be deleted when all clients are
457 // gone, so the caller should make sure to keep the client alive (hence why this method only
458 // accepts an lvalue input).
459};
460
461// =======================================================================================
462// Hook interfaces which must be implemented by the RPC system. Applications never call these
463// directly; the RPC system implements them and the types defined earlier in this file wrap them.
464
465class RequestHook {
466 // Hook interface implemented by RPC system representing a request being built.
467
468public:
469 virtual RemotePromise<AnyPointer> send() = 0;
470 // Send the call and return a promise for the result.
471
472 virtual const void* getBrand() = 0;
473 // Returns a void* that identifies who made this request. This can be used by an RPC adapter to
474 // discover when tail call is going to be sent over its own connection and therefore can be
475 // optimized into a remote tail call.
476
477 template <typename T, typename U>
478 inline static kj::Own<RequestHook> from(Request<T, U>&& request) {
479 return kj::mv(request.hook);
480 }
481};
482
483class ResponseHook {
484 // Hook interface implemented by RPC system representing a response.
485 //
486 // At present this class has no methods. It exists only for garbage collection -- when the
487 // ResponseHook is destroyed, the results can be freed.
488
489public:
490 virtual ~ResponseHook() noexcept(false);
491 // Just here to make sure the type is dynamic.
492
493 template <typename T>
494 inline static kj::Own<ResponseHook> from(Response<T>&& response) {
495 return kj::mv(response.hook);
496 }
497};
498
499// class PipelineHook is declared in any.h because it is needed there.
500
501class ClientHook {
502public:
503 ClientHook();
504
505 virtual Request<AnyPointer, AnyPointer> newCall(
506 uint64_t interfaceId, uint16_t methodId, kj::Maybe<MessageSize> sizeHint) = 0;
507 // Start a new call, allowing the client to allocate request/response objects as it sees fit.
508 // This version is used when calls are made from application code in the local process.
509
510 struct VoidPromiseAndPipeline {
511 kj::Promise<void> promise;
512 kj::Own<PipelineHook> pipeline;
513 };
514
515 virtual VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId,
516 kj::Own<CallContextHook>&& context) = 0;
517 // Call the object, but the caller controls allocation of the request/response objects. If the
518 // callee insists on allocating these objects itself, it must make a copy. This version is used
519 // when calls come in over the network via an RPC system. Note that even if the returned
520 // `Promise<void>` is discarded, the call may continue executing if any pipelined calls are
521 // waiting for it.
522 //
523 // Since the caller of this method chooses the CallContext implementation, it is the caller's
524 // responsibility to ensure that the returned promise is not canceled unless allowed via
525 // the context's `allowCancellation()`.
526 //
527 // The call must not begin synchronously; the callee must arrange for the call to begin in a
528 // later turn of the event loop. Otherwise, application code may call back and affect the
529 // callee's state in an unexpected way.
530
531 virtual kj::Maybe<ClientHook&> getResolved() = 0;
532 // If this ClientHook is a promise that has already resolved, returns the inner, resolved version
533 // of the capability. The caller may permanently replace this client with the resolved one if
534 // desired. Returns null if the client isn't a promise or hasn't resolved yet -- use
535 // `whenMoreResolved()` to distinguish between them.
536
537 virtual kj::Maybe<kj::Promise<kj::Own<ClientHook>>> whenMoreResolved() = 0;
538 // If this client is a settled reference (not a promise), return nullptr. Otherwise, return a
539 // promise that eventually resolves to a new client that is closer to being the final, settled
540 // client (i.e. the value eventually returned by `getResolved()`). Calling this repeatedly
541 // should eventually produce a settled client.
542
543 kj::Promise<void> whenResolved();
544 // Repeatedly calls whenMoreResolved() until it returns nullptr.
545
546 virtual kj::Own<ClientHook> addRef() = 0;
547 // Return a new reference to the same capability.
548
549 virtual const void* getBrand() = 0;
550 // Returns a void* that identifies who made this client. This can be used by an RPC adapter to
551 // discover when a capability it needs to marshal is one that it created in the first place, and
552 // therefore it can transfer the capability without proxying.
553
554 static const uint NULL_CAPABILITY_BRAND;
555 // Value is irrelevant; used for pointer.
556
557 inline bool isNull() { return getBrand() == &NULL_CAPABILITY_BRAND; }
558 // Returns true if the capability was created as a result of assigning a Client to null or by
559 // reading a null pointer out of a Cap'n Proto message.
560
561 virtual void* getLocalServer(_::CapabilityServerSetBase& capServerSet);
562 // If this is a local capability created through `capServerSet`, return the underlying Server.
563 // Otherwise, return nullptr. Default implementation (which everyone except LocalClient should
564 // use) always returns nullptr.
565
566 static kj::Own<ClientHook> from(Capability::Client client) { return kj::mv(client.hook); }
567};
568
569class CallContextHook {
570 // Hook interface implemented by RPC system to manage a call on the server side. See
571 // CallContext<T>.
572
573public:
574 virtual AnyPointer::Reader getParams() = 0;
575 virtual void releaseParams() = 0;
576 virtual AnyPointer::Builder getResults(kj::Maybe<MessageSize> sizeHint) = 0;
577 virtual kj::Promise<void> tailCall(kj::Own<RequestHook>&& request) = 0;
578 virtual void allowCancellation() = 0;
579
580 virtual kj::Promise<AnyPointer::Pipeline> onTailCall() = 0;
581 // If `tailCall()` is called, resolves to the PipelineHook from the tail call. An
582 // implementation of `ClientHook::call()` is allowed to call this at most once.
583
584 virtual ClientHook::VoidPromiseAndPipeline directTailCall(kj::Own<RequestHook>&& request) = 0;
585 // Call this when you would otherwise call onTailCall() immediately followed by tailCall().
586 // Implementations of tailCall() should typically call directTailCall() and then fulfill the
587 // promise fulfiller for onTailCall() with the returned pipeline.
588
589 virtual kj::Own<CallContextHook> addRef() = 0;
590};
591
592kj::Own<ClientHook> newLocalPromiseClient(kj::Promise<kj::Own<ClientHook>>&& promise);
593// Returns a ClientHook that queues up calls until `promise` resolves, then forwards them to
594// the new client. This hook's `getResolved()` and `whenMoreResolved()` methods will reflect the
595// redirection to the eventual replacement client.
596
597kj::Own<PipelineHook> newLocalPromisePipeline(kj::Promise<kj::Own<PipelineHook>>&& promise);
598// Returns a PipelineHook that queues up calls until `promise` resolves, then forwards them to
599// the new pipeline.
600
601kj::Own<ClientHook> newBrokenCap(kj::StringPtr reason);
602kj::Own<ClientHook> newBrokenCap(kj::Exception&& reason);
603// Helper function that creates a capability which simply throws exceptions when called.
604
605kj::Own<PipelineHook> newBrokenPipeline(kj::Exception&& reason);
606// Helper function that creates a pipeline which simply throws exceptions when called.
607
608Request<AnyPointer, AnyPointer> newBrokenRequest(
609 kj::Exception&& reason, kj::Maybe<MessageSize> sizeHint);
610// Helper function that creates a Request object that simply throws exceptions when sent.
611
612// =======================================================================================
613// Extend PointerHelpers for interfaces
614
615namespace _ { // private
616
617template <typename T>
618struct PointerHelpers<T, Kind::INTERFACE> {
619 static inline typename T::Client get(PointerReader reader) {
620 return typename T::Client(reader.getCapability());
621 }
622 static inline typename T::Client get(PointerBuilder builder) {
623 return typename T::Client(builder.getCapability());
624 }
625 static inline void set(PointerBuilder builder, typename T::Client&& value) {
626 builder.setCapability(kj::mv(value.Capability::Client::hook));
627 }
628 static inline void set(PointerBuilder builder, typename T::Client& value) {
629 builder.setCapability(value.Capability::Client::hook->addRef());
630 }
631 static inline void adopt(PointerBuilder builder, Orphan<T>&& value) {
632 builder.adopt(kj::mv(value.builder));
633 }
634 static inline Orphan<T> disown(PointerBuilder builder) {
635 return Orphan<T>(builder.disown());
636 }
637};
638
639} // namespace _ (private)
640
641// =======================================================================================
642// Extend List for interfaces
643
644template <typename T>
645struct List<T, Kind::INTERFACE> {
646 List() = delete;
647
648 class Reader {
649 public:
650 typedef List<T> Reads;
651
652 Reader() = default;
653 inline explicit Reader(_::ListReader reader): reader(reader) {}
654
655 inline uint size() const { return unbound(reader.size() / ELEMENTS); }
656 inline typename T::Client operator[](uint index) const {
657 KJ_IREQUIRE(index < size());
658 return typename T::Client(reader.getPointerElement(
659 bounded(index) * ELEMENTS).getCapability());
660 }
661
662 typedef _::IndexingIterator<const Reader, typename T::Client> Iterator;
663 inline Iterator begin() const { return Iterator(this, 0); }
664 inline Iterator end() const { return Iterator(this, size()); }
665
666 inline MessageSize totalSize() const {
667 return reader.totalSize().asPublic();
668 }
669
670 private:
671 _::ListReader reader;
672 template <typename U, Kind K>
673 friend struct _::PointerHelpers;
674 template <typename U, Kind K>
675 friend struct List;
676 friend class Orphanage;
677 template <typename U, Kind K>
678 friend struct ToDynamic_;
679 };
680
681 class Builder {
682 public:
683 typedef List<T> Builds;
684
685 Builder() = delete;
686 inline Builder(decltype(nullptr)) {}
687 inline explicit Builder(_::ListBuilder builder): builder(builder) {}
688
689 inline operator Reader() const { return Reader(builder.asReader()); }
690 inline Reader asReader() const { return Reader(builder.asReader()); }
691
692 inline uint size() const { return unbound(builder.size() / ELEMENTS); }
693 inline typename T::Client operator[](uint index) {
694 KJ_IREQUIRE(index < size());
695 return typename T::Client(builder.getPointerElement(
696 bounded(index) * ELEMENTS).getCapability());
697 }
698 inline void set(uint index, typename T::Client value) {
699 KJ_IREQUIRE(index < size());
700 builder.getPointerElement(bounded(index) * ELEMENTS).setCapability(kj::mv(value.hook));
701 }
702 inline void adopt(uint index, Orphan<T>&& value) {
703 KJ_IREQUIRE(index < size());
704 builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value));
705 }
706 inline Orphan<T> disown(uint index) {
707 KJ_IREQUIRE(index < size());
708 return Orphan<T>(builder.getPointerElement(bounded(index) * ELEMENTS).disown());
709 }
710
711 typedef _::IndexingIterator<Builder, typename T::Client> Iterator;
712 inline Iterator begin() { return Iterator(this, 0); }
713 inline Iterator end() { return Iterator(this, size()); }
714
715 private:
716 _::ListBuilder builder;
717 friend class Orphanage;
718 template <typename U, Kind K>
719 friend struct ToDynamic_;
720 };
721
722private:
723 inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
724 return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS);
725 }
726 inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
727 return builder.getList(ElementSize::POINTER, defaultValue);
728 }
729 inline static _::ListReader getFromPointer(
730 const _::PointerReader& reader, const word* defaultValue) {
731 return reader.getList(ElementSize::POINTER, defaultValue);
732 }
733
734 template <typename U, Kind k>
735 friend struct List;
736 template <typename U, Kind K>
737 friend struct _::PointerHelpers;
738};
739
740// =======================================================================================
741// Inline implementation details
742
743template <typename T>
744RemotePromise<T> RemotePromise<T>::reducePromise(kj::Promise<RemotePromise>&& promise) {
745 kj::Tuple<kj::Promise<Response<T>>, kj::Promise<kj::Own<PipelineHook>>> splitPromise =
746 promise.then([](RemotePromise&& inner) {
747 // `inner` is multiply-inherited, and we want to move away each superclass separately.
748 // Let's create two references to make clear what we're doing (though this is not strictly
749 // necessary).
750 kj::Promise<Response<T>>& innerPromise = inner;
751 typename T::Pipeline& innerPipeline = inner;
752 return kj::tuple(kj::mv(innerPromise), PipelineHook::from(kj::mv(innerPipeline)));
753 }).split();
754
755 return RemotePromise(kj::mv(kj::get<0>(splitPromise)),
756 typename T::Pipeline(AnyPointer::Pipeline(
757 newLocalPromisePipeline(kj::mv(kj::get<1>(splitPromise))))));
758}
759
760template <typename Params, typename Results>
761RemotePromise<Results> Request<Params, Results>::send() {
762 auto typelessPromise = hook->send();
763 hook = nullptr; // prevent reuse
764
765 // Convert the Promise to return the correct response type.
766 // Explicitly upcast to kj::Promise to make clear that calling .then() doesn't invalidate the
767 // Pipeline part of the RemotePromise.
768 auto typedPromise = kj::implicitCast<kj::Promise<Response<AnyPointer>>&>(typelessPromise)
769 .then([](Response<AnyPointer>&& response) -> Response<Results> {
770 return Response<Results>(response.getAs<Results>(), kj::mv(response.hook));
771 });
772
773 // Wrap the typeless pipeline in a typed wrapper.
774 typename Results::Pipeline typedPipeline(
775 kj::mv(kj::implicitCast<AnyPointer::Pipeline&>(typelessPromise)));
776
777 return RemotePromise<Results>(kj::mv(typedPromise), kj::mv(typedPipeline));
778}
779
780inline Capability::Client::Client(kj::Own<ClientHook>&& hook): hook(kj::mv(hook)) {}
781template <typename T, typename>
782inline Capability::Client::Client(kj::Own<T>&& server)
783 : hook(makeLocalClient(kj::mv(server))) {}
784template <typename T, typename>
785inline Capability::Client::Client(kj::Promise<T>&& promise)
786 : hook(newLocalPromiseClient(promise.then([](T&& t) { return kj::mv(t.hook); }))) {}
787inline Capability::Client::Client(Client& other): hook(other.hook->addRef()) {}
788inline Capability::Client& Capability::Client::operator=(Client& other) {
789 hook = other.hook->addRef();
790 return *this;
791}
792template <typename T>
793inline typename T::Client Capability::Client::castAs() {
794 return typename T::Client(hook->addRef());
795}
796inline kj::Promise<void> Capability::Client::whenResolved() {
797 return hook->whenResolved();
798}
799inline Request<AnyPointer, AnyPointer> Capability::Client::typelessRequest(
800 uint64_t interfaceId, uint16_t methodId,
801 kj::Maybe<MessageSize> sizeHint) {
802 return newCall<AnyPointer, AnyPointer>(interfaceId, methodId, sizeHint);
803}
804template <typename Params, typename Results>
805inline Request<Params, Results> Capability::Client::newCall(
806 uint64_t interfaceId, uint16_t methodId, kj::Maybe<MessageSize> sizeHint) {
807 auto typeless = hook->newCall(interfaceId, methodId, sizeHint);
808 return Request<Params, Results>(typeless.template getAs<Params>(), kj::mv(typeless.hook));
809}
810
811template <typename Params, typename Results>
812inline CallContext<Params, Results>::CallContext(CallContextHook& hook): hook(&hook) {}
813template <typename Params, typename Results>
814inline typename Params::Reader CallContext<Params, Results>::getParams() {
815 return hook->getParams().template getAs<Params>();
816}
817template <typename Params, typename Results>
818inline void CallContext<Params, Results>::releaseParams() {
819 hook->releaseParams();
820}
821template <typename Params, typename Results>
822inline typename Results::Builder CallContext<Params, Results>::getResults(
823 kj::Maybe<MessageSize> sizeHint) {
824 // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
825 return hook->getResults(sizeHint).template getAs<Results>();
826}
827template <typename Params, typename Results>
828inline typename Results::Builder CallContext<Params, Results>::initResults(
829 kj::Maybe<MessageSize> sizeHint) {
830 // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
831 return hook->getResults(sizeHint).template initAs<Results>();
832}
833template <typename Params, typename Results>
834inline void CallContext<Params, Results>::setResults(typename Results::Reader value) {
835 hook->getResults(value.totalSize()).template setAs<Results>(value);
836}
837template <typename Params, typename Results>
838inline void CallContext<Params, Results>::adoptResults(Orphan<Results>&& value) {
839 hook->getResults(nullptr).adopt(kj::mv(value));
840}
841template <typename Params, typename Results>
842inline Orphanage CallContext<Params, Results>::getResultsOrphanage(
843 kj::Maybe<MessageSize> sizeHint) {
844 return Orphanage::getForMessageContaining(hook->getResults(sizeHint));
845}
846template <typename Params, typename Results>
847template <typename SubParams>
848inline kj::Promise<void> CallContext<Params, Results>::tailCall(
849 Request<SubParams, Results>&& tailRequest) {
850 return hook->tailCall(kj::mv(tailRequest.hook));
851}
852template <typename Params, typename Results>
853inline void CallContext<Params, Results>::allowCancellation() {
854 hook->allowCancellation();
855}
856
857template <typename Params, typename Results>
858CallContext<Params, Results> Capability::Server::internalGetTypedContext(
859 CallContext<AnyPointer, AnyPointer> typeless) {
860 return CallContext<Params, Results>(*typeless.hook);
861}
862
863Capability::Client Capability::Server::thisCap() {
864 return Client(thisHook->addRef());
865}
866
867template <typename T>
868T ReaderCapabilityTable::imbue(T reader) {
869 return T(_::PointerHelpers<FromReader<T>>::getInternalReader(reader).imbue(this));
870}
871
872template <typename T>
873T BuilderCapabilityTable::imbue(T builder) {
874 return T(_::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::mv(builder)).imbue(this));
875}
876
877template <typename T>
878typename T::Client CapabilityServerSet<T>::add(kj::Own<typename T::Server>&& server) {
879 void* ptr = reinterpret_cast<void*>(server.get());
880 // Clang insists that `castAs` is a template-dependent member and therefore we need the
881 // `template` keyword here, but AFAICT this is wrong: addImpl() is not a template.
882 return addInternal(kj::mv(server), ptr).template castAs<T>();
883}
884
885template <typename T>
886kj::Promise<kj::Maybe<typename T::Server&>> CapabilityServerSet<T>::getLocalServer(
887 typename T::Client& client) {
888 return getLocalServerInternal(client)
889 .then([](void* server) -> kj::Maybe<typename T::Server&> {
890 if (server == nullptr) {
891 return nullptr;
892 } else {
893 return *reinterpret_cast<typename T::Server*>(server);
894 }
895 });
896}
897
898template <typename T>
899struct Orphanage::GetInnerReader<T, Kind::INTERFACE> {
900 static inline kj::Own<ClientHook> apply(typename T::Client t) {
901 return ClientHook::from(kj::mv(t));
902 }
903};
904
905#define CAPNP_CAPABILITY_H_INCLUDED // for testing includes in unit test
906
907} // namespace capnp
908