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