any.h 28.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
#ifndef CAPNP_ANY_H_
#define CAPNP_ANY_H_
24

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

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

namespace capnp {

class StructSchema;
class ListSchema;
38
class InterfaceSchema;
39
class Orphanage;
Kenton Varda's avatar
Kenton Varda committed
40
class ClientHook;
41
class PipelineHook;
42
struct PipelineOp;
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 72
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)
73 74

// =======================================================================================
75
// AnyPointer!
76

77 78
struct AnyPointer {
  // Reader/Builder for the `AnyPointer` field type, i.e. a pointer that can point to an arbitrary
79 80
  // object.

81 82
  AnyPointer() = delete;

83 84
  class Reader {
  public:
85
    typedef AnyPointer Reads;
86

87 88 89
    Reader() = default;
    inline Reader(_::PointerReader reader): reader(reader) {}

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

93
    inline bool isNull() const;
94 95 96 97 98 99
    inline bool isStruct() {
      return reader.isStruct();
    }
    inline bool isList() {
      return reader.isList();
    }
100 101

    template <typename T>
102 103
    inline ReaderFor<T> getAs() const;
    // Valid for T = any generated struct type, interface type, List<U>, Text, or Data.
104 105

    template <typename T>
106
    inline ReaderFor<T> getAs(StructSchema schema) const;
107 108 109
    // Only valid for T = DynamicStruct.  Requires `#include <capnp/dynamic.h>`.

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

113 114 115 116
    template <typename T>
    inline ReaderFor<T> getAs(InterfaceSchema schema) const;
    // Only valid for T = DynamicCapability.  Requires `#include <capnp/dynamic.h>`.

117
#if !CAPNP_LITE
118
    kj::Own<ClientHook> getPipelinedCap(kj::ArrayPtr<const PipelineOp> ops) const;
Kenton Varda's avatar
Kenton Varda committed
119 120
    // Used by RPC system to implement pipelining.  Applications generally shouldn't use this
    // directly.
121
#endif  // !CAPNP_LITE
Kenton Varda's avatar
Kenton Varda committed
122

123 124
  private:
    _::PointerReader reader;
125
    friend struct AnyPointer;
126
    friend class Orphanage;
127
    friend class CapReaderContext;
128 129 130 131
  };

  class Builder {
  public:
132
    typedef AnyPointer Builds;
133

134 135 136 137
    Builder() = delete;
    inline Builder(decltype(nullptr)) {}
    inline Builder(_::PointerBuilder builder): builder(builder) {}

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

141
    inline bool isNull();
142 143 144 145 146 147
    inline bool isStruct() {
      return builder.isStruct();
    }
    inline bool isList() {
      return builder.isList();
    }
148 149 150 151 152

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

    template <typename T>
153
    inline BuilderFor<T> getAs();
154 155 156
    // Valid for T = any generated struct type, List<U>, Text, or Data.

    template <typename T>
157
    inline BuilderFor<T> getAs(StructSchema schema);
158 159 160
    // Only valid for T = DynamicStruct.  Requires `#include <capnp/dynamic.h>`.

    template <typename T>
161
    inline BuilderFor<T> getAs(ListSchema schema);
162 163 164
    // Only valid for T = DynamicList.  Requires `#include <capnp/dynamic.h>`.

    template <typename T>
165 166 167 168 169
    inline BuilderFor<T> getAs(InterfaceSchema schema);
    // Only valid for T = DynamicCapability.  Requires `#include <capnp/dynamic.h>`.

    template <typename T>
    inline BuilderFor<T> initAs();
170 171 172
    // Valid for T = any generated struct type.

    template <typename T>
173
    inline BuilderFor<T> initAs(uint elementCount);
174 175 176
    // Valid for T = List<U>, Text, or Data.

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

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

184
    inline AnyList::Builder initAsAnyList(ElementSize elementSize, uint elementCount);
185 186
    // Note: Does not accept INLINE_COMPOSITE for elementSize.

187 188
    inline List<AnyStruct>::Builder initAsListOfAnyStruct(
        uint dataWordCount, uint pointerCount, uint elementCount);
189 190 191

    inline AnyStruct::Builder initAsAnyStruct(uint dataWordCount, uint pointerCount);

192
    template <typename T>
193
    inline void setAs(ReaderFor<T> value);
194 195 196 197 198 199 200
    // 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<?>.

201
    inline void set(Reader value) { builder.copyFrom(value.reader); }
202
    // Set to a copy of another AnyPointer.
203

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
    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>`.

221 222 223 224
    template <typename T>
    inline Orphan<T> disownAs(InterfaceSchema schema);
    // Only valid for T = DynamicCapability.  Requires `#include <capnp/dynamic.h>`.

225
    inline Orphan<AnyPointer> disown();
226 227 228 229 230
    // Disown without a type.

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

231 232
  private:
    _::PointerBuilder builder;
233
    friend class Orphanage;
234
    friend class CapBuilderContext;
235
  };
236

237
#if !CAPNP_LITE
238 239
  class Pipeline {
  public:
240 241
    typedef AnyPointer Pipelines;

242
    inline Pipeline(decltype(nullptr)) {}
243
    inline explicit Pipeline(kj::Own<PipelineHook>&& hook): hook(kj::mv(hook)) {}
244

245
    Pipeline noop();
246 247
    // Just make a copy.

248
    Pipeline getPointerField(uint16_t pointerIndex);
249 250 251
    // Deprecated. In the future, we should use .asAnyStruct.getPointerField.

    inline AnyStruct::Pipeline asAnyStruct();
252

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

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

259
  private:
260
    kj::Own<PipelineHook> hook;
261 262
    kj::Array<PipelineOp> ops;

263
    inline Pipeline(kj::Own<PipelineHook>&& hook, kj::Array<PipelineOp>&& ops)
264
        : hook(kj::mv(hook)), ops(kj::mv(ops)) {}
265 266

    friend class LocalClient;
267
    friend class PipelineHook;
268
  };
269
#endif  // !CAPNP_LITE
270 271
};

272
template <>
273
class Orphan<AnyPointer> {
274 275 276 277 278 279 280 281
  // An orphaned object of unknown type.

public:
  Orphan() = default;
  KJ_DISALLOW_COPY(Orphan);
  Orphan(Orphan&&) = default;
  Orphan& operator=(Orphan&&) = default;

282 283 284
  template <typename T>
  inline Orphan(Orphan<T>&& other): builder(kj::mv(other.builder)) {}
  template <typename T>
285
  inline Orphan& operator=(Orphan<T>&& other) { builder = kj::mv(other.builder); return *this; }
286 287
  // Cast from typed orphan.

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

  template <typename T>
293
  inline BuilderFor<T> getAs();
294
  template <typename T>
295
  inline BuilderFor<T> getAs(StructSchema schema);
296
  template <typename T>
297
  inline BuilderFor<T> getAs(ListSchema schema);
298
  template <typename T>
299
  inline typename T::Client getAs(InterfaceSchema schema);
300
  template <typename T>
301
  inline ReaderFor<T> getAsReader() const;
302
  template <typename T>
303 304 305 306 307
  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;
308 309 310 311 312 313 314

  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);
315 316
  template <typename T>
  inline Orphan<T> releaseAs(InterfaceSchema schema);
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
  // 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;

  inline Orphan(_::OrphanBuilder&& builder)
      : builder(kj::mv(builder)) {}

  template <typename, Kind>
  friend struct _::PointerHelpers;
  friend class Orphanage;
  template <typename U>
  friend class Orphan;
333
  friend class AnyPointer::Builder;
334 335
};

336 337 338 339 340
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
341
using AnyTypeFor = typename AnyTypeFor_<CAPNP_KIND(T)>::Type;
342 343 344

template <typename T>
inline ReaderFor<AnyTypeFor<FromReader<T>>> toAny(T&& value) {
345
  return ReaderFor<AnyTypeFor<FromReader<T>>>(
346 347 348 349
      _::PointerHelpers<FromReader<T>>::getInternalReader(value));
}
template <typename T>
inline BuilderFor<AnyTypeFor<FromBuilder<T>>> toAny(T&& value) {
350
  return BuilderFor<AnyTypeFor<FromBuilder<T>>>(
351 352 353 354 355
      _::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::mv(value)));
}

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

359 360 361 362 363 364 365 366 367 368
  List() = delete;

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

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

    inline uint size() const { return reader.size() / ELEMENTS; }
369
    inline AnyPointer::Reader operator[](uint index) const {
370
      KJ_IREQUIRE(index < size());
371
      return AnyPointer::Reader(reader.getPointerElement(index * ELEMENTS));
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
    }

    typedef _::IndexingIterator<const Reader, typename AnyPointer::Reader> 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<AnyPointer> 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; }
401
    inline AnyPointer::Builder operator[](uint index) {
402
      KJ_IREQUIRE(index < size());
403
      return AnyPointer::Builder(builder.getPointerElement(index * ELEMENTS));
404 405 406 407 408 409 410 411
    }

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

  private:
    _::ListBuilder builder;
412
    template <typename, Kind>
413 414
    friend struct _::PointerHelpers;
    friend class Orphanage;
415
    template <typename, Kind>
416 417 418 419 420 421 422 423 424
    friend struct ToDynamic_;
  };
};

class AnyStruct::Reader {
public:
  Reader() = default;
  inline Reader(_::StructReader reader): _reader(reader) {}

425
#if !_MSC_VER  // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves.
Kenton Varda's avatar
Kenton Varda committed
426
  template <typename T, typename = kj::EnableIf<CAPNP_KIND(FromReader<T>) == Kind::STRUCT>>
427 428
  inline Reader(T&& value)
      : _reader(_::PointerHelpers<FromReader<T>>::getInternalReader(kj::fwd<T>(value))) {}
429
#endif
430

431 432 433 434 435 436 437 438 439 440 441 442
  Data::Reader getDataSection() {
    return _reader.getDataSectionAsBlob();
  }
  List<AnyPointer>::Reader getPointerSection() {
    return List<AnyPointer>::Reader(_reader.getPointerSectionAsList());
  }

  template <typename T>
  ReaderFor<T> as();
  // T must be a struct type.
private:
  _::StructReader _reader;
443 444 445

  template <typename, Kind>
  friend struct _::PointerHelpers;
446 447 448 449 450 451 452
};

class AnyStruct::Builder {
public:
  inline Builder(decltype(nullptr)) {}
  inline Builder(_::StructBuilder builder): _builder(builder) {}

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

459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
  inline Data::Builder getDataSection() {
    return _builder.getDataSectionAsBlob();
  }
  List<AnyPointer>::Builder getPointerSection() {
    return List<AnyPointer>::Builder(_builder.getPointerSectionAsList());
  }

  inline operator Reader() const { return Reader(_builder.asReader()); }
  inline Reader asReader() const { return Reader(_builder.asReader()); }
private:
  _::StructBuilder _builder;
  friend class Orphanage;
  friend class CapBuilderContext;
};

Kenton Varda's avatar
Kenton Varda committed
474
#if !CAPNP_LITE
475 476 477 478 479 480
class AnyStruct::Pipeline {
public:
  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).
  //
Kenton Varda's avatar
Kenton Varda committed
481
  // TODO(perf):  On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies.
482 483 484 485 486 487 488 489 490 491
  //   Also make `ops` into a Vector to optimize this.

private:
  kj::Own<PipelineHook> hook;
  kj::Array<PipelineOp> ops;

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

};
Kenton Varda's avatar
Kenton Varda committed
492
#endif  // !CAPNP_LITE
493 494 495 496 497 498 499 500 501

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

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

  inline uint size() const { return reader.size() / ELEMENTS; }
502
  inline AnyStruct::Reader operator[](uint index) const {
503
    KJ_IREQUIRE(index < size());
504
    return AnyStruct::Reader(reader.getStructElement(index * ELEMENTS));
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
  }

  typedef _::IndexingIterator<const Reader, typename AnyStruct::Reader> 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 List<AnyStruct, Kind::OTHER>::Builder {
public:
  typedef List<AnyStruct> 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; }
535
  inline AnyStruct::Builder operator[](uint index) {
536
    KJ_IREQUIRE(index < size());
537
    return AnyStruct::Builder(builder.getStructElement(index * ELEMENTS));
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
  }

  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:
  Reader() = default;
  inline Reader(_::ListReader reader): _reader(reader) {}

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

564 565
  inline ElementSize getElementSize() { return _reader.getElementSize(); }
  inline uint size() { return _reader.size() / ELEMENTS; }
566 567 568 569 570 571 572

  template <typename T> ReaderFor<T> as() {
  // T must be List<U>.
    return ReaderFor<T>(_reader);
  }
private:
  _::ListReader _reader;
573 574 575

  template <typename, Kind>
  friend struct _::PointerHelpers;
576 577 578 579 580 581 582
};

class AnyList::Builder {
public:
  inline Builder(decltype(nullptr)) {}
  inline Builder(_::ListBuilder builder): _builder(builder) {}

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

589 590
  inline ElementSize getElementSize() { return _builder.getElementSize(); }
  inline uint size() { return _builder.size() / ELEMENTS; }
591 592 593 594 595 596 597 598 599 600 601 602 603

  template <typename T> BuilderFor<T> as() {
  // T must be List<U>.
    return BuilderFor<T>(_builder);
  }

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

private:
  _::ListBuilder _builder;
};

604 605 606 607 608 609
// =======================================================================================
// 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.

610 611
#if !CAPNP_LITE

612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
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:
633
  virtual kj::Own<PipelineHook> addRef() = 0;
634 635
  // Increment this object's reference count.

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

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

643 644 645 646 647
  template <typename Pipeline, typename = FromPipeline<Pipeline>>
  static inline kj::Own<PipelineHook> from(Pipeline&& pipeline);

private:
  template <typename T> struct FromImpl;
648 649
};

650 651
#endif  // !CAPNP_LITE

652 653 654
// =======================================================================================
// Inline implementation details

655 656
inline MessageSize AnyPointer::Reader::targetSize() const {
  return reader.targetSize().asPublic();
Kenton Varda's avatar
Kenton Varda committed
657 658
}

659
inline bool AnyPointer::Reader::isNull() const {
660 661 662 663
  return reader.isNull();
}

template <typename T>
664
inline ReaderFor<T> AnyPointer::Reader::getAs() const {
665 666 667
  return _::PointerHelpers<T>::get(reader);
}

668 669
inline MessageSize AnyPointer::Builder::targetSize() const {
  return asReader().targetSize();
Kenton Varda's avatar
Kenton Varda committed
670 671
}

672
inline bool AnyPointer::Builder::isNull() {
673 674 675
  return builder.isNull();
}

676
inline void AnyPointer::Builder::clear() {
677 678 679 680
  return builder.clear();
}

template <typename T>
681
inline BuilderFor<T> AnyPointer::Builder::getAs() {
682 683 684 685
  return _::PointerHelpers<T>::get(builder);
}

template <typename T>
686
inline BuilderFor<T> AnyPointer::Builder::initAs() {
687 688 689 690
  return _::PointerHelpers<T>::init(builder);
}

template <typename T>
691
inline BuilderFor<T> AnyPointer::Builder::initAs(uint elementCount) {
692 693 694
  return _::PointerHelpers<T>::init(builder, elementCount);
}

695 696 697
inline AnyList::Builder AnyPointer::Builder::initAsAnyList(
    ElementSize elementSize, uint elementCount) {
  return AnyList::Builder(builder.initList(elementSize, elementCount * ELEMENTS));
698 699
}

700 701 702 703 704
inline List<AnyStruct>::Builder AnyPointer::Builder::initAsListOfAnyStruct(
    uint dataWordCount, uint pointerCount, uint elementCount) {
  return List<AnyStruct>::Builder(builder.initStructList(elementCount * ELEMENTS,
      _::StructSize(dataWordCount * WORDS, pointerCount * POINTERS)));
}
705 706

inline AnyStruct::Builder AnyPointer::Builder::initAsAnyStruct(uint dataWordCount, uint pointerCount) {
707 708
  return AnyStruct::Builder(builder.initStruct(
      _::StructSize(dataWordCount * WORDS, pointerCount * POINTERS)));
709 710
}

711
template <typename T>
712
inline void AnyPointer::Builder::setAs(ReaderFor<T> value) {
713 714 715 716
  return _::PointerHelpers<T>::set(builder, value);
}

template <typename T>
717
inline void AnyPointer::Builder::setAs(
718 719 720 721 722
    std::initializer_list<ReaderFor<ListElementType<T>>> list) {
  return _::PointerHelpers<T>::set(builder, list);
}

template <typename T>
723
inline void AnyPointer::Builder::adopt(Orphan<T>&& orphan) {
724 725 726 727
  _::PointerHelpers<T>::adopt(builder, kj::mv(orphan));
}

template <typename T>
728
inline Orphan<T> AnyPointer::Builder::disownAs() {
729 730 731
  return _::PointerHelpers<T>::disown(builder);
}

732 733
inline Orphan<AnyPointer> AnyPointer::Builder::disown() {
  return Orphan<AnyPointer>(builder.disown());
734 735
}

736 737
template <> struct ReaderFor_ <AnyPointer, Kind::OTHER> { typedef AnyPointer::Reader Type; };
template <> struct BuilderFor_<AnyPointer, Kind::OTHER> { typedef AnyPointer::Builder Type; };
738 739
template <> struct ReaderFor_ <AnyStruct, Kind::OTHER> { typedef AnyStruct::Reader Type; };
template <> struct BuilderFor_<AnyStruct, Kind::OTHER> { typedef AnyStruct::Builder Type; };
740 741

template <>
742
struct Orphanage::GetInnerReader<AnyPointer, Kind::OTHER> {
743
  static inline _::PointerReader apply(const AnyPointer::Reader& t) {
744 745 746 747
    return t.reader;
  }
};

748
template <>
749
struct Orphanage::GetInnerBuilder<AnyPointer, Kind::OTHER> {
750
  static inline _::PointerBuilder apply(AnyPointer::Builder& t) {
751 752 753 754
    return t.builder;
  }
};

755
template <typename T>
756
inline BuilderFor<T> Orphan<AnyPointer>::getAs() {
757 758 759
  return _::OrphanGetImpl<T>::apply(builder);
}
template <typename T>
760
inline ReaderFor<T> Orphan<AnyPointer>::getAsReader() const {
761 762 763
  return _::OrphanGetImpl<T>::applyReader(builder);
}
template <typename T>
764
inline Orphan<T> Orphan<AnyPointer>::releaseAs() {
765 766 767
  return Orphan<T>(kj::mv(builder));
}

768
// Using AnyPointer as the template type should work...
769 770

template <>
771
inline typename AnyPointer::Reader AnyPointer::Reader::getAs<AnyPointer>() const {
772 773 774
  return *this;
}
template <>
775
inline typename AnyPointer::Builder AnyPointer::Builder::getAs<AnyPointer>() {
776 777 778
  return *this;
}
template <>
779
inline typename AnyPointer::Builder AnyPointer::Builder::initAs<AnyPointer>() {
780 781 782 783
  clear();
  return *this;
}
template <>
784
inline void AnyPointer::Builder::setAs<AnyPointer>(AnyPointer::Reader value) {
785 786 787
  return builder.copyFrom(value.reader);
}
template <>
788
inline void AnyPointer::Builder::adopt<AnyPointer>(Orphan<AnyPointer>&& orphan) {
789 790 791
  builder.adopt(kj::mv(orphan.builder));
}
template <>
792 793
inline Orphan<AnyPointer> AnyPointer::Builder::disownAs<AnyPointer>() {
  return Orphan<AnyPointer>(builder.disown());
794 795
}
template <>
796
inline Orphan<AnyPointer> Orphan<AnyPointer>::releaseAs() {
797 798 799
  return kj::mv(*this);
}

800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
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());
  }
};

827 828
template <>
struct PointerHelpers<AnyStruct, Kind::OTHER> {
829
  static inline AnyStruct::Reader get(
830 831 832
      PointerReader reader, const word* defaultValue = nullptr) {
    return AnyStruct::Reader(reader.getStruct(defaultValue));
  }
833
  static inline AnyStruct::Builder get(
834 835 836 837 838 839 840 841
      PointerBuilder builder, const word* defaultValue = nullptr) {
    // TODO(someday): Allow specifying the size somehow?
    return AnyStruct::Builder(builder.getStruct(
        _::StructSize(0 * WORDS, 0 * POINTERS), defaultValue));
  }
  static inline void set(PointerBuilder builder, AnyStruct::Reader value) {
    builder.setStruct(value._reader);
  }
842
  static inline AnyStruct::Builder init(
843
      PointerBuilder builder, uint dataWordCount, uint pointerCount) {
844
    return AnyStruct::Builder(builder.initStruct(
845 846 847 848 849 850
        StructSize(dataWordCount * WORDS, pointerCount * POINTERS)));
  }
};

template <>
struct PointerHelpers<AnyList, Kind::OTHER> {
851
  static inline AnyList::Reader get(
852 853 854
      PointerReader reader, const word* defaultValue = nullptr) {
    return AnyList::Reader(reader.getListAnySize(defaultValue));
  }
855
  static inline AnyList::Builder get(
856 857 858 859 860 861
      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);
  }
862
  static inline AnyList::Builder init(
863 864 865
      PointerBuilder builder, ElementSize elementSize, uint elementCount) {
    return AnyList::Builder(builder.initList(elementSize, elementCount * ELEMENTS));
  }
866
  static inline AnyList::Builder init(
867 868 869 870 871 872
      PointerBuilder builder, uint dataWordCount, uint pointerCount, uint elementCount) {
    return AnyList::Builder(builder.initStructList(
        elementCount * ELEMENTS, StructSize(dataWordCount * WORDS, pointerCount * POINTERS)));
  }
};

873 874
}  // namespace _ (private)

Kenton Varda's avatar
Kenton Varda committed
875 876
#if !CAPNP_LITE

877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
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
896 897
#endif  // !CAPNP_LITE

898 899
}  // namespace capnp

900
#endif  // CAPNP_ANY_H_