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