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_ |
