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