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