annotate osx/include/capnp/capability.h @ 83:ae30d91d2ffe

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