dynamic.h 60.2 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:
Kenton Varda's avatar
Kenton Varda committed
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:
Kenton Varda's avatar
Kenton Varda committed
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.
Kenton Varda's avatar
Kenton Varda committed
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.
Kenton Varda's avatar
Kenton Varda committed
21 22 23 24 25 26 27 28 29 30 31 32

// This file defines classes that can be used to manipulate messages based on schemas that are not
// known until runtime.  This is also useful for writing generic code that uses schemas to handle
// arbitrary types in a generic way.
//
// Each of the classes defined here has a to() template method which converts an instance back to a
// native type.  This method will throw an exception if the requested type does not match the
// schema.  To convert native types to dynamic, use DynamicFactory.
//
// As always, underlying data is validated lazily, so you have to actually traverse the whole
// message if you want to validate all content.

33
#pragma once
Kenton Varda's avatar
Kenton Varda committed
34

35
#if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
36 37 38
#pragma GCC system_header
#endif

39
#include "schema.h"
Kenton Varda's avatar
Kenton Varda committed
40
#include "layout.h"
Kenton Varda's avatar
Kenton Varda committed
41
#include "message.h"
42
#include "any.h"
43
#include "capability.h"
44
#include <kj/windows-sanity.h>  // work-around macro conflict with `VOID`
Kenton Varda's avatar
Kenton Varda committed
45

46
namespace capnp {
Kenton Varda's avatar
Kenton Varda committed
47 48 49 50 51

class MessageReader;
class MessageBuilder;

struct DynamicValue {
52 53
  DynamicValue() = delete;

54
  enum Type {
55 56 57 58 59
    UNKNOWN,
    // Means that the value has unknown type and content because it comes from a newer version of
    // the schema, or from a newer version of Cap'n Proto that has new features that this version
    // doesn't understand.

60 61 62 63 64 65 66 67 68 69
    VOID,
    BOOL,
    INT,
    UINT,
    FLOAT,
    TEXT,
    DATA,
    LIST,
    ENUM,
    STRUCT,
70
    CAPABILITY,
71
    ANY_POINTER
72 73
  };

Kenton Varda's avatar
Kenton Varda committed
74 75
  class Reader;
  class Builder;
76
  class Pipeline;
Kenton Varda's avatar
Kenton Varda committed
77 78 79
};
class DynamicEnum;
struct DynamicStruct {
80
  DynamicStruct() = delete;
Kenton Varda's avatar
Kenton Varda committed
81 82
  class Reader;
  class Builder;
83
  class Pipeline;
Kenton Varda's avatar
Kenton Varda committed
84 85
};
struct DynamicList {
86
  DynamicList() = delete;
Kenton Varda's avatar
Kenton Varda committed
87 88 89
  class Reader;
  class Builder;
};
90 91 92 93 94
struct DynamicCapability {
  DynamicCapability() = delete;
  class Client;
  class Server;
};
95
template <> class Orphan<DynamicValue>;
Kenton Varda's avatar
Kenton Varda committed
96

97 98 99 100
template <Kind k> struct DynamicTypeFor_;
template <> struct DynamicTypeFor_<Kind::ENUM> { typedef DynamicEnum Type; };
template <> struct DynamicTypeFor_<Kind::STRUCT> { typedef DynamicStruct Type; };
template <> struct DynamicTypeFor_<Kind::LIST> { typedef DynamicList Type; };
101
template <> struct DynamicTypeFor_<Kind::INTERFACE> { typedef DynamicCapability Type; };
102 103 104 105

template <typename T>
using DynamicTypeFor = typename DynamicTypeFor_<kind<T>()>::Type;

Kenton Varda's avatar
Kenton Varda committed
106
template <typename T>
107
ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value);
Kenton Varda's avatar
Kenton Varda committed
108
template <typename T>
109
BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value);
Kenton Varda's avatar
Kenton Varda committed
110
template <typename T>
111
DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value);
112 113
template <typename T>
typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value);
Kenton Varda's avatar
Kenton Varda committed
114

115 116 117 118 119 120 121 122 123 124
namespace _ {  // private

template <> struct Kind_<DynamicValue     > { static constexpr Kind kind = Kind::OTHER; };
template <> struct Kind_<DynamicEnum      > { static constexpr Kind kind = Kind::OTHER; };
template <> struct Kind_<DynamicStruct    > { static constexpr Kind kind = Kind::OTHER; };
template <> struct Kind_<DynamicList      > { static constexpr Kind kind = Kind::OTHER; };
template <> struct Kind_<DynamicCapability> { static constexpr Kind kind = Kind::OTHER; };

}  // namespace _ (private)

125 126 127 128 129 130
template <> inline constexpr Style style<DynamicValue     >() { return Style::POINTER;    }
template <> inline constexpr Style style<DynamicEnum      >() { return Style::PRIMITIVE;  }
template <> inline constexpr Style style<DynamicStruct    >() { return Style::STRUCT;     }
template <> inline constexpr Style style<DynamicList      >() { return Style::POINTER;    }
template <> inline constexpr Style style<DynamicCapability>() { return Style::CAPABILITY; }

Kenton Varda's avatar
Kenton Varda committed
131 132 133 134 135
// -------------------------------------------------------------------

class DynamicEnum {
public:
  DynamicEnum() = default;
136 137
  inline DynamicEnum(EnumSchema::Enumerant enumerant)
      : schema(enumerant.getContainingEnum()), value(enumerant.getOrdinal()) {}
138 139
  inline DynamicEnum(EnumSchema schema, uint16_t value)
      : schema(schema), value(value) {}
Kenton Varda's avatar
Kenton Varda committed
140

141
  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::ENUM>>
Kenton Varda's avatar
Kenton Varda committed
142 143
  inline DynamicEnum(T&& value): DynamicEnum(toDynamic(value)) {}

Kenton Varda's avatar
Kenton Varda committed
144
  template <typename T>
145
  inline T as() const { return static_cast<T>(asImpl(typeId<T>())); }
Kenton Varda's avatar
Kenton Varda committed
146 147
  // Cast to a native enum type.

148
  inline EnumSchema getSchema() const { return schema; }
Kenton Varda's avatar
Kenton Varda committed
149

150
  kj::Maybe<EnumSchema::Enumerant> getEnumerant() const;
Kenton Varda's avatar
Kenton Varda committed
151 152 153 154
  // Get which enumerant this enum value represents.  Returns nullptr if the numeric value does not
  // correspond to any enumerant in the schema -- this can happen if the data was built using a
  // newer schema that has more values defined.

155
  inline uint16_t getRaw() const { return value; }
Kenton Varda's avatar
Kenton Varda committed
156 157 158
  // Returns the raw underlying enum value.

private:
159
  EnumSchema schema;
Kenton Varda's avatar
Kenton Varda committed
160 161
  uint16_t value;

162
  uint16_t asImpl(uint64_t requestedTypeId) const;
Kenton Varda's avatar
Kenton Varda committed
163 164

  friend struct DynamicStruct;
Kenton Varda's avatar
Kenton Varda committed
165
  friend struct DynamicList;
166
  friend struct DynamicValue;
167 168
  template <typename T>
  friend DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value);
Kenton Varda's avatar
Kenton Varda committed
169 170 171 172
};

// -------------------------------------------------------------------

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
enum class HasMode: uint8_t {
  // Specifies the meaning of "has(field)".

  NON_NULL,
  // "has(field)" only returns false if the field is a pointer and the pointer is null. This is the
  // default behavior.

  NON_DEFAULT
  // "has(field)" returns false if the field is set to its default value. This differs from
  // NON_NULL only in the handling of primitive values.
  //
  // "Equal to default value" is technically defined as the field value being encoded as all-zero
  // on the wire (since primitive values are XORed by their defined default value when encoded).
};

Kenton Varda's avatar
Kenton Varda committed
188 189
class DynamicStruct::Reader {
public:
190 191
  typedef DynamicStruct Reads;

Kenton Varda's avatar
Kenton Varda committed
192 193
  Reader() = default;

194
  template <typename T, typename = kj::EnableIf<kind<FromReader<T>>() == Kind::STRUCT>>
Kenton Varda's avatar
Kenton Varda committed
195 196
  inline Reader(T&& value): Reader(toDynamic(value)) {}

197 198
  inline operator AnyStruct::Reader() const { return AnyStruct::Reader(reader); }

199
  inline MessageSize totalSize() const { return reader.totalSize().asPublic(); }
200

Kenton Varda's avatar
Kenton Varda committed
201
  template <typename T>
202
  typename T::Reader as() const;
Kenton Varda's avatar
Kenton Varda committed
203 204
  // Convert the dynamic struct to its compiled-in type.

205
  inline StructSchema getSchema() const { return schema; }
Kenton Varda's avatar
Kenton Varda committed
206

Kenton Varda's avatar
Kenton Varda committed
207 208
  DynamicValue::Reader get(StructSchema::Field field) const;
  // Read the given field value.
Kenton Varda's avatar
Kenton Varda committed
209

210 211 212 213
  bool has(StructSchema::Field field, HasMode mode = HasMode::NON_NULL) const;
  // Tests whether the given field is "present". If the field is a union member and is not the
  // active member, this always returns false. Otherwise, the field's value is interpreted
  // according to `mode`.
Kenton Varda's avatar
Kenton Varda committed
214 215 216 217 218 219 220

  kj::Maybe<StructSchema::Field> which() const;
  // If the struct contains an (unnamed) union, and the currently-active field within that union
  // is known, this returns that field.  Otherwise, it returns null.  In other words, this returns
  // null if there is no union present _or_ if the union's discriminant is set to an unrecognized
  // value.  This could happen in particular when receiving a message from a sender who has a
  // newer version of the protocol and is using a field of the union that you don't know about yet.
221

222
  DynamicValue::Reader get(kj::StringPtr name) const;
223
  bool has(kj::StringPtr name, HasMode mode = HasMode::NON_NULL) const;
Kenton Varda's avatar
Kenton Varda committed
224
  // Shortcuts to access fields by name.  These throw exceptions if no such field exists.
Kenton Varda's avatar
Kenton Varda committed
225 226

private:
227
  StructSchema schema;
228
  _::StructReader reader;
Kenton Varda's avatar
Kenton Varda committed
229

230
  inline Reader(StructSchema schema, _::StructReader reader)
231
      : schema(schema), reader(reader) {}
232
  Reader(StructSchema schema, const _::OrphanBuilder& orphan);
Kenton Varda's avatar
Kenton Varda committed
233

Kenton Varda's avatar
Kenton Varda committed
234 235 236
  bool isSetInUnion(StructSchema::Field field) const;
  void verifySetInUnion(StructSchema::Field field) const;
  static DynamicValue::Reader getImpl(_::StructReader reader, StructSchema::Field field);
Kenton Varda's avatar
Kenton Varda committed
237

Kenton Varda's avatar
Kenton Varda committed
238
  template <typename T, Kind K>
239
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
240 241 242 243
  friend class DynamicStruct::Builder;
  friend struct DynamicList;
  friend class MessageReader;
  friend class MessageBuilder;
244 245
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
246
  friend kj::StringTree _::structString(
247
      _::StructReader reader, const _::RawBrandedSchema& schema);
248
  friend class Orphanage;
249
  friend class Orphan<DynamicStruct>;
250
  friend class Orphan<DynamicValue>;
251
  friend class Orphan<AnyPointer>;
252
  friend class AnyStruct::Reader;
Kenton Varda's avatar
Kenton Varda committed
253 254 255 256
};

class DynamicStruct::Builder {
public:
257 258
  typedef DynamicStruct Builds;

259
  Builder() = default;
260
  inline Builder(decltype(nullptr)) {}
Kenton Varda's avatar
Kenton Varda committed
261

262
  template <typename T, typename = kj::EnableIf<kind<FromBuilder<T>>() == Kind::STRUCT>>
Kenton Varda's avatar
Kenton Varda committed
263 264
  inline Builder(T&& value): Builder(toDynamic(value)) {}

265
  inline operator AnyStruct::Builder() { return AnyStruct::Builder(builder); }
266

267
  inline MessageSize totalSize() const { return asReader().totalSize(); }
268

Kenton Varda's avatar
Kenton Varda committed
269
  template <typename T>
Kenton Varda's avatar
Kenton Varda committed
270
  typename T::Builder as();
Kenton Varda's avatar
Kenton Varda committed
271 272
  // Cast to a particular struct type.

273
  inline StructSchema getSchema() const { return schema; }
Kenton Varda's avatar
Kenton Varda committed
274

Kenton Varda's avatar
Kenton Varda committed
275 276
  DynamicValue::Builder get(StructSchema::Field field);
  // Read the given field value.
277

278 279 280 281 282
  inline bool has(StructSchema::Field field, HasMode mode = HasMode::NON_NULL)
      { return asReader().has(field, mode); }
  // Tests whether the given field is "present". If the field is a union member and is not the
  // active member, this always returns false. Otherwise, the field's value is interpreted
  // according to `mode`.
Kenton Varda's avatar
Kenton Varda committed
283 284 285 286 287 288 289 290 291 292 293 294 295

  kj::Maybe<StructSchema::Field> which();
  // If the struct contains an (unnamed) union, and the currently-active field within that union
  // is known, this returns that field.  Otherwise, it returns null.  In other words, this returns
  // null if there is no union present _or_ if the union's discriminant is set to an unrecognized
  // value.  This could happen in particular when receiving a message from a sender who has a
  // newer version of the protocol and is using a field of the union that you don't know about yet.

  void set(StructSchema::Field field, const DynamicValue::Reader& value);
  // Set the given field value.

  DynamicValue::Builder init(StructSchema::Field field);
  DynamicValue::Builder init(StructSchema::Field field, uint size);
296 297
  // Init a struct, list, or blob field.

298 299 300 301 302
  void adopt(StructSchema::Field field, Orphan<DynamicValue>&& orphan);
  Orphan<DynamicValue> disown(StructSchema::Field field);
  // Adopt/disown.  This works even for non-pointer fields: adopt() becomes equivalent to set()
  // and disown() becomes like get() followed by clear().

Kenton Varda's avatar
Kenton Varda committed
303 304 305 306
  void clear(StructSchema::Field field);
  // Clear a field, setting it to its default value.  For pointer fields, this actually makes the
  // field null.

307
  DynamicValue::Builder get(kj::StringPtr name);
308
  bool has(kj::StringPtr name, HasMode mode = HasMode::NON_NULL);
309 310 311 312
  void set(kj::StringPtr name, const DynamicValue::Reader& value);
  void set(kj::StringPtr name, std::initializer_list<DynamicValue::Reader> value);
  DynamicValue::Builder init(kj::StringPtr name);
  DynamicValue::Builder init(kj::StringPtr name, uint size);
313 314
  void adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan);
  Orphan<DynamicValue> disown(kj::StringPtr name);
Kenton Varda's avatar
Kenton Varda committed
315 316
  void clear(kj::StringPtr name);
  // Shortcuts to access fields by name.  These throw exceptions if no such field exists.
Kenton Varda's avatar
Kenton Varda committed
317

318
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
319 320

private:
321
  StructSchema schema;
322
  _::StructBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
323

324
  inline Builder(StructSchema schema, _::StructBuilder builder)
325
      : schema(schema), builder(builder) {}
326
  Builder(StructSchema schema, _::OrphanBuilder& orphan);
Kenton Varda's avatar
Kenton Varda committed
327

Kenton Varda's avatar
Kenton Varda committed
328 329 330 331
  bool isSetInUnion(StructSchema::Field field);
  void verifySetInUnion(StructSchema::Field field);
  void setInUnion(StructSchema::Field field);

Kenton Varda's avatar
Kenton Varda committed
332
  template <typename T, Kind k>
333
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
334 335 336
  friend struct DynamicList;
  friend class MessageReader;
  friend class MessageBuilder;
337 338
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
339 340
  friend class Orphanage;
  friend class Orphan<DynamicStruct>;
341
  friend class Orphan<DynamicValue>;
342
  friend class Orphan<AnyPointer>;
343
  friend class AnyStruct::Builder;
Kenton Varda's avatar
Kenton Varda committed
344 345
};

346 347 348 349 350 351 352 353 354 355
class DynamicStruct::Pipeline {
public:
  typedef DynamicStruct Pipelines;

  inline Pipeline(decltype(nullptr)): typeless(nullptr) {}

  template <typename T>
  typename T::Pipeline releaseAs();
  // Convert the dynamic pipeline to its compiled-in type.

356
  inline StructSchema getSchema() { return schema; }
357

358
  DynamicValue::Pipeline get(StructSchema::Field field);
359 360
  // Read the given field value.

361
  DynamicValue::Pipeline get(kj::StringPtr name);
362 363 364 365
  // Get by string name.

private:
  StructSchema schema;
366
  AnyPointer::Pipeline typeless;
367

368
  inline explicit Pipeline(StructSchema schema, AnyPointer::Pipeline&& typeless)
369 370 371 372 373
      : schema(schema), typeless(kj::mv(typeless)) {}

  friend class Request<DynamicStruct, DynamicStruct>;
};

Kenton Varda's avatar
Kenton Varda committed
374 375 376 377
// -------------------------------------------------------------------

class DynamicList::Reader {
public:
378 379
  typedef DynamicList Reads;

380
  inline Reader(): reader(ElementSize::VOID) {}
Kenton Varda's avatar
Kenton Varda committed
381

382
  template <typename T, typename = kj::EnableIf<kind<FromReader<T>>() == Kind::LIST>>
Kenton Varda's avatar
Kenton Varda committed
383 384
  inline Reader(T&& value): Reader(toDynamic(value)) {}

385 386
  inline operator AnyList::Reader() const { return AnyList::Reader(reader); }

Kenton Varda's avatar
Kenton Varda committed
387
  template <typename T>
388
  typename T::Reader as() const;
Kenton Varda's avatar
Kenton Varda committed
389 390 391
  // Try to convert to any List<T>, Data, or Text.  Throws an exception if the underlying data
  // can't possibly represent the requested type.

392
  inline ListSchema getSchema() const { return schema; }
393

394
  inline uint size() const { return unbound(reader.size() / ELEMENTS); }
395
  DynamicValue::Reader operator[](uint index) const;
Kenton Varda's avatar
Kenton Varda committed
396

397
  typedef _::IndexingIterator<const Reader, DynamicValue::Reader> Iterator;
398 399
  inline Iterator begin() const { return Iterator(this, 0); }
  inline Iterator end() const { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
400 401

private:
402
  ListSchema schema;
403
  _::ListReader reader;
Kenton Varda's avatar
Kenton Varda committed
404

405
  Reader(ListSchema schema, _::ListReader reader): schema(schema), reader(reader) {}
406
  Reader(ListSchema schema, const _::OrphanBuilder& orphan);
Kenton Varda's avatar
Kenton Varda committed
407

Kenton Varda's avatar
Kenton Varda committed
408
  template <typename T, Kind k>
409
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
410 411
  friend struct DynamicStruct;
  friend class DynamicList::Builder;
412 413
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
414
  friend class Orphanage;
415
  friend class Orphan<DynamicList>;
416
  friend class Orphan<DynamicValue>;
417
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
418 419 420 421
};

class DynamicList::Builder {
public:
422 423
  typedef DynamicList Builds;

424 425
  inline Builder(): builder(ElementSize::VOID) {}
  inline Builder(decltype(nullptr)): builder(ElementSize::VOID) {}
Kenton Varda's avatar
Kenton Varda committed
426

427
  template <typename T, typename = kj::EnableIf<kind<FromBuilder<T>>() == Kind::LIST>>
Kenton Varda's avatar
Kenton Varda committed
428 429
  inline Builder(T&& value): Builder(toDynamic(value)) {}

430 431
  inline operator AnyList::Builder() { return AnyList::Builder(builder); }

Kenton Varda's avatar
Kenton Varda committed
432
  template <typename T>
Kenton Varda's avatar
Kenton Varda committed
433
  typename T::Builder as();
Kenton Varda's avatar
Kenton Varda committed
434 435 436
  // Try to convert to any List<T>, Data, or Text.  Throws an exception if the underlying data
  // can't possibly represent the requested type.

437
  inline ListSchema getSchema() const { return schema; }
438

439
  inline uint size() const { return unbound(builder.size() / ELEMENTS); }
440 441
  DynamicValue::Builder operator[](uint index);
  void set(uint index, const DynamicValue::Reader& value);
Kenton Varda's avatar
Kenton Varda committed
442
  DynamicValue::Builder init(uint index, uint size);
443 444
  void adopt(uint index, Orphan<DynamicValue>&& orphan);
  Orphan<DynamicValue> disown(uint index);
Kenton Varda's avatar
Kenton Varda committed
445

446
  typedef _::IndexingIterator<Builder, DynamicStruct::Builder> Iterator;
447 448
  inline Iterator begin() { return Iterator(this, 0); }
  inline Iterator end() { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
449

450
  void copyFrom(std::initializer_list<DynamicValue::Reader> value);
Kenton Varda's avatar
Kenton Varda committed
451

452
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
453 454

private:
455
  ListSchema schema;
456
  _::ListBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
457

458
  Builder(ListSchema schema, _::ListBuilder builder): schema(schema), builder(builder) {}
459
  Builder(ListSchema schema, _::OrphanBuilder& orphan);
Kenton Varda's avatar
Kenton Varda committed
460

Kenton Varda's avatar
Kenton Varda committed
461
  template <typename T, Kind k>
462
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
463
  friend struct DynamicStruct;
464 465
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
466 467 468 469
  friend class Orphanage;
  template <typename T, Kind k>
  friend struct _::OrphanGetImpl;
  friend class Orphan<DynamicList>;
470
  friend class Orphan<DynamicValue>;
471
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
472 473 474 475
};

// -------------------------------------------------------------------

476 477 478 479 480 481 482 483 484 485 486
class DynamicCapability::Client: public Capability::Client {
public:
  typedef DynamicCapability Calls;
  typedef DynamicCapability Reads;

  Client() = default;

  template <typename T, typename = kj::EnableIf<kind<FromClient<T>>() == Kind::INTERFACE>>
  inline Client(T&& client);

  template <typename T, typename = kj::EnableIf<kj::canConvert<T*, DynamicCapability::Server*>()>>
487
  inline Client(kj::Own<T>&& server);
488 489

  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
490
  typename T::Client as();
491 492 493 494
  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
  typename T::Client releaseAs();
  // Convert to any client type.

495
  Client upcast(InterfaceSchema requestedSchema);
496 497
  // Upcast to a superclass.  Throws an exception if `schema` is not a superclass.

498
  inline InterfaceSchema getSchema() { return schema; }
499 500

  Request<DynamicStruct, DynamicStruct> newRequest(
501
      InterfaceSchema::Method method, kj::Maybe<MessageSize> sizeHint = nullptr);
502
  Request<DynamicStruct, DynamicStruct> newRequest(
503
      kj::StringPtr methodName, kj::Maybe<MessageSize> sizeHint = nullptr);
504 505 506 507

private:
  InterfaceSchema schema;

508
  Client(InterfaceSchema schema, kj::Own<ClientHook>&& hook)
509 510 511
      : Capability::Client(kj::mv(hook)), schema(schema) {}

  template <typename T>
512
  inline Client(InterfaceSchema schema, kj::Own<T>&& server);
513 514 515 516 517 518 519

  friend struct Capability;
  friend struct DynamicStruct;
  friend struct DynamicList;
  friend struct DynamicValue;
  friend class Orphan<DynamicCapability>;
  friend class Orphan<DynamicValue>;
520
  friend class Orphan<AnyPointer>;
521 522 523 524 525 526 527 528 529 530 531 532 533
  template <typename T, Kind k>
  friend struct _::PointerHelpers;
};

class DynamicCapability::Server: public Capability::Server {
public:
  typedef DynamicCapability Serves;

  Server(InterfaceSchema schema): schema(schema) {}

  virtual kj::Promise<void> call(InterfaceSchema::Method method,
                                 CallContext<DynamicStruct, DynamicStruct> context) = 0;

534 535
  DispatchCallResult dispatchCall(uint64_t interfaceId, uint16_t methodId,
                                  CallContext<AnyPointer, AnyPointer> context) override final;
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554

  inline InterfaceSchema getSchema() const { return schema; }

private:
  InterfaceSchema schema;
};

template <>
class Request<DynamicStruct, DynamicStruct>: public DynamicStruct::Builder {
  // Specialization of `Request<T, U>` for DynamicStruct.

public:
  inline Request(DynamicStruct::Builder builder, kj::Own<RequestHook>&& hook,
                 StructSchema resultSchema)
      : DynamicStruct::Builder(builder), hook(kj::mv(hook)), resultSchema(resultSchema) {}

  RemotePromise<DynamicStruct> send();
  // Send the call and return a promise for the results.

555 556 557 558
  kj::Promise<void> sendStreaming();
  // Use when the caller is aware that the response type is StreamResult and wants to invoke
  // streaming behavior. It is an error to call this if the response type is not StreamResult.

559 560 561 562 563 564
private:
  kj::Own<RequestHook> hook;
  StructSchema resultSchema;

  friend class Capability::Client;
  friend struct DynamicCapability;
565 566 567
  template <typename, typename>
  friend class CallContext;
  friend class RequestHook;
568 569 570 571 572 573 574 575 576 577 578 579 580 581
};

template <>
class CallContext<DynamicStruct, DynamicStruct>: public kj::DisallowConstCopy {
  // Wrapper around CallContextHook with a specific return type.
  //
  // Methods of this class may only be called from within the server's event loop, not from other
  // threads.

public:
  explicit CallContext(CallContextHook& hook, StructSchema paramType, StructSchema resultType);

  DynamicStruct::Reader getParams();
  void releaseParams();
582 583
  DynamicStruct::Builder getResults(kj::Maybe<MessageSize> sizeHint = nullptr);
  DynamicStruct::Builder initResults(kj::Maybe<MessageSize> sizeHint = nullptr);
584 585
  void setResults(DynamicStruct::Reader value);
  void adoptResults(Orphan<DynamicStruct>&& value);
586
  Orphanage getResultsOrphanage(kj::Maybe<MessageSize> sizeHint = nullptr);
Kenton Varda's avatar
Kenton Varda committed
587 588
  template <typename SubParams>
  kj::Promise<void> tailCall(Request<SubParams, DynamicStruct>&& tailRequest);
589
  void allowCancellation();
590

591 592 593
  StructSchema getParamsType() const { return paramType; }
  StructSchema getResultsType() const { return resultType; }

594 595 596 597 598 599 600 601 602 603
private:
  CallContextHook* hook;
  StructSchema paramType;
  StructSchema resultType;

  friend class DynamicCapability::Server;
};

// -------------------------------------------------------------------

604
// Make sure ReaderFor<T> and BuilderFor<T> work for DynamicEnum, DynamicStruct, and
Kenton Varda's avatar
Kenton Varda committed
605
// DynamicList, so that we can define DynamicValue::as().
Kenton Varda's avatar
Kenton Varda committed
606

607 608 609 610 611 612 613 614 615
template <> struct ReaderFor_ <DynamicEnum, Kind::OTHER> { typedef DynamicEnum Type; };
template <> struct BuilderFor_<DynamicEnum, Kind::OTHER> { typedef DynamicEnum Type; };
template <> struct ReaderFor_ <DynamicStruct, Kind::OTHER> { typedef DynamicStruct::Reader Type; };
template <> struct BuilderFor_<DynamicStruct, Kind::OTHER> { typedef DynamicStruct::Builder Type; };
template <> struct ReaderFor_ <DynamicList, Kind::OTHER> { typedef DynamicList::Reader Type; };
template <> struct BuilderFor_<DynamicList, Kind::OTHER> { typedef DynamicList::Builder Type; };
template <> struct ReaderFor_ <DynamicCapability, Kind::OTHER> { typedef DynamicCapability::Client Type; };
template <> struct BuilderFor_<DynamicCapability, Kind::OTHER> { typedef DynamicCapability::Client Type; };
template <> struct PipelineFor_<DynamicCapability, Kind::OTHER> { typedef DynamicCapability::Client Type; };
Kenton Varda's avatar
Kenton Varda committed
616 617 618

class DynamicValue::Reader {
public:
619 620
  typedef DynamicValue Reads;

621
  inline Reader(decltype(nullptr) n = nullptr);  // UNKNOWN
622
  inline Reader(Void value);
623 624 625 626 627 628 629 630 631 632 633 634 635 636
  inline Reader(bool value);
  inline Reader(char value);
  inline Reader(signed char value);
  inline Reader(short value);
  inline Reader(int value);
  inline Reader(long value);
  inline Reader(long long value);
  inline Reader(unsigned char value);
  inline Reader(unsigned short value);
  inline Reader(unsigned int value);
  inline Reader(unsigned long value);
  inline Reader(unsigned long long value);
  inline Reader(float value);
  inline Reader(double value);
Kenton Varda's avatar
Kenton Varda committed
637
  inline Reader(const char* value);  // Text
638 639 640
  inline Reader(const Text::Reader& value);
  inline Reader(const Data::Reader& value);
  inline Reader(const DynamicList::Reader& value);
641
  inline Reader(DynamicEnum value);
642
  inline Reader(const DynamicStruct::Reader& value);
643
  inline Reader(const AnyPointer::Reader& value);
644
  inline Reader(DynamicCapability::Client& value);
645 646 647
  inline Reader(DynamicCapability::Client&& value);
  template <typename T, typename = kj::EnableIf<kj::canConvert<T*, DynamicCapability::Server*>()>>
  inline Reader(kj::Own<T>&& value);
648
  Reader(ConstSchema constant);
Kenton Varda's avatar
Kenton Varda committed
649

Kenton Varda's avatar
Kenton Varda committed
650
  template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
651 652 653
  inline Reader(T&& value): Reader(toDynamic(kj::mv(value))) {}

  Reader(const Reader& other);
Kenton Varda's avatar
Kenton Varda committed
654 655
  Reader(Reader&& other) noexcept;
  ~Reader() noexcept(false);
656 657 658 659
  Reader& operator=(const Reader& other);
  Reader& operator=(Reader&& other);
  // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not
  // trivially copyable.
Kenton Varda's avatar
Kenton Varda committed
660 661

  template <typename T>
662
  inline ReaderFor<T> as() const { return AsImpl<T>::apply(*this); }
663
  // Use to interpret the value as some Cap'n Proto type.  Allowed types are:
Kenton Varda's avatar
Kenton Varda committed
664
  // - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum:  Returns the raw value.
665
  // - Text, Data, AnyPointer, any struct type:  Returns the corresponding Reader.
Kenton Varda's avatar
Kenton Varda committed
666
  // - List<T> for any T listed above:  Returns List<T>::Reader.
667
  // - DynamicEnum:  Returns the corresponding type.
Kenton Varda's avatar
Kenton Varda committed
668
  // - DynamicStruct, DynamicList:  Returns the corresponding Reader.
669
  // - Any capability type, including DynamicCapability:  Returns the corresponding Client.
670
  // - DynamicValue:  Returns an identical Reader. Useful to avoid special-casing in generic code.
671 672
  //   (TODO(perf):  On GCC 4.8 / Clang 3.3, provide rvalue-qualified version that avoids
  //   refcounting.)
673
  //
674
  // DynamicValue allows various implicit conversions, mostly just to make the interface friendlier.
675 676 677 678 679 680 681
  // - Any integer can be converted to any other integer type so long as the actual value is within
  //   the new type's range.
  // - Floating-point types can be converted to integers as long as no information would be lost
  //   in the conversion.
  // - Integers can be converted to floating points.  This may lose information, but won't throw.
  // - Float32/Float64 can be converted between each other.  Converting Float64 -> Float32 may lose
  //   information, but won't throw.
682 683
  // - Text can be converted to an enum, if the Text matches one of the enumerant names (but not
  //   vice-versa).
684
  // - Capabilities can be upcast (cast to a supertype), but not downcast.
685 686
  //
  // Any other conversion attempt will throw an exception.
Kenton Varda's avatar
Kenton Varda committed
687

688
  inline Type getType() const { return type; }
Kenton Varda's avatar
Kenton Varda committed
689 690 691
  // Get the type of this value.

private:
692
  Type type;
Kenton Varda's avatar
Kenton Varda committed
693 694 695 696

  union {
    Void voidValue;
    bool boolValue;
697 698 699
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
700 701 702 703 704
    Text::Reader textValue;
    Data::Reader dataValue;
    DynamicList::Reader listValue;
    DynamicEnum enumValue;
    DynamicStruct::Reader structValue;
705
    AnyPointer::Reader anyPointerValue;
706 707 708

    mutable DynamicCapability::Client capabilityValue;
    // Declared mutable because `Client`s normally cannot be const.
709 710 711

    // Warning:  Copy/move constructors assume all these types are trivially copyable except
    //   Capability.
Kenton Varda's avatar
Kenton Varda committed
712 713
  };

714
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
715
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
716
  // specialization.  Has a method apply() which does the work.
717 718

  friend class Orphanage;  // to speed up newOrphanCopy(DynamicValue::Reader)
Kenton Varda's avatar
Kenton Varda committed
719 720 721 722
};

class DynamicValue::Builder {
public:
723 724
  typedef DynamicValue Builds;

725
  inline Builder(decltype(nullptr) n = nullptr);  // UNKNOWN
726
  inline Builder(Void value);
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
  inline Builder(bool value);
  inline Builder(char value);
  inline Builder(signed char value);
  inline Builder(short value);
  inline Builder(int value);
  inline Builder(long value);
  inline Builder(long long value);
  inline Builder(unsigned char value);
  inline Builder(unsigned short value);
  inline Builder(unsigned int value);
  inline Builder(unsigned long value);
  inline Builder(unsigned long long value);
  inline Builder(float value);
  inline Builder(double value);
  inline Builder(Text::Builder value);
  inline Builder(Data::Builder value);
  inline Builder(DynamicList::Builder value);
  inline Builder(DynamicEnum value);
  inline Builder(DynamicStruct::Builder value);
746
  inline Builder(AnyPointer::Builder value);
747
  inline Builder(DynamicCapability::Client& value);
748
  inline Builder(DynamicCapability::Client&& value);
Kenton Varda's avatar
Kenton Varda committed
749

Kenton Varda's avatar
Kenton Varda committed
750
  template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
751 752
  inline Builder(T value): Builder(toDynamic(value)) {}

753
  Builder(Builder& other);
Kenton Varda's avatar
Kenton Varda committed
754 755
  Builder(Builder&& other) noexcept;
  ~Builder() noexcept(false);
756 757 758 759 760
  Builder& operator=(Builder& other);
  Builder& operator=(Builder&& other);
  // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not
  // trivially copyable.

Kenton Varda's avatar
Kenton Varda committed
761
  template <typename T>
762
  inline BuilderFor<T> as() { return AsImpl<T>::apply(*this); }
Kenton Varda's avatar
Kenton Varda committed
763
  // See DynamicValue::Reader::as().
Kenton Varda's avatar
Kenton Varda committed
764

765
  inline Type getType() { return type; }
Kenton Varda's avatar
Kenton Varda committed
766 767
  // Get the type of this value.

768
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
769 770

private:
771
  Type type;
Kenton Varda's avatar
Kenton Varda committed
772 773 774 775

  union {
    Void voidValue;
    bool boolValue;
776 777 778
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
779 780 781 782 783
    Text::Builder textValue;
    Data::Builder dataValue;
    DynamicList::Builder listValue;
    DynamicEnum enumValue;
    DynamicStruct::Builder structValue;
784
    AnyPointer::Builder anyPointerValue;
785 786 787

    mutable DynamicCapability::Client capabilityValue;
    // Declared mutable because `Client`s normally cannot be const.
Kenton Varda's avatar
Kenton Varda committed
788 789
  };

790
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
791
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
792
  // specialization.  Has a method apply() which does the work.
793 794

  friend class Orphan<DynamicValue>;
Kenton Varda's avatar
Kenton Varda committed
795 796
};

797 798 799 800
class DynamicValue::Pipeline {
public:
  typedef DynamicValue Pipelines;

801
  inline Pipeline(decltype(nullptr) n = nullptr);
802 803 804
  inline Pipeline(DynamicStruct::Pipeline&& value);
  inline Pipeline(DynamicCapability::Client&& value);

805
  Pipeline(Pipeline&& other) noexcept;
806 807 808 809 810 811
  Pipeline& operator=(Pipeline&& other);
  ~Pipeline() noexcept(false);

  template <typename T>
  inline PipelineFor<T> releaseAs() { return AsImpl<T>::apply(*this); }

812 813 814
  inline Type getType() { return type; }
  // Get the type of this value.

815 816 817 818 819 820 821 822 823 824 825 826
private:
  Type type;
  union {
    DynamicStruct::Pipeline structValue;
    DynamicCapability::Client capabilityValue;
  };

  template <typename T, Kind kind = kind<T>()> struct AsImpl;
  // Implementation backing the releaseAs() method.  Needs to be a struct to allow partial
  // specialization.  Has a method apply() which does the work.
};

827 828 829 830 831 832 833
kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value);
kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value);
kj::StringTree KJ_STRINGIFY(DynamicEnum value);
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value);
kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value);
kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value);
kj::StringTree KJ_STRINGIFY(const DynamicList::Builder& value);
Kenton Varda's avatar
Kenton Varda committed
834

835 836 837 838 839 840 841 842 843 844 845
// -------------------------------------------------------------------
// Orphan <-> Dynamic glue

template <>
class Orphan<DynamicStruct> {
public:
  Orphan() = default;
  KJ_DISALLOW_COPY(Orphan);
  Orphan(Orphan&&) = default;
  Orphan& operator=(Orphan&&) = default;

846 847 848
  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::STRUCT>>
  inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {}

849
  DynamicStruct::Builder get();
850
  DynamicStruct::Reader getReader() const;
851

852 853 854 855 856 857 858 859
  template <typename T>
  Orphan<T> releaseAs();
  // Like DynamicStruct::Builder::as(), but coerces the Orphan type.  Since Orphans are move-only,
  // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is
  // transferred to the returned Orphan<T>.

  inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
  inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
860 861 862 863 864 865 866 867 868 869 870 871

private:
  StructSchema schema;
  _::OrphanBuilder builder;

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

  template <typename, Kind>
  friend struct _::PointerHelpers;
  friend struct DynamicList;
  friend class Orphanage;
872
  friend class Orphan<DynamicValue>;
873
  friend class Orphan<AnyPointer>;
874
  friend class MessageBuilder;
875 876 877 878 879 880 881 882 883 884
};

template <>
class Orphan<DynamicList> {
public:
  Orphan() = default;
  KJ_DISALLOW_COPY(Orphan);
  Orphan(Orphan&&) = default;
  Orphan& operator=(Orphan&&) = default;

885 886 887
  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::LIST>>
  inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {}

888
  DynamicList::Builder get();
889
  DynamicList::Reader getReader() const;
890

891 892 893 894 895 896
  template <typename T>
  Orphan<T> releaseAs();
  // Like DynamicList::Builder::as(), but coerces the Orphan type.  Since Orphans are move-only,
  // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is
  // transferred to the returned Orphan<T>.

897 898
  // TODO(someday): Support truncate().

899 900
  inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
  inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
901 902 903 904 905 906 907 908 909 910 911 912

private:
  ListSchema schema;
  _::OrphanBuilder builder;

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

  template <typename, Kind>
  friend struct _::PointerHelpers;
  friend struct DynamicList;
  friend class Orphanage;
913
  friend class Orphan<DynamicValue>;
914
  friend class Orphan<AnyPointer>;
915 916
};

917 918 919 920 921 922 923 924
template <>
class Orphan<DynamicCapability> {
public:
  Orphan() = default;
  KJ_DISALLOW_COPY(Orphan);
  Orphan(Orphan&&) = default;
  Orphan& operator=(Orphan&&) = default;

925 926 927
  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
  inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {}

928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951
  DynamicCapability::Client get();
  DynamicCapability::Client getReader() const;

  template <typename T>
  Orphan<T> releaseAs();
  // Like DynamicCapability::Client::as(), but coerces the Orphan type.  Since Orphans are move-only,
  // the original Orphan<DynamicCapability> is no longer valid after this call; ownership is
  // transferred to the returned Orphan<T>.

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

private:
  InterfaceSchema schema;
  _::OrphanBuilder builder;

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

  template <typename, Kind>
  friend struct _::PointerHelpers;
  friend struct DynamicList;
  friend class Orphanage;
  friend class Orphan<DynamicValue>;
952
  friend class Orphan<AnyPointer>;
953 954
};

955 956 957
template <>
class Orphan<DynamicValue> {
public:
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974
  inline Orphan(decltype(nullptr) n = nullptr): type(DynamicValue::UNKNOWN) {}
  inline Orphan(Void value);
  inline Orphan(bool value);
  inline Orphan(char value);
  inline Orphan(signed char value);
  inline Orphan(short value);
  inline Orphan(int value);
  inline Orphan(long value);
  inline Orphan(long long value);
  inline Orphan(unsigned char value);
  inline Orphan(unsigned short value);
  inline Orphan(unsigned int value);
  inline Orphan(unsigned long value);
  inline Orphan(unsigned long long value);
  inline Orphan(float value);
  inline Orphan(double value);
  inline Orphan(DynamicEnum value);
975 976 977
  Orphan(Orphan&&) = default;
  template <typename T>
  Orphan(Orphan<T>&&);
978
  Orphan(Orphan<AnyPointer>&&);
979
  Orphan(void*) = delete;  // So Orphan(bool) doesn't accept pointers.
980 981
  KJ_DISALLOW_COPY(Orphan);

982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
  Orphan& operator=(Orphan&&) = default;

  inline DynamicValue::Type getType() { return type; }

  DynamicValue::Builder get();
  DynamicValue::Reader getReader() const;

  template <typename T>
  Orphan<T> releaseAs();
  // Like DynamicValue::Builder::as(), but coerces the Orphan type.  Since Orphans are move-only,
  // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is
  // transferred to the returned Orphan<T>.

private:
  DynamicValue::Type type;
  union {
    Void voidValue;
    bool boolValue;
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
    DynamicEnum enumValue;
    StructSchema structSchema;
    ListSchema listSchema;
1006
    InterfaceSchema interfaceSchema;
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
  };

  _::OrphanBuilder builder;
  // Only used if `type` is a pointer type.

  Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder);
  Orphan(DynamicValue::Type type, _::OrphanBuilder&& builder)
      : type(type), builder(kj::mv(builder)) {}
  Orphan(StructSchema structSchema, _::OrphanBuilder&& builder)
      : type(DynamicValue::STRUCT), structSchema(structSchema), builder(kj::mv(builder)) {}
  Orphan(ListSchema listSchema, _::OrphanBuilder&& builder)
      : type(DynamicValue::LIST), listSchema(listSchema), builder(kj::mv(builder)) {}

  template <typename, Kind>
  friend struct _::PointerHelpers;
  friend struct DynamicStruct;
  friend struct DynamicList;
1024
  friend struct AnyPointer;
1025 1026 1027 1028
  friend class Orphanage;
};

template <typename T>
1029
inline Orphan<DynamicValue>::Orphan(Orphan<T>&& other)
1030 1031
    : Orphan(other.get(), kj::mv(other.builder)) {}

1032 1033
inline Orphan<DynamicValue>::Orphan(Orphan<AnyPointer>&& other)
    : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {}
1034

1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
template <typename T>
Orphan<T> Orphan<DynamicStruct>::releaseAs() {
  get().as<T>();  // type check
  return Orphan<T>(kj::mv(builder));
}

template <typename T>
Orphan<T> Orphan<DynamicList>::releaseAs() {
  get().as<T>();  // type check
  return Orphan<T>(kj::mv(builder));
}

1047 1048 1049 1050 1051 1052
template <typename T>
Orphan<T> Orphan<DynamicCapability>::releaseAs() {
  get().as<T>();  // type check
  return Orphan<T>(kj::mv(builder));
}

1053 1054 1055
template <typename T>
Orphan<T> Orphan<DynamicValue>::releaseAs() {
  get().as<T>();  // type check
1056
  type = DynamicValue::UNKNOWN;
1057 1058 1059
  return Orphan<T>(kj::mv(builder));
}

1060
template <>
1061
Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>();
1062 1063 1064 1065
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>();
template <>
Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>();
1066 1067
template <>
Orphan<DynamicCapability> Orphan<DynamicValue>::releaseAs<DynamicCapability>();
1068

1069
template <>
1070
struct Orphanage::GetInnerBuilder<DynamicStruct, Kind::OTHER> {
1071 1072 1073 1074 1075 1076
  static inline _::StructBuilder apply(DynamicStruct::Builder& t) {
    return t.builder;
  }
};

template <>
1077
struct Orphanage::GetInnerBuilder<DynamicList, Kind::OTHER> {
1078 1079 1080 1081 1082 1083 1084
  static inline _::ListBuilder apply(DynamicList::Builder& t) {
    return t.builder;
  }
};

template <>
inline Orphan<DynamicStruct> Orphanage::newOrphanCopy<DynamicStruct::Reader>(
1085
    DynamicStruct::Reader copyFrom) const {
1086
  return Orphan<DynamicStruct>(
1087
      copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.reader));
1088 1089 1090 1091
}

template <>
inline Orphan<DynamicList> Orphanage::newOrphanCopy<DynamicList::Reader>(
1092
    DynamicList::Reader copyFrom) const {
1093 1094
  return Orphan<DynamicList>(copyFrom.getSchema(),
      _::OrphanBuilder::copy(arena, capTable, copyFrom.reader));
1095 1096
}

1097 1098
template <>
inline Orphan<DynamicCapability> Orphanage::newOrphanCopy<DynamicCapability::Client>(
1099
    DynamicCapability::Client copyFrom) const {
1100
  return Orphan<DynamicCapability>(
1101
      copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.hook->addRef()));
1102 1103
}

1104 1105
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
1106
    DynamicValue::Reader copyFrom) const;
1107

1108
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
1109 1110

template <>
1111
struct PointerHelpers<DynamicStruct, Kind::OTHER> {
1112
  // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1113 1114
  // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we
  // don't want people to accidentally be able to provide their own default value.
1115 1116 1117 1118 1119 1120
  static DynamicStruct::Reader getDynamic(PointerReader reader, StructSchema schema);
  static DynamicStruct::Builder getDynamic(PointerBuilder builder, StructSchema schema);
  static void set(PointerBuilder builder, const DynamicStruct::Reader& value);
  static DynamicStruct::Builder init(PointerBuilder builder, StructSchema schema);
  static inline void adopt(PointerBuilder builder, Orphan<DynamicStruct>&& value) {
    builder.adopt(kj::mv(value.builder));
1121
  }
1122 1123
  static inline Orphan<DynamicStruct> disown(PointerBuilder builder, StructSchema schema) {
    return Orphan<DynamicStruct>(schema, builder.disown());
1124
  }
Kenton Varda's avatar
Kenton Varda committed
1125 1126 1127
};

template <>
1128
struct PointerHelpers<DynamicList, Kind::OTHER> {
1129
  // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1130 1131
  // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we
  // don't want people to accidentally be able to provide their own default value.
1132 1133 1134 1135 1136 1137
  static DynamicList::Reader getDynamic(PointerReader reader, ListSchema schema);
  static DynamicList::Builder getDynamic(PointerBuilder builder, ListSchema schema);
  static void set(PointerBuilder builder, const DynamicList::Reader& value);
  static DynamicList::Builder init(PointerBuilder builder, ListSchema schema, uint size);
  static inline void adopt(PointerBuilder builder, Orphan<DynamicList>&& value) {
    builder.adopt(kj::mv(value.builder));
1138
  }
1139 1140
  static inline Orphan<DynamicList> disown(PointerBuilder builder, ListSchema schema) {
    return Orphan<DynamicList>(schema, builder.disown());
1141
  }
Kenton Varda's avatar
Kenton Varda committed
1142 1143
};

1144
template <>
1145
struct PointerHelpers<DynamicCapability, Kind::OTHER> {
1146
  // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1147 1148 1149 1150
  // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we
  // don't want people to accidentally be able to provide their own default value.
  static DynamicCapability::Client getDynamic(PointerReader reader, InterfaceSchema schema);
  static DynamicCapability::Client getDynamic(PointerBuilder builder, InterfaceSchema schema);
1151
  static void set(PointerBuilder builder, DynamicCapability::Client& value);
1152 1153 1154 1155 1156 1157 1158 1159 1160
  static void set(PointerBuilder builder, DynamicCapability::Client&& value);
  static inline void adopt(PointerBuilder builder, Orphan<DynamicCapability>&& value) {
    builder.adopt(kj::mv(value.builder));
  }
  static inline Orphan<DynamicCapability> disown(PointerBuilder builder, InterfaceSchema schema) {
    return Orphan<DynamicCapability>(schema, builder.disown());
  }
};

1161
}  // namespace _ (private)
Kenton Varda's avatar
Kenton Varda committed
1162

1163
template <typename T>
1164
inline ReaderFor<T> AnyPointer::Reader::getAs(StructSchema schema) const {
1165 1166 1167
  return _::PointerHelpers<T>::getDynamic(reader, schema);
}
template <typename T>
1168
inline ReaderFor<T> AnyPointer::Reader::getAs(ListSchema schema) const {
1169 1170 1171
  return _::PointerHelpers<T>::getDynamic(reader, schema);
}
template <typename T>
1172
inline ReaderFor<T> AnyPointer::Reader::getAs(InterfaceSchema schema) const {
1173 1174 1175
  return _::PointerHelpers<T>::getDynamic(reader, schema);
}
template <typename T>
1176
inline BuilderFor<T> AnyPointer::Builder::getAs(StructSchema schema) {
1177 1178 1179
  return _::PointerHelpers<T>::getDynamic(builder, schema);
}
template <typename T>
1180
inline BuilderFor<T> AnyPointer::Builder::getAs(ListSchema schema) {
1181 1182 1183
  return _::PointerHelpers<T>::getDynamic(builder, schema);
}
template <typename T>
1184
inline BuilderFor<T> AnyPointer::Builder::getAs(InterfaceSchema schema) {
1185 1186 1187
  return _::PointerHelpers<T>::getDynamic(builder, schema);
}
template <typename T>
1188
inline BuilderFor<T> AnyPointer::Builder::initAs(StructSchema schema) {
1189 1190 1191
  return _::PointerHelpers<T>::init(builder, schema);
}
template <typename T>
1192
inline BuilderFor<T> AnyPointer::Builder::initAs(ListSchema schema, uint elementCount) {
1193 1194 1195
  return _::PointerHelpers<T>::init(builder, schema, elementCount);
}
template <>
1196
inline void AnyPointer::Builder::setAs<DynamicStruct>(DynamicStruct::Reader value) {
1197 1198 1199
  return _::PointerHelpers<DynamicStruct>::set(builder, value);
}
template <>
1200
inline void AnyPointer::Builder::setAs<DynamicList>(DynamicList::Reader value) {
1201 1202 1203
  return _::PointerHelpers<DynamicList>::set(builder, value);
}
template <>
1204
inline void AnyPointer::Builder::setAs<DynamicCapability>(DynamicCapability::Client value) {
1205 1206 1207
  return _::PointerHelpers<DynamicCapability>::set(builder, kj::mv(value));
}
template <>
1208
void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan);
1209
template <typename T>
1210
inline Orphan<T> AnyPointer::Builder::disownAs(StructSchema schema) {
1211 1212 1213
  return _::PointerHelpers<T>::disown(builder, schema);
}
template <typename T>
1214
inline Orphan<T> AnyPointer::Builder::disownAs(ListSchema schema) {
1215 1216
  return _::PointerHelpers<T>::disown(builder, schema);
}
1217
template <typename T>
1218
inline Orphan<T> AnyPointer::Builder::disownAs(InterfaceSchema schema) {
1219 1220
  return _::PointerHelpers<T>::disown(builder, schema);
}
1221

1222 1223
// We have to declare the methods below inline because Clang and GCC disagree about how to mangle
// their symbol names.
1224
template <>
1225 1226 1227
inline DynamicStruct::Builder Orphan<AnyPointer>::getAs<DynamicStruct>(StructSchema schema) {
  return DynamicStruct::Builder(schema, builder);
}
1228
template <>
1229 1230 1231 1232
inline DynamicStruct::Reader Orphan<AnyPointer>::getAsReader<DynamicStruct>(
    StructSchema schema) const {
  return DynamicStruct::Reader(schema, builder);
}
1233
template <>
1234 1235 1236
inline Orphan<DynamicStruct> Orphan<AnyPointer>::releaseAs<DynamicStruct>(StructSchema schema) {
  return Orphan<DynamicStruct>(schema, kj::mv(builder));
}
1237
template <>
1238 1239 1240
inline DynamicList::Builder Orphan<AnyPointer>::getAs<DynamicList>(ListSchema schema) {
  return DynamicList::Builder(schema, builder);
}
1241
template <>
1242 1243 1244
inline DynamicList::Reader Orphan<AnyPointer>::getAsReader<DynamicList>(ListSchema schema) const {
  return DynamicList::Reader(schema, builder);
}
1245
template <>
1246 1247 1248
inline Orphan<DynamicList> Orphan<AnyPointer>::releaseAs<DynamicList>(ListSchema schema) {
  return Orphan<DynamicList>(schema, kj::mv(builder));
}
1249
template <>
1250 1251 1252 1253
inline DynamicCapability::Client Orphan<AnyPointer>::getAs<DynamicCapability>(
    InterfaceSchema schema) {
  return DynamicCapability::Client(schema, builder.asCapability());
}
1254
template <>
1255 1256 1257 1258
inline DynamicCapability::Client Orphan<AnyPointer>::getAsReader<DynamicCapability>(
    InterfaceSchema schema) const {
  return DynamicCapability::Client(schema, builder.asCapability());
}
1259
template <>
1260 1261 1262 1263
inline Orphan<DynamicCapability> Orphan<AnyPointer>::releaseAs<DynamicCapability>(
    InterfaceSchema schema) {
  return Orphan<DynamicCapability>(schema, kj::mv(builder));
}
1264

Kenton Varda's avatar
Kenton Varda committed
1265
// =======================================================================================
Kenton Varda's avatar
Kenton Varda committed
1266
// Inline implementation details.
Kenton Varda's avatar
Kenton Varda committed
1267

1268
template <typename T>
1269
struct ToDynamic_<T, Kind::STRUCT> {
1270
  static inline DynamicStruct::Reader apply(const typename T::Reader& value) {
1271
    return DynamicStruct::Reader(Schema::from<T>(), value._reader);
1272
  }
1273
  static inline DynamicStruct::Builder apply(typename T::Builder& value) {
1274
    return DynamicStruct::Builder(Schema::from<T>(), value._builder);
1275 1276 1277 1278
  }
};

template <typename T>
1279
struct ToDynamic_<T, Kind::LIST> {
1280
  static inline DynamicList::Reader apply(const typename T::Reader& value) {
1281
    return DynamicList::Reader(Schema::from<T>(), value.reader);
1282
  }
1283
  static inline DynamicList::Builder apply(typename T::Builder& value) {
1284
    return DynamicList::Builder(Schema::from<T>(), value.builder);
1285 1286 1287
  }
};

1288 1289
template <typename T>
struct ToDynamic_<T, Kind::INTERFACE> {
1290 1291
  static inline DynamicCapability::Client apply(typename T::Client value) {
    return DynamicCapability::Client(kj::mv(value));
1292 1293 1294 1295 1296 1297
  }
  static inline DynamicCapability::Client apply(typename T::Client&& value) {
    return DynamicCapability::Client(kj::mv(value));
  }
};

1298
template <typename T>
1299 1300
ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromReader<T>>::apply(value);
1301 1302
}
template <typename T>
1303 1304
BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromBuilder<T>>::apply(value);
1305
}
1306
template <typename T>
1307
DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) {
1308
  return DynamicEnum(Schema::from<kj::Decay<T>>(), static_cast<uint16_t>(value));
1309
}
1310 1311 1312 1313
template <typename T>
typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value) {
  return typename FromServer<T>::Client(kj::mv(value));
}
1314

1315 1316 1317
inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {}
inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {}

1318
#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
1319 1320 1321
inline DynamicValue::Reader::Reader(cppType value) \
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType value) \
1322 1323 1324
    : type(typeTag), fieldName##Value(value) {} \
inline Orphan<DynamicValue>::Orphan(cppType value) \
    : type(DynamicValue::typeTag), fieldName##Value(value) {}
1325

Kenton Varda's avatar
Kenton Varda committed
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Void, VOID, void);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(bool, BOOL, bool);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(char, INT, int);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(signed char, INT, int);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(short, INT, int);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(int, INT, int);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long, INT, int);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long long, INT, int);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned char, UINT, uint);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned short, UINT, uint);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned int, UINT, uint);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long, UINT, uint);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long long, UINT, uint);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(float, FLOAT, float);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(double, FLOAT, float);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicEnum, ENUM, enum);
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR

#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
1345
inline DynamicValue::Reader::Reader(const cppType::Reader& value) \
1346 1347 1348 1349
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType::Builder value) \
    : type(typeTag), fieldName##Value(value) {}

Kenton Varda's avatar
Kenton Varda committed
1350 1351 1352 1353
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Text, TEXT, text);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Data, DATA, data);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicList, LIST, list);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicStruct, STRUCT, struct);
1354
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(AnyPointer, ANY_POINTER, anyPointer);
1355

Kenton Varda's avatar
Kenton Varda committed
1356
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
1357

1358
inline DynamicValue::Reader::Reader(DynamicCapability::Client& value)
1359 1360 1361 1362 1363 1364
    : type(CAPABILITY), capabilityValue(value) {}
inline DynamicValue::Reader::Reader(DynamicCapability::Client&& value)
    : type(CAPABILITY), capabilityValue(kj::mv(value)) {}
template <typename T, typename>
inline DynamicValue::Reader::Reader(kj::Own<T>&& value)
    : type(CAPABILITY), capabilityValue(kj::mv(value)) {}
1365
inline DynamicValue::Builder::Builder(DynamicCapability::Client& value)
1366 1367 1368 1369
    : type(CAPABILITY), capabilityValue(value) {}
inline DynamicValue::Builder::Builder(DynamicCapability::Client&& value)
    : type(CAPABILITY), capabilityValue(kj::mv(value)) {}

Kenton Varda's avatar
Kenton Varda committed
1370 1371
inline DynamicValue::Reader::Reader(const char* value): Reader(Text::Reader(value)) {}

1372
#define CAPNP_DECLARE_TYPE(discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1373
template <> \
1374
struct DynamicValue::Reader::AsImpl<typeName> { \
1375
  static ReaderFor<typeName> apply(const Reader& reader); \
Kenton Varda's avatar
Kenton Varda committed
1376 1377
}; \
template <> \
1378
struct DynamicValue::Builder::AsImpl<typeName> { \
1379
  static BuilderFor<typeName> apply(Builder& builder); \
Kenton Varda's avatar
Kenton Varda committed
1380 1381
};

1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
//CAPNP_DECLARE_TYPE(VOID, Void)
CAPNP_DECLARE_TYPE(BOOL, bool)
CAPNP_DECLARE_TYPE(INT8, int8_t)
CAPNP_DECLARE_TYPE(INT16, int16_t)
CAPNP_DECLARE_TYPE(INT32, int32_t)
CAPNP_DECLARE_TYPE(INT64, int64_t)
CAPNP_DECLARE_TYPE(UINT8, uint8_t)
CAPNP_DECLARE_TYPE(UINT16, uint16_t)
CAPNP_DECLARE_TYPE(UINT32, uint32_t)
CAPNP_DECLARE_TYPE(UINT64, uint64_t)
CAPNP_DECLARE_TYPE(FLOAT32, float)
CAPNP_DECLARE_TYPE(FLOAT64, double)

CAPNP_DECLARE_TYPE(TEXT, Text)
CAPNP_DECLARE_TYPE(DATA, Data)
CAPNP_DECLARE_TYPE(LIST, DynamicList)
CAPNP_DECLARE_TYPE(STRUCT, DynamicStruct)
CAPNP_DECLARE_TYPE(INTERFACE, DynamicCapability)
CAPNP_DECLARE_TYPE(ENUM, DynamicEnum)
CAPNP_DECLARE_TYPE(ANY_POINTER, AnyPointer)
Kenton Varda's avatar
Kenton Varda committed
1402 1403 1404
#undef CAPNP_DECLARE_TYPE

// CAPNP_DECLARE_TYPE(Void) causes gcc 4.7 to segfault.  If I do it manually and remove the
Kenton Varda's avatar
Kenton Varda committed
1405 1406
// ReaderFor<> and BuilderFor<> wrappers, it works.
template <>
1407
struct DynamicValue::Reader::AsImpl<Void> {
1408
  static Void apply(const Reader& reader);
Kenton Varda's avatar
Kenton Varda committed
1409 1410
};
template <>
1411
struct DynamicValue::Builder::AsImpl<Void> {
1412
  static Void apply(Builder& builder);
Kenton Varda's avatar
Kenton Varda committed
1413 1414 1415
};

template <typename T>
1416
struct DynamicValue::Reader::AsImpl<T, Kind::ENUM> {
1417
  static T apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1418
    return reader.as<DynamicEnum>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1419 1420 1421
  }
};
template <typename T>
1422
struct DynamicValue::Builder::AsImpl<T, Kind::ENUM> {
1423
  static T apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1424
    return builder.as<DynamicEnum>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1425 1426 1427 1428
  }
};

template <typename T>
1429
struct DynamicValue::Reader::AsImpl<T, Kind::STRUCT> {
1430
  static typename T::Reader apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1431
    return reader.as<DynamicStruct>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1432 1433 1434
  }
};
template <typename T>
1435
struct DynamicValue::Builder::AsImpl<T, Kind::STRUCT> {
1436
  static typename T::Builder apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1437
    return builder.as<DynamicStruct>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1438 1439 1440 1441
  }
};

template <typename T>
1442
struct DynamicValue::Reader::AsImpl<T, Kind::LIST> {
1443
  static typename T::Reader apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1444
    return reader.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1445 1446 1447
  }
};
template <typename T>
1448
struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
1449
  static typename T::Builder apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1450
    return builder.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1451 1452 1453
  }
};

1454 1455
template <typename T>
struct DynamicValue::Reader::AsImpl<T, Kind::INTERFACE> {
1456
  static typename T::Client apply(const Reader& reader) {
1457 1458 1459 1460 1461 1462 1463 1464 1465 1466
    return reader.as<DynamicCapability>().as<T>();
  }
};
template <typename T>
struct DynamicValue::Builder::AsImpl<T, Kind::INTERFACE> {
  static typename T::Client apply(Builder& builder) {
    return builder.as<DynamicCapability>().as<T>();
  }
};

1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479
template <>
struct DynamicValue::Reader::AsImpl<DynamicValue> {
  static DynamicValue::Reader apply(const Reader& reader) {
    return reader;
  }
};
template <>
struct DynamicValue::Builder::AsImpl<DynamicValue> {
  static DynamicValue::Builder apply(Builder& builder) {
    return builder;
  }
};

1480
inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {}
1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
inline DynamicValue::Pipeline::Pipeline(DynamicStruct::Pipeline&& value)
    : type(STRUCT), structValue(kj::mv(value)) {}
inline DynamicValue::Pipeline::Pipeline(DynamicCapability::Client&& value)
    : type(CAPABILITY), capabilityValue(kj::mv(value)) {}

template <typename T>
struct DynamicValue::Pipeline::AsImpl<T, Kind::STRUCT> {
  static typename T::Pipeline apply(Pipeline& pipeline) {
    return pipeline.releaseAs<DynamicStruct>().releaseAs<T>();
  }
};
template <typename T>
struct DynamicValue::Pipeline::AsImpl<T, Kind::INTERFACE> {
  static typename T::Client apply(Pipeline& pipeline) {
    return pipeline.releaseAs<DynamicCapability>().releaseAs<T>();
  }
};
template <>
1499
struct DynamicValue::Pipeline::AsImpl<DynamicStruct, Kind::OTHER> {
1500 1501 1502
  static PipelineFor<DynamicStruct> apply(Pipeline& pipeline);
};
template <>
1503
struct DynamicValue::Pipeline::AsImpl<DynamicCapability, Kind::OTHER> {
1504 1505 1506
  static PipelineFor<DynamicCapability> apply(Pipeline& pipeline);
};

Kenton Varda's avatar
Kenton Varda committed
1507 1508
// -------------------------------------------------------------------

Kenton Varda's avatar
Kenton Varda committed
1509
template <typename T>
1510
typename T::Reader DynamicStruct::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1511 1512
  static_assert(kind<T>() == Kind::STRUCT,
                "DynamicStruct::Reader::as<T>() can only convert to struct types.");
1513
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1514 1515
  return typename T::Reader(reader);
}
1516

Kenton Varda's avatar
Kenton Varda committed
1517 1518 1519 1520
template <typename T>
typename T::Builder DynamicStruct::Builder::as() {
  static_assert(kind<T>() == Kind::STRUCT,
                "DynamicStruct::Builder::as<T>() can only convert to struct types.");
1521
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1522 1523 1524
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
1525
template <>
1526
inline DynamicStruct::Reader DynamicStruct::Reader::as<DynamicStruct>() const {
Kenton Varda's avatar
Kenton Varda committed
1527 1528 1529 1530 1531 1532 1533
  return *this;
}
template <>
inline DynamicStruct::Builder DynamicStruct::Builder::as<DynamicStruct>() {
  return *this;
}

1534
inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const {
1535
  return DynamicStruct::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
1536 1537
}

1538 1539 1540 1541 1542 1543 1544 1545 1546 1547
template <>
inline AnyStruct::Reader DynamicStruct::Reader::as<AnyStruct>() const {
  return AnyStruct::Reader(reader);
}

template <>
inline AnyStruct::Builder DynamicStruct::Builder::as<AnyStruct>() {
  return AnyStruct::Builder(builder);
}

1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
template <>
inline DynamicStruct::Reader AnyStruct::Reader::as<DynamicStruct>(StructSchema schema) const {
  return DynamicStruct::Reader(schema, _reader);
}

template <>
inline DynamicStruct::Builder AnyStruct::Builder::as<DynamicStruct>(StructSchema schema) {
  return DynamicStruct::Builder(schema, _builder);
}

1558 1559 1560 1561 1562 1563 1564 1565
template <typename T>
typename T::Pipeline DynamicStruct::Pipeline::releaseAs() {
  static_assert(kind<T>() == Kind::STRUCT,
                "DynamicStruct::Pipeline::releaseAs<T>() can only convert to struct types.");
  schema.requireUsableAs<T>();
  return typename T::Pipeline(kj::mv(typeless));
}

Kenton Varda's avatar
Kenton Varda committed
1566 1567 1568
// -------------------------------------------------------------------

template <typename T>
1569
typename T::Reader DynamicList::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1570 1571
  static_assert(kind<T>() == Kind::LIST,
                "DynamicStruct::Reader::as<T>() can only convert to list types.");
1572
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1573 1574 1575 1576 1577 1578
  return typename T::Reader(reader);
}
template <typename T>
typename T::Builder DynamicList::Builder::as() {
  static_assert(kind<T>() == Kind::LIST,
                "DynamicStruct::Builder::as<T>() can only convert to list types.");
1579
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1580 1581 1582
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
1583
template <>
1584
inline DynamicList::Reader DynamicList::Reader::as<DynamicList>() const {
Kenton Varda's avatar
Kenton Varda committed
1585 1586 1587 1588 1589 1590 1591
  return *this;
}
template <>
inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
  return *this;
}

1592 1593 1594 1595 1596 1597 1598 1599 1600 1601
template <>
inline AnyList::Reader DynamicList::Reader::as<AnyList>() const {
  return AnyList::Reader(reader);
}

template <>
inline AnyList::Builder DynamicList::Builder::as<AnyList>() {
  return AnyList::Builder(builder);
}

1602 1603
// -------------------------------------------------------------------

1604 1605 1606 1607 1608
template <typename T, typename>
inline DynamicCapability::Client::Client(T&& client)
    : Capability::Client(kj::mv(client)), schema(Schema::from<FromClient<T>>()) {}

template <typename T, typename>
1609 1610
inline DynamicCapability::Client::Client(kj::Own<T>&& server)
    : Client(server->getSchema(), kj::mv(server)) {}
1611
template <typename T>
1612 1613
inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own<T>&& server)
    : Capability::Client(kj::mv(server)), schema(schema) {}
1614 1615

template <typename T, typename>
1616
typename T::Client DynamicCapability::Client::as() {
1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
  static_assert(kind<T>() == Kind::INTERFACE,
                "DynamicCapability::Client::as<T>() can only convert to interface types.");
  schema.requireUsableAs<T>();
  return typename T::Client(hook->addRef());
}

template <typename T, typename>
typename T::Client DynamicCapability::Client::releaseAs() {
  static_assert(kind<T>() == Kind::INTERFACE,
                "DynamicCapability::Client::as<T>() can only convert to interface types.");
  schema.requireUsableAs<T>();
  return typename T::Client(kj::mv(hook));
}

inline CallContext<DynamicStruct, DynamicStruct>::CallContext(
    CallContextHook& hook, StructSchema paramType, StructSchema resultType)
    : hook(&hook), paramType(paramType), resultType(resultType) {}
inline DynamicStruct::Reader CallContext<DynamicStruct, DynamicStruct>::getParams() {
  return hook->getParams().getAs<DynamicStruct>(paramType);
}
inline void CallContext<DynamicStruct, DynamicStruct>::releaseParams() {
  hook->releaseParams();
}
inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::getResults(
1641 1642
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).getAs<DynamicStruct>(resultType);
1643 1644
}
inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::initResults(
1645 1646
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).initAs<DynamicStruct>(resultType);
1647 1648
}
inline void CallContext<DynamicStruct, DynamicStruct>::setResults(DynamicStruct::Reader value) {
1649
  hook->getResults(value.totalSize()).setAs<DynamicStruct>(value);
1650 1651
}
inline void CallContext<DynamicStruct, DynamicStruct>::adoptResults(Orphan<DynamicStruct>&& value) {
1652
  hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value));
1653 1654
}
inline Orphanage CallContext<DynamicStruct, DynamicStruct>::getResultsOrphanage(
1655 1656
    kj::Maybe<MessageSize> sizeHint) {
  return Orphanage::getForMessageContaining(hook->getResults(sizeHint));
1657
}
Kenton Varda's avatar
Kenton Varda committed
1658 1659 1660 1661 1662
template <typename SubParams>
inline kj::Promise<void> CallContext<DynamicStruct, DynamicStruct>::tailCall(
    Request<SubParams, DynamicStruct>&& tailRequest) {
  return hook->tailCall(kj::mv(tailRequest.hook));
}
1663 1664
inline void CallContext<DynamicStruct, DynamicStruct>::allowCancellation() {
  hook->allowCancellation();
1665 1666 1667 1668
}

template <>
inline DynamicCapability::Client Capability::Client::castAs<DynamicCapability>(
1669
    InterfaceSchema schema) {
1670 1671 1672 1673 1674
  return DynamicCapability::Client(schema, hook->addRef());
}

// -------------------------------------------------------------------

1675 1676 1677 1678 1679
template <typename T>
ReaderFor<T> ConstSchema::as() const {
  return DynamicValue::Reader(*this).as<T>();
}

1680
}  // namespace capnp