capability.h 29.1 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
21 22 23 24

#ifndef CAPNP_CAPABILITY_H_
#define CAPNP_CAPABILITY_H_

25 26 27 28
#if CAPNP_LITE
#error "RPC APIs, including this header, are not available in lite mode."
#endif

29
#include <kj/async.h>
30
#include "any.h"
31
#include "pointer-helpers.h"
32 33 34

namespace capnp {

35
template <typename Results>
36 37
class Response;

38
template <typename T>
39 40 41 42 43 44 45 46
class RemotePromise: public kj::Promise<Response<T>>, public T::Pipeline {
  // A Promise which supports pipelined calls.  T is typically a struct type.  T must declare
  // an inner "mix-in" type "Pipeline" which implements pipelining; RemotePromise simply
  // multiply-inherits that type along with Promise<Response<T>>.  T::Pipeline must be movable,
  // but does not need to be copyable (i.e. just like Promise<T>).
  //
  // The promise is for an owned pointer so that the RPC system can allocate the MessageReader
  // itself.
47 48

public:
49 50
  inline RemotePromise(kj::Promise<Response<T>>&& promise, typename T::Pipeline&& pipeline)
      : kj::Promise<Response<T>>(kj::mv(promise)),
51 52
        T::Pipeline(kj::mv(pipeline)) {}
  inline RemotePromise(decltype(nullptr))
53 54
      : kj::Promise<Response<T>>(nullptr),
        T::Pipeline(nullptr) {}
55 56 57 58 59
  KJ_DISALLOW_COPY(RemotePromise);
  RemotePromise(RemotePromise&& other) = default;
  RemotePromise& operator=(RemotePromise&& other) = default;
};

60 61
namespace _ { // private
struct RawSchema;
62
struct RawBrandedSchema;
63 64 65 66 67 68 69 70 71 72 73
extern const RawSchema NULL_INTERFACE_SCHEMA;  // defined in schema.c++
}  // namespace _ (private)

struct Capability {
  // A capability without type-safe methods.  Typed capability clients wrap `Client` and typed
  // capability servers subclass `Server` to dispatch to the regular, typed methods.

  class Client;
  class Server;

  struct _capnpPrivate {
74
    struct IsInterface;
75 76 77
    static constexpr uint64_t typeId = 0x3;
    static constexpr Kind kind = Kind::INTERFACE;
    static constexpr _::RawSchema const* schema = &_::NULL_INTERFACE_SCHEMA;
78 79 80 81 82 83

    static const _::RawBrandedSchema* const brand;
    // Can't quite declare this one inline without including generated-header-support.h. Avoiding
    // for now by declaring out-of-line.
    // TODO(cleanup): Split RawSchema stuff into its own header that can be included here, or
    //   something.
84 85 86
  };
};

87 88
// =======================================================================================

89 90 91 92
class RequestHook;
class ResponseHook;
class PipelineHook;
class ClientHook;
93

94
template <typename Params, typename Results>
95 96 97 98 99 100 101
class Request: public Params::Builder {
  // A call that hasn't been sent yet.  This class extends a Builder for the call's "Params"
  // structure with a method send() that actually sends it.
  //
  // Given a Cap'n Proto method `foo(a :A, b :B): C`, the generated client interface will have
  // a method `Request<FooParams, C> startFoo()` (as well as a convenience method
  // `RemotePromise<C> foo(A::Reader a, B::Reader b)`).
102 103

public:
104 105
  inline Request(typename Params::Builder builder, kj::Own<RequestHook>&& hook)
      : Params::Builder(builder), hook(kj::mv(hook)) {}
106

107 108
  RemotePromise<Results> send();
  // Send the call and return a promise for the results.
109

110 111
private:
  kj::Own<RequestHook> hook;
112 113

  friend class Capability::Client;
114
  friend struct DynamicCapability;
115 116
  template <typename, typename>
  friend class CallContext;
117
  friend class RequestHook;
118 119
};

120 121
template <typename Results>
class Response: public Results::Reader {
122 123 124 125
  // A completed call.  This class extends a Reader for the call's answer structure.  The Response
  // is move-only -- once it goes out-of-scope, the underlying message will be freed.

public:
126
  inline Response(typename Results::Reader reader, kj::Own<ResponseHook>&& hook)
127
      : Results::Reader(reader), hook(kj::mv(hook)) {}
128 129

private:
130
  kj::Own<ResponseHook> hook;
131 132 133 134 135 136 137 138 139

  template <typename, typename>
  friend class Request;
};

class Capability::Client {
  // Base type for capability clients.

public:
140
  Client(decltype(nullptr));
141 142 143 144
  // If you need to declare a Client before you have anything to assign to it (perhaps because
  // the assignment is going to occur in an if/else scope), you can start by initializing it to
  // `nullptr`.  The resulting client is not meant to be called and throws exceptions from all
  // methods.
145

146
  template <typename T, typename = kj::EnableIf<kj::canConvert<T*, Capability::Server*>()>>
147
  Client(kj::Own<T>&& server);
148 149 150
  // Make a client capability that wraps the given server capability.  The server's methods will
  // only be executed in the given EventLoop, regardless of what thread calls the client's methods.

151
  template <typename T, typename = kj::EnableIf<kj::canConvert<T*, Client*>()>>
152
  Client(kj::Promise<T>&& promise);
153 154 155 156 157 158
  // Make a client from a promise for a future client.  The resulting client queues calls until the
  // promise resolves.

  Client(kj::Exception&& exception);
  // Make a broken client that throws the given exception from all calls.

159 160 161 162
  Client(Client& other);
  Client& operator=(Client& other);
  // Copies by reference counting.  Warning:  This refcounting is not thread-safe.  All copies of
  // the client must remain in one thread.
163 164 165

  Client(Client&&) = default;
  Client& operator=(Client&&) = default;
166
  // Move constructor avoids reference counting.
167

168
  explicit Client(kj::Own<ClientHook>&& hook);
169 170
  // For use by the RPC implementation:  Wrap a ClientHook.

171
  template <typename T>
172
  typename T::Client castAs();
173 174 175 176 177 178 179 180
  // Reinterpret the capability as implementing the given interface.  Note that no error will occur
  // here if the capability does not actually implement this interface, but later method calls will
  // fail.  It's up to the application to decide how indicate that additional interfaces are
  // supported.
  //
  // TODO(kenton):  GCC 4.8 / Clang 3.3:  rvalue-qualified version for better performance.

  template <typename T>
181
  typename T::Client castAs(InterfaceSchema schema);
182 183
  // Dynamic version.  `T` must be `DynamicCapability`, and you must `#include <capnp/dynamic.h>`.

184
  kj::Promise<void> whenResolved();
185 186 187 188 189 190
  // If the capability is actually only a promise, the returned promise resolves once the
  // capability itself has resolved to its final destination (or propagates the exception if
  // the capability promise is rejected).  This is mainly useful for error-checking in the case
  // where no calls are being made.  There is no reason to wait for this before making calls; if
  // the capability does not resolve, the call results will propagate the error.

191 192 193 194 195 196
  Request<AnyPointer, AnyPointer> typelessRequest(
      uint64_t interfaceId, uint16_t methodId,
      kj::Maybe<MessageSize> sizeHint);
  // Make a request without knowing the types of the params or results. You specify the type ID
  // and method number manually.

197
  // TODO(someday):  method(s) for Join
198

199 200 201 202 203
protected:
  Client() = default;

  template <typename Params, typename Results>
  Request<Params, Results> newCall(uint64_t interfaceId, uint16_t methodId,
204
                                   kj::Maybe<MessageSize> sizeHint);
205

206
private:
207
  kj::Own<ClientHook> hook;
208

209
  static kj::Own<ClientHook> makeLocalClient(kj::Own<Capability::Server>&& server);
210

Kenton Varda's avatar
Kenton Varda committed
211 212
  template <typename, Kind>
  friend struct _::PointerHelpers;
213 214 215 216 217 218
  friend struct DynamicCapability;
  friend class Orphanage;
  friend struct DynamicStruct;
  friend struct DynamicList;
  template <typename, Kind>
  friend struct List;
219 220 221
};

// =======================================================================================
222 223 224 225
// Local capabilities

class CallContextHook;

226
template <typename Params, typename Results>
227
class CallContext: public kj::DisallowConstCopy {
228
  // Wrapper around CallContextHook with a specific return type.
229 230 231
  //
  // Methods of this class may only be called from within the server's event loop, not from other
  // threads.
Kenton Varda's avatar
Kenton Varda committed
232 233
  //
  // The CallContext becomes invalid as soon as the call reports completion.
234 235

public:
236 237 238 239 240 241 242 243 244 245 246
  explicit CallContext(CallContextHook& hook);

  typename Params::Reader getParams();
  // Get the params payload.

  void releaseParams();
  // Release the params payload.  getParams() will throw an exception after this is called.
  // Releasing the params may allow the RPC system to free up buffer space to handle other
  // requests.  Long-running asynchronous methods should try to call this as early as is
  // convenient.

247 248
  typename Results::Builder getResults(kj::Maybe<MessageSize> sizeHint = nullptr);
  typename Results::Builder initResults(kj::Maybe<MessageSize> sizeHint = nullptr);
249 250
  void setResults(typename Results::Reader value);
  void adoptResults(Orphan<Results>&& value);
251
  Orphanage getResultsOrphanage(kj::Maybe<MessageSize> sizeHint = nullptr);
252 253
  // Manipulate the results payload.  The "Return" message (part of the RPC protocol) will
  // typically be allocated the first time one of these is called.  Some RPC systems may
254 255 256
  // allocate these messages in a limited space (such as a shared memory segment), therefore the
  // application should delay calling these as long as is convenient to do so (but don't delay
  // if doing so would require extra copies later).
Kenton Varda's avatar
Kenton Varda committed
257
  //
258 259 260 261 262
  // `sizeHint` indicates a guess at the message size.  This will usually be used to decide how
  // much space to allocate for the first message segment (don't worry: only space that is actually
  // used will be sent on the wire).  If omitted, the system decides.  The message root pointer
  // should not be included in the size.  So, if you are simply going to copy some existing message
  // directly into the results, just call `.totalSize()` and pass that in.
263

264 265 266 267 268 269 270 271 272 273 274 275 276
  template <typename SubParams>
  kj::Promise<void> tailCall(Request<SubParams, Results>&& tailRequest);
  // Resolve the call by making a tail call.  `tailRequest` is a request that has been filled in
  // but not yet sent.  The context will send the call, then fill in the results with the result
  // of the call.  If tailCall() is used, {get,init,set,adopt}Results (above) *must not* be called.
  //
  // The RPC implementation may be able to optimize a tail call to another machine such that the
  // results never actually pass through this machine.  Even if no such optimization is possible,
  // `tailCall()` may allow pipelined calls to be forwarded optimistically to the new call site.
  //
  // In general, this should be the last thing a method implementation calls, and the promise
  // returned from `tailCall()` should then be returned by the method implementation.

277
  void allowCancellation();
278 279 280 281 282 283 284 285 286 287
  // Indicate that it is OK for the RPC system to discard its Promise for this call's result if
  // the caller cancels the call, thereby transitively canceling any asynchronous operations the
  // call implementation was performing.  This is not done by default because it could represent a
  // security risk:  applications must be carefully written to ensure that they do not end up in
  // a bad state if an operation is canceled at an arbitrary point.  However, for long-running
  // method calls that hold significant resources, prompt cancellation is often useful.
  //
  // Keep in mind that asynchronous cancellation cannot occur while the method is synchronously
  // executing on a local thread.  The method must perform an asynchronous operation or call
  // `EventLoop::current().runLater()` to yield control.
Kenton Varda's avatar
Kenton Varda committed
288
  //
289 290 291 292 293 294 295 296 297
  // Note:  You might think that we should offer `onCancel()` and/or `isCanceled()` methods that
  // provide notification when the caller cancels the request without forcefully killing off the
  // promise chain.  Unfortunately, this composes poorly with promise forking:  the canceled
  // path may be just one branch of a fork of the result promise.  The other branches still want
  // the call to continue.  Promise forking is used within the Cap'n Proto implementation -- in
  // particular each pipelined call forks the result promise.  So, if a caller made a pipelined
  // call and then dropped the original object, the call should not be canceled, but it would be
  // excessively complicated for the framework to avoid notififying of cancellation as long as
  // pipelined calls still exist.
298

299
private:
300 301 302
  CallContextHook* hook;

  friend class Capability::Server;
303
  friend struct DynamicCapability;
304 305
};

306 307 308 309
class Capability::Server {
  // Objects implementing a Cap'n Proto interface must subclass this.  Typically, such objects
  // will instead subclass a typed Server interface which will take care of implementing
  // dispatchCall().
310 311

public:
312
  virtual kj::Promise<void> dispatchCall(uint64_t interfaceId, uint16_t methodId,
313
                                         CallContext<AnyPointer, AnyPointer> context) = 0;
314 315 316 317
  // Call the given method.  `params` is the input struct, and should be released as soon as it
  // is no longer needed.  `context` may be used to allocate the output struct and deal with
  // cancellation.

318
  // TODO(someday):  Method which can optionally be overridden to implement Join when the object is
319
  //   a proxy.
320 321 322 323

protected:
  template <typename Params, typename Results>
  CallContext<Params, Results> internalGetTypedContext(
324
      CallContext<AnyPointer, AnyPointer> typeless);
325 326 327 328 329 330
  kj::Promise<void> internalUnimplemented(const char* actualInterfaceName,
                                          uint64_t requestedTypeId);
  kj::Promise<void> internalUnimplemented(const char* interfaceName,
                                          uint64_t typeId, uint16_t methodId);
  kj::Promise<void> internalUnimplemented(const char* interfaceName, const char* methodName,
                                          uint64_t typeId, uint16_t methodId);
331 332
};

333
// =======================================================================================
334 335
// Hook interfaces which must be implemented by the RPC system.  Applications never call these
// directly; the RPC system implements them and the types defined earlier in this file wrap them.
336

337 338
class RequestHook {
  // Hook interface implemented by RPC system representing a request being built.
339

340
public:
341
  virtual RemotePromise<AnyPointer> send() = 0;
342
  // Send the call and return a promise for the result.
343

344
  virtual const void* getBrand() = 0;
345 346 347
  // Returns a void* that identifies who made this request.  This can be used by an RPC adapter to
  // discover when tail call is going to be sent over its own connection and therefore can be
  // optimized into a remote tail call.
348 349 350 351 352

  template <typename T, typename U>
  inline static kj::Own<RequestHook> from(Request<T, U>&& request) {
    return kj::mv(request.hook);
  }
353 354
};

355 356 357 358
class ResponseHook {
  // Hook interface implemented by RPC system representing a response.
  //
  // At present this class has no methods.  It exists only for garbage collection -- when the
359
  // ResponseHook is destroyed, the results can be freed.
360 361

public:
Kenton Varda's avatar
Kenton Varda committed
362 363
  virtual ~ResponseHook() noexcept(false);
  // Just here to make sure the type is dynamic.
364 365
};

366
// class PipelineHook is declared in any.h because it is needed there.
367

368
class ClientHook {
369
public:
370 371
  ClientHook();

372
  virtual Request<AnyPointer, AnyPointer> newCall(
373
      uint64_t interfaceId, uint16_t methodId, kj::Maybe<MessageSize> sizeHint) = 0;
Kenton Varda's avatar
Kenton Varda committed
374 375
  // Start a new call, allowing the client to allocate request/response objects as it sees fit.
  // This version is used when calls are made from application code in the local process.
376

Kenton Varda's avatar
Kenton Varda committed
377 378
  struct VoidPromiseAndPipeline {
    kj::Promise<void> promise;
379
    kj::Own<PipelineHook> pipeline;
Kenton Varda's avatar
Kenton Varda committed
380 381 382
  };

  virtual VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId,
383
                                      kj::Own<CallContextHook>&& context) = 0;
Kenton Varda's avatar
Kenton Varda committed
384
  // Call the object, but the caller controls allocation of the request/response objects.  If the
385
  // callee insists on allocating these objects itself, it must make a copy.  This version is used
Kenton Varda's avatar
Kenton Varda committed
386
  // when calls come in over the network via an RPC system.  During the call, the context object
387 388 389 390
  // may be used from any thread so long as it is only used from one thread at a time.  Note that
  // even if the returned `Promise<void>` is discarded, the call may continue executing if any
  // pipelined calls are waiting for it; the call is only truly done when the CallContextHook is
  // destroyed.
Kenton Varda's avatar
Kenton Varda committed
391
  //
392 393
  // Since the caller of this method chooses the CallContext implementation, it is the caller's
  // responsibility to ensure that the returned promise is not canceled unless allowed via
394
  // the context's `allowCancellation()`.
395
  //
Kenton Varda's avatar
Kenton Varda committed
396 397
  // The call must not begin synchronously, as the caller may hold arbitrary mutexes.

398
  virtual kj::Maybe<ClientHook&> getResolved() = 0;
399 400 401 402 403
  // If this ClientHook is a promise that has already resolved, returns the inner, resolved version
  // of the capability.  The caller may permanently replace this client with the resolved one if
  // desired.  Returns null if the client isn't a promise or hasn't resolved yet -- use
  // `whenMoreResolved()` to distinguish between them.

404
  virtual kj::Maybe<kj::Promise<kj::Own<ClientHook>>> whenMoreResolved() = 0;
Kenton Varda's avatar
Kenton Varda committed
405 406
  // If this client is a settled reference (not a promise), return nullptr.  Otherwise, return a
  // promise that eventually resolves to a new client that is closer to being the final, settled
407 408
  // client (i.e. the value eventually returned by `getResolved()`).  Calling this repeatedly
  // should eventually produce a settled client.
Kenton Varda's avatar
Kenton Varda committed
409

410
  kj::Promise<void> whenResolved();
411 412
  // Repeatedly calls whenMoreResolved() until it returns nullptr.

413
  virtual kj::Own<ClientHook> addRef() = 0;
414
  // Return a new reference to the same capability.
415

416
  virtual const void* getBrand() = 0;
417 418 419
  // Returns a void* that identifies who made this client.  This can be used by an RPC adapter to
  // discover when a capability it needs to marshal is one that it created in the first place, and
  // therefore it can transfer the capability without proxying.
420 421
};

422 423 424
class CallContextHook {
  // Hook interface implemented by RPC system to manage a call on the server side.  See
  // CallContext<T>.
425 426

public:
427
  virtual AnyPointer::Reader getParams() = 0;
428
  virtual void releaseParams() = 0;
429
  virtual AnyPointer::Builder getResults(kj::Maybe<MessageSize> sizeHint) = 0;
430
  virtual kj::Promise<void> tailCall(kj::Own<RequestHook>&& request) = 0;
431
  virtual void allowCancellation() = 0;
432

433
  virtual kj::Promise<AnyPointer::Pipeline> onTailCall() = 0;
434 435 436
  // If `tailCall()` is called, resolves to the PipelineHook from the tail call.  An
  // implementation of `ClientHook::call()` is allowed to call this at most once.

437 438 439 440 441
  virtual ClientHook::VoidPromiseAndPipeline directTailCall(kj::Own<RequestHook>&& request) = 0;
  // Call this when you would otherwise call onTailCall() immediately followed by tailCall().
  // Implementations of tailCall() should typically call directTailCall() and then fulfill the
  // promise fulfiller for onTailCall() with the returned pipeline.

442
  virtual kj::Own<CallContextHook> addRef() = 0;
443
};
444

445
kj::Own<ClientHook> newLocalPromiseClient(kj::Promise<kj::Own<ClientHook>>&& promise);
Kenton Varda's avatar
Kenton Varda committed
446 447 448 449
// Returns a ClientHook that queues up calls until `promise` resolves, then forwards them to
// the new client.  This hook's `getResolved()` and `whenMoreResolved()` methods will reflect the
// redirection to the eventual replacement client.

450 451 452 453 454 455 456
kj::Own<ClientHook> newBrokenCap(kj::StringPtr reason);
kj::Own<ClientHook> newBrokenCap(kj::Exception&& reason);
// Helper function that creates a capability which simply throws exceptions when called.

kj::Own<PipelineHook> newBrokenPipeline(kj::Exception&& reason);
// Helper function that creates a pipeline which simply throws exceptions when called.

457 458 459 460
Request<AnyPointer, AnyPointer> newBrokenRequest(
    kj::Exception&& reason, kj::Maybe<MessageSize> sizeHint);
// Helper function that creates a Request object that simply throws exceptions when sent.

461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
// =======================================================================================
// Extend PointerHelpers for interfaces

namespace _ {  // private

template <typename T>
struct PointerHelpers<T, Kind::INTERFACE> {
  static inline typename T::Client get(PointerReader reader) {
    return typename T::Client(reader.getCapability());
  }
  static inline typename T::Client get(PointerBuilder builder) {
    return typename T::Client(builder.getCapability());
  }
  static inline void set(PointerBuilder builder, typename T::Client&& value) {
    builder.setCapability(kj::mv(value.Capability::Client::hook));
  }
477
  static inline void set(PointerBuilder builder, typename T::Client& value) {
478 479
    builder.setCapability(value.Capability::Client::hook->addRef());
  }
480 481 482 483 484 485 486 487 488 489
  static inline void adopt(PointerBuilder builder, Orphan<T>&& value) {
    builder.adopt(kj::mv(value.builder));
  }
  static inline Orphan<T> disown(PointerBuilder builder) {
    return Orphan<T>(builder.disown());
  }
};

}  // namespace _ (private)

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
// =======================================================================================
// Extend List for interfaces

template <typename T>
struct List<T, Kind::INTERFACE> {
  List() = delete;

  class Reader {
  public:
    typedef List<T> Reads;

    Reader() = default;
    inline explicit Reader(_::ListReader reader): reader(reader) {}

    inline uint size() const { return reader.size() / ELEMENTS; }
    inline typename T::Client operator[](uint index) const {
      KJ_IREQUIRE(index < size());
      return typename T::Client(reader.getPointerElement(index * ELEMENTS).getCapability());
    }

    typedef _::IndexingIterator<const Reader, typename T::Client> Iterator;
    inline Iterator begin() const { return Iterator(this, 0); }
    inline Iterator end() const { return Iterator(this, size()); }

  private:
    _::ListReader reader;
    template <typename U, Kind K>
    friend struct _::PointerHelpers;
    template <typename U, Kind K>
    friend struct List;
    friend class Orphanage;
    template <typename U, Kind K>
    friend struct ToDynamic_;
  };

  class Builder {
  public:
    typedef List<T> Builds;

    Builder() = delete;
    inline Builder(decltype(nullptr)) {}
    inline explicit Builder(_::ListBuilder builder): builder(builder) {}

    inline operator Reader() { return Reader(builder.asReader()); }
    inline Reader asReader() { return Reader(builder.asReader()); }

    inline uint size() const { return builder.size() / ELEMENTS; }
    inline typename T::Client operator[](uint index) {
      KJ_IREQUIRE(index < size());
      return typename T::Client(builder.getPointerElement(index * ELEMENTS).getCapability());
    }
    inline void set(uint index, typename T::Client value) {
      KJ_IREQUIRE(index < size());
      builder.getPointerElement(index * ELEMENTS).setCapability(kj::mv(value.hook));
    }
    inline void adopt(uint index, Orphan<T>&& value) {
      KJ_IREQUIRE(index < size());
      builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(value));
    }
    inline Orphan<T> disown(uint index) {
      KJ_IREQUIRE(index < size());
      return Orphan<T>(builder.getPointerElement(index * ELEMENTS).disown());
    }

    typedef _::IndexingIterator<Builder, typename T::Client> Iterator;
    inline Iterator begin() { return Iterator(this, 0); }
    inline Iterator end() { return Iterator(this, size()); }

  private:
    _::ListBuilder builder;
    friend class Orphanage;
    template <typename U, Kind K>
    friend struct ToDynamic_;
  };

private:
  inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) {
    return builder.initList(_::FieldSize::POINTER, size * ELEMENTS);
  }
  inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) {
    return builder.getList(_::FieldSize::POINTER, defaultValue);
  }
  inline static _::ListReader getFromPointer(
      const _::PointerReader& reader, const word* defaultValue) {
    return reader.getList(_::FieldSize::POINTER, defaultValue);
  }

  template <typename U, Kind k>
  friend struct List;
  template <typename U, Kind K>
  friend struct _::PointerHelpers;
};

583 584 585
// =======================================================================================
// Inline implementation details

586 587
template <typename Params, typename Results>
RemotePromise<Results> Request<Params, Results>::send() {
588 589 590 591 592
  auto typelessPromise = hook->send();

  // Convert the Promise to return the correct response type.
  // Explicitly upcast to kj::Promise to make clear that calling .then() doesn't invalidate the
  // Pipeline part of the RemotePromise.
593 594
  auto typedPromise = kj::implicitCast<kj::Promise<Response<AnyPointer>>&>(typelessPromise)
      .then([](Response<AnyPointer>&& response) -> Response<Results> {
595
        return Response<Results>(response.getAs<Results>(), kj::mv(response.hook));
596 597 598
      });

  // Wrap the typeless pipeline in a typed wrapper.
599
  typename Results::Pipeline typedPipeline(
600
      kj::mv(kj::implicitCast<AnyPointer::Pipeline&>(typelessPromise)));
601

602
  return RemotePromise<Results>(kj::mv(typedPromise), kj::mv(typedPipeline));
603 604
}

605
inline Capability::Client::Client(kj::Own<ClientHook>&& hook): hook(kj::mv(hook)) {}
606
template <typename T, typename>
607 608
inline Capability::Client::Client(kj::Own<T>&& server)
    : hook(makeLocalClient(kj::mv(server))) {}
609
template <typename T, typename>
610 611 612 613
inline Capability::Client::Client(kj::Promise<T>&& promise)
    : hook(newLocalPromiseClient(promise.then([](T&& t) { return kj::mv(t.hook); }))) {}
inline Capability::Client::Client(Client& other): hook(other.hook->addRef()) {}
inline Capability::Client& Capability::Client::operator=(Client& other) {
614 615 616
  hook = other.hook->addRef();
  return *this;
}
617
template <typename T>
618
inline typename T::Client Capability::Client::castAs() {
619 620
  return typename T::Client(hook->addRef());
}
621
inline kj::Promise<void> Capability::Client::whenResolved() {
622 623
  return hook->whenResolved();
}
624 625 626 627 628
inline Request<AnyPointer, AnyPointer> Capability::Client::typelessRequest(
    uint64_t interfaceId, uint16_t methodId,
    kj::Maybe<MessageSize> sizeHint) {
  return newCall<AnyPointer, AnyPointer>(interfaceId, methodId, sizeHint);
}
629 630
template <typename Params, typename Results>
inline Request<Params, Results> Capability::Client::newCall(
631 632
    uint64_t interfaceId, uint16_t methodId, kj::Maybe<MessageSize> sizeHint) {
  auto typeless = hook->newCall(interfaceId, methodId, sizeHint);
633 634
  return Request<Params, Results>(typeless.template getAs<Params>(), kj::mv(typeless.hook));
}
635

636 637 638 639 640 641 642 643 644 645 646
template <typename Params, typename Results>
inline CallContext<Params, Results>::CallContext(CallContextHook& hook): hook(&hook) {}
template <typename Params, typename Results>
inline typename Params::Reader CallContext<Params, Results>::getParams() {
  return hook->getParams().template getAs<Params>();
}
template <typename Params, typename Results>
inline void CallContext<Params, Results>::releaseParams() {
  hook->releaseParams();
}
template <typename Params, typename Results>
Kenton Varda's avatar
Kenton Varda committed
647
inline typename Results::Builder CallContext<Params, Results>::getResults(
648
    kj::Maybe<MessageSize> sizeHint) {
649
  // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
650
  return hook->getResults(sizeHint).template getAs<Results>();
651
}
652
template <typename Params, typename Results>
Kenton Varda's avatar
Kenton Varda committed
653
inline typename Results::Builder CallContext<Params, Results>::initResults(
654
    kj::Maybe<MessageSize> sizeHint) {
655
  // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401
656
  return hook->getResults(sizeHint).template initAs<Results>();
657
}
658 659
template <typename Params, typename Results>
inline void CallContext<Params, Results>::setResults(typename Results::Reader value) {
660
  hook->getResults(value.totalSize()).template setAs<Results>(value);
661
}
662 663
template <typename Params, typename Results>
inline void CallContext<Params, Results>::adoptResults(Orphan<Results>&& value) {
664
  hook->getResults(nullptr).adopt(kj::mv(value));
665
}
666
template <typename Params, typename Results>
667 668 669
inline Orphanage CallContext<Params, Results>::getResultsOrphanage(
    kj::Maybe<MessageSize> sizeHint) {
  return Orphanage::getForMessageContaining(hook->getResults(sizeHint));
670
}
671
template <typename Params, typename Results>
672 673 674 675 676 677
template <typename SubParams>
inline kj::Promise<void> CallContext<Params, Results>::tailCall(
    Request<SubParams, Results>&& tailRequest) {
  return hook->tailCall(kj::mv(tailRequest.hook));
}
template <typename Params, typename Results>
678 679
inline void CallContext<Params, Results>::allowCancellation() {
  hook->allowCancellation();
680
}
681

682 683
template <typename Params, typename Results>
CallContext<Params, Results> Capability::Server::internalGetTypedContext(
684
    CallContext<AnyPointer, AnyPointer> typeless) {
685 686 687
  return CallContext<Params, Results>(*typeless.hook);
}

688 689 690
}  // namespace capnp

#endif  // CAPNP_CAPABILITY_H_