any.h 34.5 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
#pragma once
23

24
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
25 26 27
#pragma GCC system_header
#endif

28 29
#include "layout.h"
#include "pointer-helpers.h"
30
#include "orphan.h"
31
#include "list.h"
32 33 34 35 36

namespace capnp {

class StructSchema;
class ListSchema;
37
class InterfaceSchema;
38
class Orphanage;
Kenton Varda's avatar
Kenton Varda committed
39
class ClientHook;
40
class PipelineHook;
41
struct PipelineOp;
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
struct AnyPointer;

struct AnyList {
  AnyList() = delete;

  class Reader;
  class Builder;
};

struct AnyStruct {
  AnyStruct() = delete;

  class Reader;
  class Builder;
  class Pipeline;
};

template<>
struct List<AnyStruct, Kind::OTHER> {
  List() = delete;

  class Reader;
  class Builder;
};

namespace _ {  // private
template <> struct Kind_<AnyPointer> { static constexpr Kind kind = Kind::OTHER; };
template <> struct Kind_<AnyStruct> { static constexpr Kind kind = Kind::OTHER; };
template <> struct Kind_<AnyList> { static constexpr Kind kind = Kind::OTHER; };
}  // namespace _ (private)
72 73

// =======================================================================================
74
// AnyPointer!
75

76
enum class Equality {
77 78 79 80 81
  NOT_EQUAL,
  EQUAL,
  UNKNOWN_CONTAINS_CAPS
};

82
kj::StringPtr KJ_STRINGIFY(Equality res);
83

84 85
struct AnyPointer {
  // Reader/Builder for the `AnyPointer` field type, i.e. a pointer that can point to an arbitrary
86 87
  // object.

88 89
  AnyPointer() = delete;

90 91
  class Reader {
  public:
92
    typedef AnyPointer Reads;
93

94 95 96
    Reader() = default;
    inline Reader(_::PointerReader reader): reader(reader) {}

97 98
    inline MessageSize targetSize() const;
    // Get the total size of the target object and all its children.
Kenton Varda's avatar
Kenton Varda committed
99

100 101 102 103 104 105
    inline PointerType getPointerType() const;

    inline bool isNull() const { return getPointerType() == PointerType::NULL_; }
    inline bool isStruct() const { return getPointerType() == PointerType::STRUCT; }
    inline bool isList() const { return getPointerType() == PointerType::LIST; }
    inline bool isCapability() const { return getPointerType() == PointerType::CAPABILITY; }
106

107
    Equality equals(AnyPointer::Reader right);
108 109
    bool operator==(AnyPointer::Reader right);
    inline bool operator!=(AnyPointer::Reader right) {
110
      return !(*this == right);
111
    }
112 113

    template <typename T>
114 115
    inline ReaderFor<T> getAs() const;
    // Valid for T = any generated struct type, interface type, List<U>, Text, or Data.
116 117

    template <typename T>
118
    inline ReaderFor<T> getAs(StructSchema schema) const;
119 120 121
    // Only valid for T = DynamicStruct.  Requires `#include <capnp/dynamic.h>`.

    template <typename T>
122
    inline ReaderFor<T> getAs(ListSchema schema) const;
123 124
    // Only valid for T = DynamicList.  Requires `#include <capnp/dynamic.h>`.

125 126 127 128
    template <typename T>
    inline ReaderFor<T> getAs(InterfaceSchema schema) const;
    // Only valid for T = DynamicCapability.  Requires `#include <capnp/dynamic.h>`.

129
#if !CAPNP_LITE
130
    kj::Own<ClientHook> getPipelinedCap(kj::ArrayPtr<const PipelineOp> ops) const;
Kenton Varda's avatar
Kenton Varda committed
131 132
    // Used by RPC system to implement pipelining.  Applications generally shouldn't use this
    // directly.
133
#endif  // !CAPNP_LITE
Kenton Varda's avatar
Kenton Varda committed
134

135 136
  private:
    _::PointerReader reader;
137
    friend struct AnyPointer;
138
    friend class Orphanage;
139
    friend class CapReaderContext;
140
    friend struct _::PointerHelpers<AnyPointer>;
141 142 143 144
  };

  class Builder {
  public:
145
    typedef AnyPointer Builds;
146

147 148 149 150
    Builder() = delete;
    inline Builder(decltype(nullptr)) {}
    inline Builder(_::PointerBuilder builder): builder(builder) {}

151 152
    inline MessageSize targetSize() const;
    // Get the total size of the target object and all its children.
Kenton Varda's avatar
Kenton Varda committed
153

154 155 156 157 158 159
    inline PointerType getPointerType();

    inline bool isNull() { return getPointerType() == PointerType::NULL_; }
    inline bool isStruct() { return getPointerType() == PointerType::STRUCT; }
    inline bool isList() { return getPointerType() == PointerType::LIST; }
    inline bool isCapability() { return getPointerType() == PointerType::CAPABILITY; }
160

161
    inline Equality equals(AnyPointer::Reader right) {
162 163
      return asReader().equals(right);
    }
164
    inline bool operator==(AnyPointer::Reader right) {
165
      return asReader() == right;
166
    }
167
    inline bool operator!=(AnyPointer::Reader right) {
168
      return !(*this == right);
169
    }
170 171 172 173 174

    inline void clear();
    // Set to null.

    template <typename T>
175
    inline BuilderFor<T> getAs();
176 177 178
    // Valid for T = any generated struct type, List<U>, Text, or Data.

    template <typename T>
179
    inline BuilderFor<T> getAs(StructSchema schema);
180 181 182
    // Only valid for T = DynamicStruct.  Requires `#include <capnp/dynamic.h>`.

    template <typename T>
183
    inline BuilderFor<T> getAs(ListSchema schema);
184 185 186
    // Only valid for T = DynamicList.  Requires `#include <capnp/dynamic.h>`.

    template <typename T>
187 188 189 190 191
    inline BuilderFor<T> getAs(InterfaceSchema schema);
    // Only valid for T = DynamicCapability.  Requires `#include <capnp/dynamic.h>`.

    template <typename T>
    inline BuilderFor<T> initAs();
192 193 194
    // Valid for T = any generated struct type.

    template <typename T>
195
    inline BuilderFor<T> initAs(uint elementCount);
196 197 198
    // Valid for T = List<U>, Text, or Data.

    template <typename T>
199
    inline BuilderFor<T> initAs(StructSchema schema);
200 201 202
    // Only valid for T = DynamicStruct.  Requires `#include <capnp/dynamic.h>`.

    template <typename T>
203
    inline BuilderFor<T> initAs(ListSchema schema, uint elementCount);
204 205
    // Only valid for T = DynamicList.  Requires `#include <capnp/dynamic.h>`.

206
    inline AnyList::Builder initAsAnyList(ElementSize elementSize, uint elementCount);
207 208
    // Note: Does not accept INLINE_COMPOSITE for elementSize.

209
    inline List<AnyStruct>::Builder initAsListOfAnyStruct(
210
        uint16_t dataWordCount, uint16_t pointerCount, uint elementCount);
211

212
    inline AnyStruct::Builder initAsAnyStruct(uint16_t dataWordCount, uint16_t pointerCount);
213

214
    template <typename T>
215
    inline void setAs(ReaderFor<T> value);
216 217 218 219 220 221 222
    // Valid for ReaderType = T::Reader for T = any generated struct type, List<U>, Text, Data,
    // DynamicStruct, or DynamicList (the dynamic types require `#include <capnp/dynamic.h>`).

    template <typename T>
    inline void setAs(std::initializer_list<ReaderFor<ListElementType<T>>> list);
    // Valid for T = List<?>.

Matthew Maurer's avatar
Matthew Maurer committed
223 224 225
    template <typename T>
    inline void setCanonicalAs(ReaderFor<T> value);

226
    inline void set(Reader value) { builder.copyFrom(value.reader); }
227
    // Set to a copy of another AnyPointer.
228

Matthew Maurer's avatar
Matthew Maurer committed
229 230
    inline void setCanonical(Reader value) { builder.copyFrom(value.reader, true); }

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    template <typename T>
    inline void adopt(Orphan<T>&& orphan);
    // Valid for T = any generated struct type, List<U>, Text, Data, DynamicList, DynamicStruct,
    // or DynamicValue (the dynamic types require `#include <capnp/dynamic.h>`).

    template <typename T>
    inline Orphan<T> disownAs();
    // Valid for T = any generated struct type, List<U>, Text, Data.

    template <typename T>
    inline Orphan<T> disownAs(StructSchema schema);
    // Only valid for T = DynamicStruct.  Requires `#include <capnp/dynamic.h>`.

    template <typename T>
    inline Orphan<T> disownAs(ListSchema schema);
    // Only valid for T = DynamicList.  Requires `#include <capnp/dynamic.h>`.

248 249 250 251
    template <typename T>
    inline Orphan<T> disownAs(InterfaceSchema schema);
    // Only valid for T = DynamicCapability.  Requires `#include <capnp/dynamic.h>`.

252
    inline Orphan<AnyPointer> disown();
253 254 255 256 257
    // Disown without a type.

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

258 259
  private:
    _::PointerBuilder builder;
260
    friend class Orphanage;
261
    friend class CapBuilderContext;
262
    friend struct _::PointerHelpers<AnyPointer>;
263
  };
264

265
#if !CAPNP_LITE
266 267
  class Pipeline {
  public:
268 269
    typedef AnyPointer Pipelines;

270
    inline Pipeline(decltype(nullptr)) {}
271
    inline explicit Pipeline(kj::Own<PipelineHook>&& hook): hook(kj::mv(hook)) {}
272

273
    Pipeline noop();
274 275
    // Just make a copy.

276
    Pipeline getPointerField(uint16_t pointerIndex);
277 278 279
    // Deprecated. In the future, we should use .asAnyStruct.getPointerField.

    inline AnyStruct::Pipeline asAnyStruct();
280

281
    kj::Own<ClientHook> asCap();
282 283
    // Expect that the result is a capability and construct a pipelined version of it now.

284
    inline kj::Own<PipelineHook> releasePipelineHook() { return kj::mv(hook); }
Kenton Varda's avatar
Kenton Varda committed
285 286
    // For use by RPC implementations.

287 288 289
    template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromClient<T>) == Kind::INTERFACE>>
    inline operator T() { return T(asCap()); }

290
  private:
291
    kj::Own<PipelineHook> hook;
292 293
    kj::Array<PipelineOp> ops;

294
    inline Pipeline(kj::Own<PipelineHook>&& hook, kj::Array<PipelineOp>&& ops)
295
        : hook(kj::mv(hook)), ops(kj::mv(ops)) {}
296 297

    friend class LocalClient;
298
    friend class PipelineHook;
299
    friend class AnyStruct::Pipeline;
300
  };
301
#endif  // !CAPNP_LITE
302 303
};

304
template <>
305
class Orphan<AnyPointer> {
306 307 308 309 310 311
  // An orphaned object of unknown type.

public:
  Orphan() = default;
  KJ_DISALLOW_COPY(Orphan);
  Orphan(Orphan&&) = default;
312 313 314
  inline Orphan(_::OrphanBuilder&& builder)
      : builder(kj::mv(builder)) {}

315 316
  Orphan& operator=(Orphan&&) = default;

317 318 319
  template <typename T>
  inline Orphan(Orphan<T>&& other): builder(kj::mv(other.builder)) {}
  template <typename T>
320
  inline Orphan& operator=(Orphan<T>&& other) { builder = kj::mv(other.builder); return *this; }
321 322
  // Cast from typed orphan.

323
  // It's not possible to get an AnyPointer::{Reader,Builder} directly since there is no
324
  // underlying pointer (the pointer would normally live in the parent, but this object is
325
  // orphaned).  It is possible, however, to request typed readers/builders.
326 327

  template <typename T>
328
  inline BuilderFor<T> getAs();
329
  template <typename T>
330
  inline BuilderFor<T> getAs(StructSchema schema);
331
  template <typename T>
332
  inline BuilderFor<T> getAs(ListSchema schema);
333
  template <typename T>
334
  inline typename T::Client getAs(InterfaceSchema schema);
335
  template <typename T>
336
  inline ReaderFor<T> getAsReader() const;
337
  template <typename T>
338 339 340 341 342
  inline ReaderFor<T> getAsReader(StructSchema schema) const;
  template <typename T>
  inline ReaderFor<T> getAsReader(ListSchema schema) const;
  template <typename T>
  inline typename T::Client getAsReader(InterfaceSchema schema) const;
343 344 345 346 347 348 349

  template <typename T>
  inline Orphan<T> releaseAs();
  template <typename T>
  inline Orphan<T> releaseAs(StructSchema schema);
  template <typename T>
  inline Orphan<T> releaseAs(ListSchema schema);
350 351
  template <typename T>
  inline Orphan<T> releaseAs(InterfaceSchema schema);
352 353 354 355 356 357 358 359 360 361 362 363 364
  // Down-cast the orphan to a specific type.

  inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
  inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }

private:
  _::OrphanBuilder builder;

  template <typename, Kind>
  friend struct _::PointerHelpers;
  friend class Orphanage;
  template <typename U>
  friend class Orphan;
365
  friend class AnyPointer::Builder;
366 367
};

368 369 370 371 372
template <Kind k> struct AnyTypeFor_;
template <> struct AnyTypeFor_<Kind::STRUCT> { typedef AnyStruct Type; };
template <> struct AnyTypeFor_<Kind::LIST> { typedef AnyList Type; };

template <typename T>
Kenton Varda's avatar
Kenton Varda committed
373
using AnyTypeFor = typename AnyTypeFor_<CAPNP_KIND(T)>::Type;
374 375 376

template <typename T>
inline ReaderFor<AnyTypeFor<FromReader<T>>> toAny(T&& value) {
377
  return ReaderFor<AnyTypeFor<FromReader<T>>>(
378 379 380 381
      _::PointerHelpers<FromReader<T>>::getInternalReader(value));
}
template <typename T>
inline BuilderFor<AnyTypeFor<FromBuilder<T>>> toAny(T&& value) {
382
  return BuilderFor<AnyTypeFor<FromBuilder<T>>>(
383 384 385 386 387
      _::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::mv(value)));
}

template <>
struct List<AnyPointer, Kind::OTHER> {
388 389 390
  // Note: This cannot be used for a list of structs, since such lists are not encoded as pointer
  //   lists! Use List<AnyStruct>.

391 392 393 394 395 396
  List() = delete;

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

397
    inline Reader(): reader(ElementSize::POINTER) {}
398 399
    inline explicit Reader(_::ListReader reader): reader(reader) {}

400
    inline uint size() const { return unbound(reader.size() / ELEMENTS); }
401
    inline AnyPointer::Reader operator[](uint index) const {
402
      KJ_IREQUIRE(index < size());
403
      return AnyPointer::Reader(reader.getPointerElement(bounded(index) * ELEMENTS));
404 405 406 407 408 409
    }

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

410 411 412 413
    inline MessageSize totalSize() const {
      return reader.totalSize().asPublic();
    }

414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
  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<AnyPointer> Builds;

    Builder() = delete;
430
    inline Builder(decltype(nullptr)): builder(ElementSize::POINTER) {}
431 432
    inline explicit Builder(_::ListBuilder builder): builder(builder) {}

433 434
    inline operator Reader() const { return Reader(builder.asReader()); }
    inline Reader asReader() const { return Reader(builder.asReader()); }
435

436
    inline uint size() const { return unbound(builder.size() / ELEMENTS); }
437
    inline AnyPointer::Builder operator[](uint index) {
438
      KJ_IREQUIRE(index < size());
439
      return AnyPointer::Builder(builder.getPointerElement(bounded(index) * ELEMENTS));
440 441 442 443 444 445 446 447
    }

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

  private:
    _::ListBuilder builder;
448
    template <typename, Kind>
449 450
    friend struct _::PointerHelpers;
    friend class Orphanage;
451
    template <typename, Kind>
452 453 454 455 456 457
    friend struct ToDynamic_;
  };
};

class AnyStruct::Reader {
public:
Kenton Varda's avatar
Kenton Varda committed
458 459
  typedef AnyStruct Reads;

460 461 462
  Reader() = default;
  inline Reader(_::StructReader reader): _reader(reader) {}

Kenton Varda's avatar
Kenton Varda committed
463
  template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromReader<T>) == Kind::STRUCT>>
464 465 466
  inline Reader(T&& value)
      : _reader(_::PointerHelpers<FromReader<T>>::getInternalReader(kj::fwd<T>(value))) {}

467 468
  inline MessageSize totalSize() const { return _reader.totalSize().asPublic(); }

469
  kj::ArrayPtr<const byte> getDataSection() {
470 471 472 473 474 475
    return _reader.getDataSectionAsBlob();
  }
  List<AnyPointer>::Reader getPointerSection() {
    return List<AnyPointer>::Reader(_reader.getPointerSectionAsList());
  }

476 477 478 479
  kj::Array<word> canonicalize() {
    return _reader.canonicalize();
  }

480
  Equality equals(AnyStruct::Reader right);
481 482
  bool operator==(AnyStruct::Reader right);
  inline bool operator!=(AnyStruct::Reader right) {
483 484 485
    return !(*this == right);
  }

486
  template <typename T>
487
  ReaderFor<T> as() const {
488
    // T must be a struct type.
489 490
    return typename T::Reader(_reader);
  }
491 492 493 494 495

  template <typename T>
  ReaderFor<T> as(StructSchema schema) const;
  // T must be DynamicStruct. Defined in dynamic.h.

496 497
private:
  _::StructReader _reader;
498 499 500

  template <typename, Kind>
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
501
  friend class Orphanage;
502 503 504 505
};

class AnyStruct::Builder {
public:
Kenton Varda's avatar
Kenton Varda committed
506 507
  typedef AnyStruct Builds;

508 509 510
  inline Builder(decltype(nullptr)) {}
  inline Builder(_::StructBuilder builder): _builder(builder) {}

511
#if !_MSC_VER  // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves.
Kenton Varda's avatar
Kenton Varda committed
512
  template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromBuilder<T>) == Kind::STRUCT>>
513 514
  inline Builder(T&& value)
      : _builder(_::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::fwd<T>(value))) {}
515
#endif
516

517
  inline kj::ArrayPtr<byte> getDataSection() {
518 519 520 521 522 523
    return _builder.getDataSectionAsBlob();
  }
  List<AnyPointer>::Builder getPointerSection() {
    return List<AnyPointer>::Builder(_builder.getPointerSectionAsList());
  }

524
  inline Equality equals(AnyStruct::Reader right) {
525 526
    return asReader().equals(right);
  }
527
  inline bool operator==(AnyStruct::Reader right) {
528 529
    return asReader() == right;
  }
530
  inline bool operator!=(AnyStruct::Reader right) {
531 532 533
    return !(*this == right);
  }

534 535
  inline operator Reader() const { return Reader(_builder.asReader()); }
  inline Reader asReader() const { return Reader(_builder.asReader()); }
536 537 538

  template <typename T>
  BuilderFor<T> as() {
539
    // T must be a struct type.
540 541
    return typename T::Builder(_builder);
  }
542 543 544 545 546

  template <typename T>
  BuilderFor<T> as(StructSchema schema);
  // T must be DynamicStruct. Defined in dynamic.h.

547 548 549 550 551 552
private:
  _::StructBuilder _builder;
  friend class Orphanage;
  friend class CapBuilderContext;
};

Kenton Varda's avatar
Kenton Varda committed
553
#if !CAPNP_LITE
554 555
class AnyStruct::Pipeline {
public:
556 557 558 559 560 561 562 563 564 565 566 567
  inline Pipeline(decltype(nullptr)): typeless(nullptr) {}
  inline explicit Pipeline(AnyPointer::Pipeline&& typeless)
      : typeless(kj::mv(typeless)) {}

  inline AnyPointer::Pipeline getPointerField(uint16_t pointerIndex) {
    // Return a new Promise representing a sub-object of the result.  `pointerIndex` is the index
    // of the sub-object within the pointer section of the result (the result must be a struct).
    //
    // TODO(perf):  On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies.
    //   Also make `ops` into a Vector to optimize this.
    return typeless.getPointerField(pointerIndex);
  }
568 569

private:
570
  AnyPointer::Pipeline typeless;
571
};
Kenton Varda's avatar
Kenton Varda committed
572
#endif  // !CAPNP_LITE
573 574 575 576 577

class List<AnyStruct, Kind::OTHER>::Reader {
public:
  typedef List<AnyStruct> Reads;

578
  inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {}
579 580
  inline explicit Reader(_::ListReader reader): reader(reader) {}

581
  inline uint size() const { return unbound(reader.size() / ELEMENTS); }
582
  inline AnyStruct::Reader operator[](uint index) const {
583
    KJ_IREQUIRE(index < size());
584
    return AnyStruct::Reader(reader.getStructElement(bounded(index) * ELEMENTS));
585 586 587 588 589 590
  }

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

591 592 593 594
  inline MessageSize totalSize() const {
    return reader.totalSize().asPublic();
  }

595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
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 List<AnyStruct, Kind::OTHER>::Builder {
public:
  typedef List<AnyStruct> Builds;

  Builder() = delete;
611
  inline Builder(decltype(nullptr)): builder(ElementSize::INLINE_COMPOSITE) {}
612 613
  inline explicit Builder(_::ListBuilder builder): builder(builder) {}

614 615
  inline operator Reader() const { return Reader(builder.asReader()); }
  inline Reader asReader() const { return Reader(builder.asReader()); }
616

617
  inline uint size() const { return unbound(builder.size() / ELEMENTS); }
618
  inline AnyStruct::Builder operator[](uint index) {
619
    KJ_IREQUIRE(index < size());
620
    return AnyStruct::Builder(builder.getStructElement(bounded(index) * ELEMENTS));
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
  }

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

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

class AnyList::Reader {
public:
Kenton Varda's avatar
Kenton Varda committed
638 639
  typedef AnyList Reads;

640
  inline Reader(): _reader(ElementSize::VOID) {}
641 642
  inline Reader(_::ListReader reader): _reader(reader) {}

643
#if !_MSC_VER  // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves.
Kenton Varda's avatar
Kenton Varda committed
644
  template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromReader<T>) == Kind::LIST>>
645 646
  inline Reader(T&& value)
      : _reader(_::PointerHelpers<FromReader<T>>::getInternalReader(kj::fwd<T>(value))) {}
647
#endif
648

649
  inline ElementSize getElementSize() { return _reader.getElementSize(); }
650
  inline uint size() { return unbound(_reader.size() / ELEMENTS); }
651

652
  inline kj::ArrayPtr<const byte> getRawBytes() { return _reader.asRawBytes(); }
653

654
  Equality equals(AnyList::Reader right);
655 656
  bool operator==(AnyList::Reader right);
  inline bool operator!=(AnyList::Reader right) {
657 658 659
    return !(*this == right);
  }

660 661 662 663
  inline MessageSize totalSize() const {
    return _reader.totalSize().asPublic();
  }

664
  template <typename T> ReaderFor<T> as() {
665
    // T must be List<U>.
666 667 668 669
    return ReaderFor<T>(_reader);
  }
private:
  _::ListReader _reader;
670 671 672

  template <typename, Kind>
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
673
  friend class Orphanage;
674 675 676 677
};

class AnyList::Builder {
public:
Kenton Varda's avatar
Kenton Varda committed
678 679
  typedef AnyList Builds;

680
  inline Builder(decltype(nullptr)): _builder(ElementSize::VOID) {}
681 682
  inline Builder(_::ListBuilder builder): _builder(builder) {}

683
#if !_MSC_VER  // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves.
Kenton Varda's avatar
Kenton Varda committed
684
  template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromBuilder<T>) == Kind::LIST>>
685 686
  inline Builder(T&& value)
      : _builder(_::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::fwd<T>(value))) {}
687
#endif
688

689
  inline ElementSize getElementSize() { return _builder.getElementSize(); }
690
  inline uint size() { return unbound(_builder.size() / ELEMENTS); }
691

692
  Equality equals(AnyList::Reader right);
693
  inline bool operator==(AnyList::Reader right) {
694 695
    return asReader() == right;
  }
696
  inline bool operator!=(AnyList::Reader right) {
697 698 699
    return !(*this == right);
  }

700
  template <typename T> BuilderFor<T> as() {
701
    // T must be List<U>.
702 703 704 705 706 707 708 709
    return BuilderFor<T>(_builder);
  }

  inline operator Reader() const { return Reader(_builder.asReader()); }
  inline Reader asReader() const { return Reader(_builder.asReader()); }

private:
  _::ListBuilder _builder;
Kenton Varda's avatar
Kenton Varda committed
710 711

  friend class Orphanage;
712 713
};

714 715 716 717 718 719
// =======================================================================================
// Pipeline helpers
//
// These relate to capabilities, but we don't declare them in capability.h because generated code
// for structs needs to know about these, even in files that contain no interfaces.

720 721
#if !CAPNP_LITE

722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
struct PipelineOp {
  // Corresponds to rpc.capnp's PromisedAnswer.Op.

  enum Type {
    NOOP,  // for convenience

    GET_POINTER_FIELD

    // There may be other types in the future...
  };

  Type type;
  union {
    uint16_t pointerIndex;  // for GET_POINTER_FIELD
  };
};

class PipelineHook {
  // Represents a currently-running call, and implements pipelined requests on its result.

public:
743
  virtual kj::Own<PipelineHook> addRef() = 0;
744 745
  // Increment this object's reference count.

746
  virtual kj::Own<ClientHook> getPipelinedCap(kj::ArrayPtr<const PipelineOp> ops) = 0;
747 748
  // Extract a promised Capability from the results.

749
  virtual kj::Own<ClientHook> getPipelinedCap(kj::Array<PipelineOp>&& ops);
750 751 752
  // Version of getPipelinedCap() passing the array by move.  May avoid a copy in some cases.
  // Default implementation just calls the other version.

753 754 755 756 757
  template <typename Pipeline, typename = FromPipeline<Pipeline>>
  static inline kj::Own<PipelineHook> from(Pipeline&& pipeline);

private:
  template <typename T> struct FromImpl;
758 759
};

760 761
#endif  // !CAPNP_LITE

762 763 764
// =======================================================================================
// Inline implementation details

765 766
inline MessageSize AnyPointer::Reader::targetSize() const {
  return reader.targetSize().asPublic();
Kenton Varda's avatar
Kenton Varda committed
767 768
}

769 770
inline PointerType AnyPointer::Reader::getPointerType() const {
  return reader.getPointerType();
771 772 773
}

template <typename T>
774
inline ReaderFor<T> AnyPointer::Reader::getAs() const {
775 776 777
  return _::PointerHelpers<T>::get(reader);
}

778 779
inline MessageSize AnyPointer::Builder::targetSize() const {
  return asReader().targetSize();
Kenton Varda's avatar
Kenton Varda committed
780 781
}

782 783
inline PointerType AnyPointer::Builder::getPointerType() {
  return builder.getPointerType();
784 785
}

786
inline void AnyPointer::Builder::clear() {
787 788 789 790
  return builder.clear();
}

template <typename T>
791
inline BuilderFor<T> AnyPointer::Builder::getAs() {
792 793 794 795
  return _::PointerHelpers<T>::get(builder);
}

template <typename T>
796
inline BuilderFor<T> AnyPointer::Builder::initAs() {
797 798 799 800
  return _::PointerHelpers<T>::init(builder);
}

template <typename T>
801
inline BuilderFor<T> AnyPointer::Builder::initAs(uint elementCount) {
802 803 804
  return _::PointerHelpers<T>::init(builder, elementCount);
}

805 806
inline AnyList::Builder AnyPointer::Builder::initAsAnyList(
    ElementSize elementSize, uint elementCount) {
807
  return AnyList::Builder(builder.initList(elementSize, bounded(elementCount) * ELEMENTS));
808 809
}

810
inline List<AnyStruct>::Builder AnyPointer::Builder::initAsListOfAnyStruct(
811
    uint16_t dataWordCount, uint16_t pointerCount, uint elementCount) {
812 813 814
  return List<AnyStruct>::Builder(builder.initStructList(bounded(elementCount) * ELEMENTS,
      _::StructSize(bounded(dataWordCount) * WORDS,
                    bounded(pointerCount) * POINTERS)));
815
}
816

817 818
inline AnyStruct::Builder AnyPointer::Builder::initAsAnyStruct(
    uint16_t dataWordCount, uint16_t pointerCount) {
819
  return AnyStruct::Builder(builder.initStruct(
820 821
      _::StructSize(bounded(dataWordCount) * WORDS,
                    bounded(pointerCount) * POINTERS)));
822 823
}

824
template <typename T>
825
inline void AnyPointer::Builder::setAs(ReaderFor<T> value) {
826 827 828
  return _::PointerHelpers<T>::set(builder, value);
}

Matthew Maurer's avatar
Matthew Maurer committed
829 830 831 832 833
template <typename T>
inline void AnyPointer::Builder::setCanonicalAs(ReaderFor<T> value) {
  return _::PointerHelpers<T>::setCanonical(builder, value);
}

834
template <typename T>
835
inline void AnyPointer::Builder::setAs(
836 837 838 839 840
    std::initializer_list<ReaderFor<ListElementType<T>>> list) {
  return _::PointerHelpers<T>::set(builder, list);
}

template <typename T>
841
inline void AnyPointer::Builder::adopt(Orphan<T>&& orphan) {
842 843 844 845
  _::PointerHelpers<T>::adopt(builder, kj::mv(orphan));
}

template <typename T>
846
inline Orphan<T> AnyPointer::Builder::disownAs() {
847 848 849
  return _::PointerHelpers<T>::disown(builder);
}

850 851
inline Orphan<AnyPointer> AnyPointer::Builder::disown() {
  return Orphan<AnyPointer>(builder.disown());
852 853
}

854 855
template <> struct ReaderFor_ <AnyPointer, Kind::OTHER> { typedef AnyPointer::Reader Type; };
template <> struct BuilderFor_<AnyPointer, Kind::OTHER> { typedef AnyPointer::Builder Type; };
856 857
template <> struct ReaderFor_ <AnyStruct, Kind::OTHER> { typedef AnyStruct::Reader Type; };
template <> struct BuilderFor_<AnyStruct, Kind::OTHER> { typedef AnyStruct::Builder Type; };
858 859

template <>
860
struct Orphanage::GetInnerReader<AnyPointer, Kind::OTHER> {
861
  static inline _::PointerReader apply(const AnyPointer::Reader& t) {
862 863 864 865
    return t.reader;
  }
};

866
template <>
867
struct Orphanage::GetInnerBuilder<AnyPointer, Kind::OTHER> {
868
  static inline _::PointerBuilder apply(AnyPointer::Builder& t) {
869 870 871 872
    return t.builder;
  }
};

Kenton Varda's avatar
Kenton Varda committed
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
template <>
struct Orphanage::GetInnerReader<AnyStruct, Kind::OTHER> {
  static inline _::StructReader apply(const AnyStruct::Reader& t) {
    return t._reader;
  }
};

template <>
struct Orphanage::GetInnerBuilder<AnyStruct, Kind::OTHER> {
  static inline _::StructBuilder apply(AnyStruct::Builder& t) {
    return t._builder;
  }
};

template <>
struct Orphanage::GetInnerReader<AnyList, Kind::OTHER> {
  static inline _::ListReader apply(const AnyList::Reader& t) {
    return t._reader;
  }
};

template <>
struct Orphanage::GetInnerBuilder<AnyList, Kind::OTHER> {
  static inline _::ListBuilder apply(AnyList::Builder& t) {
    return t._builder;
  }
};

901
template <typename T>
902
inline BuilderFor<T> Orphan<AnyPointer>::getAs() {
903 904 905
  return _::OrphanGetImpl<T>::apply(builder);
}
template <typename T>
906
inline ReaderFor<T> Orphan<AnyPointer>::getAsReader() const {
907 908 909
  return _::OrphanGetImpl<T>::applyReader(builder);
}
template <typename T>
910
inline Orphan<T> Orphan<AnyPointer>::releaseAs() {
911 912 913
  return Orphan<T>(kj::mv(builder));
}

914
// Using AnyPointer as the template type should work...
915 916

template <>
917
inline typename AnyPointer::Reader AnyPointer::Reader::getAs<AnyPointer>() const {
918 919 920
  return *this;
}
template <>
921
inline typename AnyPointer::Builder AnyPointer::Builder::getAs<AnyPointer>() {
922 923 924
  return *this;
}
template <>
925
inline typename AnyPointer::Builder AnyPointer::Builder::initAs<AnyPointer>() {
926 927 928 929
  clear();
  return *this;
}
template <>
930
inline void AnyPointer::Builder::setAs<AnyPointer>(AnyPointer::Reader value) {
931 932 933
  return builder.copyFrom(value.reader);
}
template <>
934
inline void AnyPointer::Builder::adopt<AnyPointer>(Orphan<AnyPointer>&& orphan) {
935 936 937
  builder.adopt(kj::mv(orphan.builder));
}
template <>
938 939
inline Orphan<AnyPointer> AnyPointer::Builder::disownAs<AnyPointer>() {
  return Orphan<AnyPointer>(builder.disown());
940 941
}
template <>
942
inline Orphan<AnyPointer> Orphan<AnyPointer>::releaseAs() {
943 944 945
  return kj::mv(*this);
}

946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970
namespace _ {  // private

// Specialize PointerHelpers for AnyPointer.

template <>
struct PointerHelpers<AnyPointer, Kind::OTHER> {
  static inline AnyPointer::Reader get(PointerReader reader,
                                       const void* defaultValue = nullptr,
                                       uint defaultBytes = 0) {
    return AnyPointer::Reader(reader);
  }
  static inline AnyPointer::Builder get(PointerBuilder builder,
                                        const void* defaultValue = nullptr,
                                        uint defaultBytes = 0) {
    return AnyPointer::Builder(builder);
  }
  static inline void set(PointerBuilder builder, AnyPointer::Reader value) {
    AnyPointer::Builder(builder).set(value);
  }
  static inline void adopt(PointerBuilder builder, Orphan<AnyPointer>&& value) {
    builder.adopt(kj::mv(value.builder));
  }
  static inline Orphan<AnyPointer> disown(PointerBuilder builder) {
    return Orphan<AnyPointer>(builder.disown());
  }
971 972 973 974 975 976
  static inline _::PointerReader getInternalReader(const AnyPointer::Reader& reader) {
    return reader.reader;
  }
  static inline _::PointerBuilder getInternalBuilder(AnyPointer::Builder&& builder) {
    return builder.builder;
  }
977 978
};

979 980
template <>
struct PointerHelpers<AnyStruct, Kind::OTHER> {
981
  static inline AnyStruct::Reader get(
982 983 984
      PointerReader reader, const word* defaultValue = nullptr) {
    return AnyStruct::Reader(reader.getStruct(defaultValue));
  }
985
  static inline AnyStruct::Builder get(
986 987 988
      PointerBuilder builder, const word* defaultValue = nullptr) {
    // TODO(someday): Allow specifying the size somehow?
    return AnyStruct::Builder(builder.getStruct(
989
        _::StructSize(ZERO * WORDS, ZERO * POINTERS), defaultValue));
990 991 992 993
  }
  static inline void set(PointerBuilder builder, AnyStruct::Reader value) {
    builder.setStruct(value._reader);
  }
994
  static inline AnyStruct::Builder init(
995
      PointerBuilder builder, uint16_t dataWordCount, uint16_t pointerCount) {
996
    return AnyStruct::Builder(builder.initStruct(
997 998
        StructSize(bounded(dataWordCount) * WORDS,
                   bounded(pointerCount) * POINTERS)));
999
  }
1000

1001 1002 1003 1004 1005 1006
  static void adopt(PointerBuilder builder, Orphan<AnyStruct>&& value) {
    builder.adopt(kj::mv(value.builder));
  }
  static Orphan<AnyStruct> disown(PointerBuilder builder) {
    return Orphan<AnyStruct>(builder.disown());
  }
1007 1008 1009 1010
};

template <>
struct PointerHelpers<AnyList, Kind::OTHER> {
1011
  static inline AnyList::Reader get(
1012 1013 1014
      PointerReader reader, const word* defaultValue = nullptr) {
    return AnyList::Reader(reader.getListAnySize(defaultValue));
  }
1015
  static inline AnyList::Builder get(
1016 1017 1018 1019 1020 1021
      PointerBuilder builder, const word* defaultValue = nullptr) {
    return AnyList::Builder(builder.getListAnySize(defaultValue));
  }
  static inline void set(PointerBuilder builder, AnyList::Reader value) {
    builder.setList(value._reader);
  }
1022
  static inline AnyList::Builder init(
1023
      PointerBuilder builder, ElementSize elementSize, uint elementCount) {
1024
    return AnyList::Builder(builder.initList(
1025
        elementSize, bounded(elementCount) * ELEMENTS));
1026
  }
1027
  static inline AnyList::Builder init(
1028
      PointerBuilder builder, uint16_t dataWordCount, uint16_t pointerCount, uint elementCount) {
1029
    return AnyList::Builder(builder.initStructList(
1030 1031 1032
        bounded(elementCount) * ELEMENTS,
        StructSize(bounded(dataWordCount) * WORDS,
                   bounded(pointerCount) * POINTERS)));
1033
  }
1034

1035 1036 1037 1038 1039 1040
  static void adopt(PointerBuilder builder, Orphan<AnyList>&& value) {
    builder.adopt(kj::mv(value.builder));
  }
  static Orphan<AnyList> disown(PointerBuilder builder) {
    return Orphan<AnyList>(builder.disown());
  }
1041 1042
};

Kenton Varda's avatar
Kenton Varda committed
1043 1044 1045
template <>
struct OrphanGetImpl<AnyStruct, Kind::OTHER> {
  static inline AnyStruct::Builder apply(_::OrphanBuilder& builder) {
1046
    return AnyStruct::Builder(builder.asStruct(_::StructSize(ZERO * WORDS, ZERO * POINTERS)));
Kenton Varda's avatar
Kenton Varda committed
1047 1048
  }
  static inline AnyStruct::Reader applyReader(const _::OrphanBuilder& builder) {
1049
    return AnyStruct::Reader(builder.asStructReader(_::StructSize(ZERO * WORDS, ZERO * POINTERS)));
Kenton Varda's avatar
Kenton Varda committed
1050 1051
  }
  static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
1052
    builder.truncate(size, _::StructSize(ZERO * WORDS, ZERO * POINTERS));
Kenton Varda's avatar
Kenton Varda committed
1053 1054 1055
  }
};

1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
template <>
struct OrphanGetImpl<AnyList, Kind::OTHER> {
  static inline AnyList::Builder apply(_::OrphanBuilder& builder) {
    return AnyList::Builder(builder.asListAnySize());
  }
  static inline AnyList::Reader applyReader(const _::OrphanBuilder& builder) {
    return AnyList::Reader(builder.asListReaderAnySize());
  }
  static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) {
    builder.truncate(size, ElementSize::POINTER);
  }
};

1069 1070
}  // namespace _ (private)

Kenton Varda's avatar
Kenton Varda committed
1071 1072
#if !CAPNP_LITE

1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
template <typename T>
struct PipelineHook::FromImpl {
  static inline kj::Own<PipelineHook> apply(typename T::Pipeline&& pipeline) {
    return from(kj::mv(pipeline._typeless));
  }
};

template <>
struct PipelineHook::FromImpl<AnyPointer> {
  static inline kj::Own<PipelineHook> apply(AnyPointer::Pipeline&& pipeline) {
    return kj::mv(pipeline.hook);
  }
};

template <typename Pipeline, typename T>
inline kj::Own<PipelineHook> PipelineHook::from(Pipeline&& pipeline) {
  return FromImpl<T>::apply(kj::fwd<Pipeline>(pipeline));
}

Kenton Varda's avatar
Kenton Varda committed
1092 1093
#endif  // !CAPNP_LITE

1094
}  // namespace capnp