dynamic.h 58 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.

Kenton Varda's avatar
Kenton Varda committed
33 34
#ifndef CAPNP_DYNAMIC_H_
#define CAPNP_DYNAMIC_H_
Kenton Varda's avatar
Kenton Varda committed
35

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

40
#include "schema.h"
Kenton Varda's avatar
Kenton Varda committed
41
#include "layout.h"
Kenton Varda's avatar
Kenton Varda committed
42
#include "message.h"
43
#include "any.h"
44
#include "capability.h"
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
};

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

class DynamicStruct::Reader {
public:
175 176
  typedef DynamicStruct Reads;

Kenton Varda's avatar
Kenton Varda committed
177 178
  Reader() = default;

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

182
  inline MessageSize totalSize() const { return reader.totalSize().asPublic(); }
183

Kenton Varda's avatar
Kenton Varda committed
184
  template <typename T>
185
  typename T::Reader as() const;
Kenton Varda's avatar
Kenton Varda committed
186 187
  // Convert the dynamic struct to its compiled-in type.

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

Kenton Varda's avatar
Kenton Varda committed
190 191
  DynamicValue::Reader get(StructSchema::Field field) const;
  // Read the given field value.
Kenton Varda's avatar
Kenton Varda committed
192

Kenton Varda's avatar
Kenton Varda committed
193 194
  bool has(StructSchema::Field field) const;
  // Tests whether the given field is set to its default value.  For pointer values, this does
195
  // not actually traverse the value comparing it with the default, but simply returns true if the
196 197 198
  // pointer is non-null.  For members of unions, has() returns false if the union member is not
  // active, but does not necessarily return true if the member is active (depends on the field's
  // value).
Kenton Varda's avatar
Kenton Varda committed
199 200 201 202 203 204 205

  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.
206

207 208
  DynamicValue::Reader get(kj::StringPtr name) const;
  bool has(kj::StringPtr name) const;
Kenton Varda's avatar
Kenton Varda committed
209
  // Shortcuts to access fields by name.  These throw exceptions if no such field exists.
Kenton Varda's avatar
Kenton Varda committed
210 211

private:
212
  StructSchema schema;
213
  _::StructReader reader;
Kenton Varda's avatar
Kenton Varda committed
214

215
  inline Reader(StructSchema schema, _::StructReader reader)
216
      : schema(schema), reader(reader) {}
Kenton Varda's avatar
Kenton Varda committed
217

Kenton Varda's avatar
Kenton Varda committed
218 219 220
  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
221

Kenton Varda's avatar
Kenton Varda committed
222
  template <typename T, Kind K>
223
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
224 225 226 227
  friend class DynamicStruct::Builder;
  friend struct DynamicList;
  friend class MessageReader;
  friend class MessageBuilder;
228 229
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
230
  friend kj::StringTree _::structString(
231
      _::StructReader reader, const _::RawBrandedSchema& schema);
232
  friend class Orphanage;
233
  friend class Orphan<DynamicStruct>;
234
  friend class Orphan<DynamicValue>;
235
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
236 237 238 239
};

class DynamicStruct::Builder {
public:
240 241
  typedef DynamicStruct Builds;

242
  Builder() = default;
243
  inline Builder(decltype(nullptr)) {}
Kenton Varda's avatar
Kenton Varda committed
244

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

248
  inline MessageSize totalSize() const { return asReader().totalSize(); }
249

Kenton Varda's avatar
Kenton Varda committed
250
  template <typename T>
Kenton Varda's avatar
Kenton Varda committed
251
  typename T::Builder as();
Kenton Varda's avatar
Kenton Varda committed
252 253
  // Cast to a particular struct type.

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

Kenton Varda's avatar
Kenton Varda committed
256 257
  DynamicValue::Builder get(StructSchema::Field field);
  // Read the given field value.
258

Kenton Varda's avatar
Kenton Varda committed
259 260
  inline bool has(StructSchema::Field field) { return asReader().has(field); }
  // Tests whether the given field is set to its default value.  For pointer values, this does
261
  // not actually traverse the value comparing it with the default, but simply returns true if the
Kenton Varda's avatar
Kenton Varda committed
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
  // pointer is non-null.  For members of unions, has() returns whether the field is currently
  // active and the union as a whole is non-default -- so, the only time has() will return false
  // for an active union field is if it is the default active field and it has its default value.

  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);
278 279
  // Init a struct, list, or blob field.

280 281 282 283 284
  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
285 286 287 288
  void clear(StructSchema::Field field);
  // Clear a field, setting it to its default value.  For pointer fields, this actually makes the
  // field null.

289 290 291 292 293 294
  DynamicValue::Builder get(kj::StringPtr name);
  bool has(kj::StringPtr name);
  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);
295 296
  void adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan);
  Orphan<DynamicValue> disown(kj::StringPtr name);
Kenton Varda's avatar
Kenton Varda committed
297 298
  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
299

300
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
301 302

private:
303
  StructSchema schema;
304
  _::StructBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
305

306
  inline Builder(StructSchema schema, _::StructBuilder builder)
307
      : schema(schema), builder(builder) {}
Kenton Varda's avatar
Kenton Varda committed
308

Kenton Varda's avatar
Kenton Varda committed
309 310 311 312
  bool isSetInUnion(StructSchema::Field field);
  void verifySetInUnion(StructSchema::Field field);
  void setInUnion(StructSchema::Field field);

Kenton Varda's avatar
Kenton Varda committed
313
  template <typename T, Kind k>
314
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
315 316 317
  friend struct DynamicList;
  friend class MessageReader;
  friend class MessageBuilder;
318 319
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
320 321
  friend class Orphanage;
  friend class Orphan<DynamicStruct>;
322
  friend class Orphan<DynamicValue>;
323
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
324 325
};

326 327 328 329 330 331 332 333 334 335
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.

336
  inline StructSchema getSchema() { return schema; }
337

338
  DynamicValue::Pipeline get(StructSchema::Field field);
339 340
  // Read the given field value.

341
  DynamicValue::Pipeline get(kj::StringPtr name);
342 343 344 345
  // Get by string name.

private:
  StructSchema schema;
346
  AnyPointer::Pipeline typeless;
347

348
  inline explicit Pipeline(StructSchema schema, AnyPointer::Pipeline&& typeless)
349 350 351 352 353
      : schema(schema), typeless(kj::mv(typeless)) {}

  friend class Request<DynamicStruct, DynamicStruct>;
};

Kenton Varda's avatar
Kenton Varda committed
354 355 356 357
// -------------------------------------------------------------------

class DynamicList::Reader {
public:
358 359
  typedef DynamicList Reads;

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

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

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

370
  inline ListSchema getSchema() const { return schema; }
371

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

375
  typedef _::IndexingIterator<const Reader, DynamicValue::Reader> Iterator;
376 377
  inline Iterator begin() const { return Iterator(this, 0); }
  inline Iterator end() const { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
378 379

private:
380
  ListSchema schema;
381
  _::ListReader reader;
Kenton Varda's avatar
Kenton Varda committed
382

383
  Reader(ListSchema schema, _::ListReader reader): schema(schema), reader(reader) {}
Kenton Varda's avatar
Kenton Varda committed
384

Kenton Varda's avatar
Kenton Varda committed
385
  template <typename T, Kind k>
386
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
387 388
  friend struct DynamicStruct;
  friend class DynamicList::Builder;
389 390
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
391
  friend class Orphanage;
392
  friend class Orphan<DynamicList>;
393
  friend class Orphan<DynamicValue>;
394
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
395 396 397 398
};

class DynamicList::Builder {
public:
399 400
  typedef DynamicList Builds;

401 402
  inline Builder(): builder(ElementSize::VOID) {}
  inline Builder(decltype(nullptr)): builder(ElementSize::VOID) {}
Kenton Varda's avatar
Kenton Varda committed
403

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

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

412
  inline ListSchema getSchema() const { return schema; }
413

414
  inline uint size() const { return unbound(builder.size() / ELEMENTS); }
415 416
  DynamicValue::Builder operator[](uint index);
  void set(uint index, const DynamicValue::Reader& value);
Kenton Varda's avatar
Kenton Varda committed
417
  DynamicValue::Builder init(uint index, uint size);
418 419
  void adopt(uint index, Orphan<DynamicValue>&& orphan);
  Orphan<DynamicValue> disown(uint index);
Kenton Varda's avatar
Kenton Varda committed
420

421
  typedef _::IndexingIterator<Builder, DynamicStruct::Builder> Iterator;
422 423
  inline Iterator begin() { return Iterator(this, 0); }
  inline Iterator end() { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
424

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

427
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
428 429

private:
430
  ListSchema schema;
431
  _::ListBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
432

433
  Builder(ListSchema schema, _::ListBuilder builder): schema(schema), builder(builder) {}
Kenton Varda's avatar
Kenton Varda committed
434

Kenton Varda's avatar
Kenton Varda committed
435
  template <typename T, Kind k>
436
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
437
  friend struct DynamicStruct;
438 439
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
440 441 442 443
  friend class Orphanage;
  template <typename T, Kind k>
  friend struct _::OrphanGetImpl;
  friend class Orphan<DynamicList>;
444
  friend class Orphan<DynamicValue>;
445
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
446 447 448 449
};

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

450 451 452 453 454 455 456 457 458 459 460
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*>()>>
461
  inline Client(kj::Own<T>&& server);
462 463

  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
464
  typename T::Client as();
465 466 467 468
  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
  typename T::Client releaseAs();
  // Convert to any client type.

469
  Client upcast(InterfaceSchema requestedSchema);
470 471
  // Upcast to a superclass.  Throws an exception if `schema` is not a superclass.

472
  inline InterfaceSchema getSchema() { return schema; }
473 474

  Request<DynamicStruct, DynamicStruct> newRequest(
475
      InterfaceSchema::Method method, kj::Maybe<MessageSize> sizeHint = nullptr);
476
  Request<DynamicStruct, DynamicStruct> newRequest(
477
      kj::StringPtr methodName, kj::Maybe<MessageSize> sizeHint = nullptr);
478 479 480 481

private:
  InterfaceSchema schema;

482
  Client(InterfaceSchema schema, kj::Own<ClientHook>&& hook)
483 484 485
      : Capability::Client(kj::mv(hook)), schema(schema) {}

  template <typename T>
486
  inline Client(InterfaceSchema schema, kj::Own<T>&& server);
487 488 489 490 491 492 493

  friend struct Capability;
  friend struct DynamicStruct;
  friend struct DynamicList;
  friend struct DynamicValue;
  friend class Orphan<DynamicCapability>;
  friend class Orphan<DynamicValue>;
494
  friend class Orphan<AnyPointer>;
495 496 497 498 499 500 501 502 503 504 505 506 507 508
  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;

  kj::Promise<void> dispatchCall(uint64_t interfaceId, uint16_t methodId,
509
                                 CallContext<AnyPointer, AnyPointer> context) override final;
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

  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.

private:
  kj::Own<RequestHook> hook;
  StructSchema resultSchema;

  friend class Capability::Client;
  friend struct DynamicCapability;
535 536 537
  template <typename, typename>
  friend class CallContext;
  friend class RequestHook;
538 539 540 541 542 543 544 545 546 547 548 549 550 551
};

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();
552 553
  DynamicStruct::Builder getResults(kj::Maybe<MessageSize> sizeHint = nullptr);
  DynamicStruct::Builder initResults(kj::Maybe<MessageSize> sizeHint = nullptr);
554 555
  void setResults(DynamicStruct::Reader value);
  void adoptResults(Orphan<DynamicStruct>&& value);
556
  Orphanage getResultsOrphanage(kj::Maybe<MessageSize> sizeHint = nullptr);
Kenton Varda's avatar
Kenton Varda committed
557 558
  template <typename SubParams>
  kj::Promise<void> tailCall(Request<SubParams, DynamicStruct>&& tailRequest);
559
  void allowCancellation();
560 561 562 563 564 565 566 567 568 569 570

private:
  CallContextHook* hook;
  StructSchema paramType;
  StructSchema resultType;

  friend class DynamicCapability::Server;
};

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

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

574 575 576 577 578 579 580 581 582
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
583 584 585

class DynamicValue::Reader {
public:
586 587
  typedef DynamicValue Reads;

588
  inline Reader(decltype(nullptr) n = nullptr);  // UNKNOWN
589
  inline Reader(Void value);
590 591 592 593 594 595 596 597 598 599 600 601 602 603
  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
604
  inline Reader(const char* value);  // Text
605 606 607
  inline Reader(const Text::Reader& value);
  inline Reader(const Data::Reader& value);
  inline Reader(const DynamicList::Reader& value);
608
  inline Reader(DynamicEnum value);
609
  inline Reader(const DynamicStruct::Reader& value);
610
  inline Reader(const AnyPointer::Reader& value);
611
  inline Reader(DynamicCapability::Client& value);
612 613 614
  inline Reader(DynamicCapability::Client&& value);
  template <typename T, typename = kj::EnableIf<kj::canConvert<T*, DynamicCapability::Server*>()>>
  inline Reader(kj::Own<T>&& value);
615
  Reader(ConstSchema constant);
Kenton Varda's avatar
Kenton Varda committed
616

Kenton Varda's avatar
Kenton Varda committed
617
  template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
618 619 620
  inline Reader(T&& value): Reader(toDynamic(kj::mv(value))) {}

  Reader(const Reader& other);
Kenton Varda's avatar
Kenton Varda committed
621 622
  Reader(Reader&& other) noexcept;
  ~Reader() noexcept(false);
623 624 625 626
  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
627 628

  template <typename T>
629
  inline ReaderFor<T> as() const { return AsImpl<T>::apply(*this); }
630
  // Use to interpret the value as some Cap'n Proto type.  Allowed types are:
Kenton Varda's avatar
Kenton Varda committed
631
  // - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum:  Returns the raw value.
632
  // - Text, Data, AnyPointer, any struct type:  Returns the corresponding Reader.
Kenton Varda's avatar
Kenton Varda committed
633
  // - List<T> for any T listed above:  Returns List<T>::Reader.
634
  // - DynamicEnum:  Returns the corresponding type.
Kenton Varda's avatar
Kenton Varda committed
635
  // - DynamicStruct, DynamicList:  Returns the corresponding Reader.
636
  // - Any capability type, including DynamicCapability:  Returns the corresponding Client.
637
  // - DynamicValue:  Returns an identical Reader. Useful to avoid special-casing in generic code.
638 639
  //   (TODO(perf):  On GCC 4.8 / Clang 3.3, provide rvalue-qualified version that avoids
  //   refcounting.)
640
  //
641
  // DynamicValue allows various implicit conversions, mostly just to make the interface friendlier.
642 643 644 645 646 647 648
  // - 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.
649 650
  // - Text can be converted to an enum, if the Text matches one of the enumerant names (but not
  //   vice-versa).
651
  // - Capabilities can be upcast (cast to a supertype), but not downcast.
652 653
  //
  // Any other conversion attempt will throw an exception.
Kenton Varda's avatar
Kenton Varda committed
654

655
  inline Type getType() const { return type; }
Kenton Varda's avatar
Kenton Varda committed
656 657 658
  // Get the type of this value.

private:
659
  Type type;
Kenton Varda's avatar
Kenton Varda committed
660 661 662 663

  union {
    Void voidValue;
    bool boolValue;
664 665 666
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
667 668 669 670 671
    Text::Reader textValue;
    Data::Reader dataValue;
    DynamicList::Reader listValue;
    DynamicEnum enumValue;
    DynamicStruct::Reader structValue;
672
    AnyPointer::Reader anyPointerValue;
673 674 675

    mutable DynamicCapability::Client capabilityValue;
    // Declared mutable because `Client`s normally cannot be const.
676 677 678

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

681
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
682
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
683
  // specialization.  Has a method apply() which does the work.
684 685

  friend class Orphanage;  // to speed up newOrphanCopy(DynamicValue::Reader)
Kenton Varda's avatar
Kenton Varda committed
686 687 688 689
};

class DynamicValue::Builder {
public:
690 691
  typedef DynamicValue Builds;

692
  inline Builder(decltype(nullptr) n = nullptr);  // UNKNOWN
693
  inline Builder(Void value);
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
  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);
713
  inline Builder(AnyPointer::Builder value);
714
  inline Builder(DynamicCapability::Client& value);
715
  inline Builder(DynamicCapability::Client&& value);
Kenton Varda's avatar
Kenton Varda committed
716

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

720
  Builder(Builder& other);
Kenton Varda's avatar
Kenton Varda committed
721 722
  Builder(Builder&& other) noexcept;
  ~Builder() noexcept(false);
723 724 725 726 727
  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
728
  template <typename T>
729
  inline BuilderFor<T> as() { return AsImpl<T>::apply(*this); }
Kenton Varda's avatar
Kenton Varda committed
730
  // See DynamicValue::Reader::as().
Kenton Varda's avatar
Kenton Varda committed
731

732
  inline Type getType() { return type; }
Kenton Varda's avatar
Kenton Varda committed
733 734
  // Get the type of this value.

735
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
736 737

private:
738
  Type type;
Kenton Varda's avatar
Kenton Varda committed
739 740 741 742

  union {
    Void voidValue;
    bool boolValue;
743 744 745
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
746 747 748 749 750
    Text::Builder textValue;
    Data::Builder dataValue;
    DynamicList::Builder listValue;
    DynamicEnum enumValue;
    DynamicStruct::Builder structValue;
751
    AnyPointer::Builder anyPointerValue;
752 753 754

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

757
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
758
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
759
  // specialization.  Has a method apply() which does the work.
760 761

  friend class Orphan<DynamicValue>;
Kenton Varda's avatar
Kenton Varda committed
762 763
};

764 765 766 767
class DynamicValue::Pipeline {
public:
  typedef DynamicValue Pipelines;

768
  inline Pipeline(decltype(nullptr) n = nullptr);
769 770 771
  inline Pipeline(DynamicStruct::Pipeline&& value);
  inline Pipeline(DynamicCapability::Client&& value);

772
  Pipeline(Pipeline&& other) noexcept;
773 774 775 776 777 778
  Pipeline& operator=(Pipeline&& other);
  ~Pipeline() noexcept(false);

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

779 780 781
  inline Type getType() { return type; }
  // Get the type of this value.

782 783 784 785 786 787 788 789 790 791 792 793
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.
};

794 795 796 797 798 799 800
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
801

802 803 804 805 806 807 808 809 810 811 812
// -------------------------------------------------------------------
// Orphan <-> Dynamic glue

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

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

816
  DynamicStruct::Builder get();
817
  DynamicStruct::Reader getReader() const;
818

819 820 821 822 823 824 825 826
  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; }
827 828 829 830 831 832 833 834 835 836 837 838

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;
839
  friend class Orphan<DynamicValue>;
840
  friend class Orphan<AnyPointer>;
841
  friend class MessageBuilder;
842 843 844 845 846 847 848 849 850 851
};

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

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

855
  DynamicList::Builder get();
856
  DynamicList::Reader getReader() const;
857

858 859 860 861 862 863
  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>.

864 865
  // TODO(someday): Support truncate().

866 867
  inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
  inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
868 869 870 871 872 873 874 875 876 877 878 879

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;
880
  friend class Orphan<DynamicValue>;
881
  friend class Orphan<AnyPointer>;
882 883
};

884 885 886 887 888 889 890 891
template <>
class Orphan<DynamicCapability> {
public:
  Orphan() = default;
  KJ_DISALLOW_COPY(Orphan);
  Orphan(Orphan&&) = default;
  Orphan& operator=(Orphan&&) = default;

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

895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918
  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>;
919
  friend class Orphan<AnyPointer>;
920 921
};

922 923 924
template <>
class Orphan<DynamicValue> {
public:
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
  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);
942 943 944
  Orphan(Orphan&&) = default;
  template <typename T>
  Orphan(Orphan<T>&&);
945
  Orphan(Orphan<AnyPointer>&&);
946
  Orphan(void*) = delete;  // So Orphan(bool) doesn't accept pointers.
947 948
  KJ_DISALLOW_COPY(Orphan);

949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
  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;
973
    InterfaceSchema interfaceSchema;
974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
  };

  _::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;
991
  friend struct AnyPointer;
992 993 994 995
  friend class Orphanage;
};

template <typename T>
996
inline Orphan<DynamicValue>::Orphan(Orphan<T>&& other)
997 998
    : Orphan(other.get(), kj::mv(other.builder)) {}

999 1000
inline Orphan<DynamicValue>::Orphan(Orphan<AnyPointer>&& other)
    : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {}
1001

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
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));
}

1014 1015 1016 1017 1018 1019
template <typename T>
Orphan<T> Orphan<DynamicCapability>::releaseAs() {
  get().as<T>();  // type check
  return Orphan<T>(kj::mv(builder));
}

1020 1021 1022
template <typename T>
Orphan<T> Orphan<DynamicValue>::releaseAs() {
  get().as<T>();  // type check
1023
  type = DynamicValue::UNKNOWN;
1024 1025 1026
  return Orphan<T>(kj::mv(builder));
}

1027
template <>
1028
Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>();
1029 1030 1031 1032
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>();
template <>
Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>();
1033 1034
template <>
Orphan<DynamicCapability> Orphan<DynamicValue>::releaseAs<DynamicCapability>();
1035

1036
template <>
1037
struct Orphanage::GetInnerBuilder<DynamicStruct, Kind::OTHER> {
1038 1039 1040 1041 1042 1043
  static inline _::StructBuilder apply(DynamicStruct::Builder& t) {
    return t.builder;
  }
};

template <>
1044
struct Orphanage::GetInnerBuilder<DynamicList, Kind::OTHER> {
1045 1046 1047 1048 1049 1050 1051
  static inline _::ListBuilder apply(DynamicList::Builder& t) {
    return t.builder;
  }
};

template <>
inline Orphan<DynamicStruct> Orphanage::newOrphanCopy<DynamicStruct::Reader>(
1052
    DynamicStruct::Reader copyFrom) const {
1053
  return Orphan<DynamicStruct>(
1054
      copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.reader));
1055 1056 1057 1058
}

template <>
inline Orphan<DynamicList> Orphanage::newOrphanCopy<DynamicList::Reader>(
1059
    DynamicList::Reader copyFrom) const {
1060 1061
  return Orphan<DynamicList>(copyFrom.getSchema(),
      _::OrphanBuilder::copy(arena, capTable, copyFrom.reader));
1062 1063
}

1064 1065
template <>
inline Orphan<DynamicCapability> Orphanage::newOrphanCopy<DynamicCapability::Client>(
1066
    DynamicCapability::Client copyFrom) const {
1067
  return Orphan<DynamicCapability>(
1068
      copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.hook->addRef()));
1069 1070
}

1071 1072
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
1073
    DynamicValue::Reader copyFrom) const;
1074

1075
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
1076 1077

template <>
1078
struct PointerHelpers<DynamicStruct, Kind::OTHER> {
1079
  // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1080 1081
  // 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.
1082 1083 1084 1085 1086 1087
  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));
1088
  }
1089 1090
  static inline Orphan<DynamicStruct> disown(PointerBuilder builder, StructSchema schema) {
    return Orphan<DynamicStruct>(schema, builder.disown());
1091
  }
Kenton Varda's avatar
Kenton Varda committed
1092 1093 1094
};

template <>
1095
struct PointerHelpers<DynamicList, Kind::OTHER> {
1096
  // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1097 1098
  // 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.
1099 1100 1101 1102 1103 1104
  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));
1105
  }
1106 1107
  static inline Orphan<DynamicList> disown(PointerBuilder builder, ListSchema schema) {
    return Orphan<DynamicList>(schema, builder.disown());
1108
  }
Kenton Varda's avatar
Kenton Varda committed
1109 1110
};

1111
template <>
1112
struct PointerHelpers<DynamicCapability, Kind::OTHER> {
1113
  // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1114 1115 1116 1117
  // 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);
1118
  static void set(PointerBuilder builder, DynamicCapability::Client& value);
1119 1120 1121 1122 1123 1124 1125 1126 1127
  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());
  }
};

1128
}  // namespace _ (private)
Kenton Varda's avatar
Kenton Varda committed
1129

1130
template <typename T>
1131
inline ReaderFor<T> AnyPointer::Reader::getAs(StructSchema schema) const {
1132 1133 1134
  return _::PointerHelpers<T>::getDynamic(reader, schema);
}
template <typename T>
1135
inline ReaderFor<T> AnyPointer::Reader::getAs(ListSchema schema) const {
1136 1137 1138
  return _::PointerHelpers<T>::getDynamic(reader, schema);
}
template <typename T>
1139
inline ReaderFor<T> AnyPointer::Reader::getAs(InterfaceSchema schema) const {
1140 1141 1142
  return _::PointerHelpers<T>::getDynamic(reader, schema);
}
template <typename T>
1143
inline BuilderFor<T> AnyPointer::Builder::getAs(StructSchema schema) {
1144 1145 1146
  return _::PointerHelpers<T>::getDynamic(builder, schema);
}
template <typename T>
1147
inline BuilderFor<T> AnyPointer::Builder::getAs(ListSchema schema) {
1148 1149 1150
  return _::PointerHelpers<T>::getDynamic(builder, schema);
}
template <typename T>
1151
inline BuilderFor<T> AnyPointer::Builder::getAs(InterfaceSchema schema) {
1152 1153 1154
  return _::PointerHelpers<T>::getDynamic(builder, schema);
}
template <typename T>
1155
inline BuilderFor<T> AnyPointer::Builder::initAs(StructSchema schema) {
1156 1157 1158
  return _::PointerHelpers<T>::init(builder, schema);
}
template <typename T>
1159
inline BuilderFor<T> AnyPointer::Builder::initAs(ListSchema schema, uint elementCount) {
1160 1161 1162
  return _::PointerHelpers<T>::init(builder, schema, elementCount);
}
template <>
1163
inline void AnyPointer::Builder::setAs<DynamicStruct>(DynamicStruct::Reader value) {
1164 1165 1166
  return _::PointerHelpers<DynamicStruct>::set(builder, value);
}
template <>
1167
inline void AnyPointer::Builder::setAs<DynamicList>(DynamicList::Reader value) {
1168 1169 1170
  return _::PointerHelpers<DynamicList>::set(builder, value);
}
template <>
1171
inline void AnyPointer::Builder::setAs<DynamicCapability>(DynamicCapability::Client value) {
1172 1173 1174
  return _::PointerHelpers<DynamicCapability>::set(builder, kj::mv(value));
}
template <>
1175
void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan);
1176
template <typename T>
1177
inline Orphan<T> AnyPointer::Builder::disownAs(StructSchema schema) {
1178 1179 1180
  return _::PointerHelpers<T>::disown(builder, schema);
}
template <typename T>
1181
inline Orphan<T> AnyPointer::Builder::disownAs(ListSchema schema) {
1182 1183
  return _::PointerHelpers<T>::disown(builder, schema);
}
1184
template <typename T>
1185
inline Orphan<T> AnyPointer::Builder::disownAs(InterfaceSchema schema) {
1186 1187
  return _::PointerHelpers<T>::disown(builder, schema);
}
1188

1189
template <>
1190
DynamicStruct::Builder Orphan<AnyPointer>::getAs<DynamicStruct>(StructSchema schema);
1191
template <>
1192
DynamicList::Builder Orphan<AnyPointer>::getAs<DynamicList>(ListSchema schema);
1193
template <>
1194
DynamicCapability::Client Orphan<AnyPointer>::getAs<DynamicCapability>(InterfaceSchema schema);
1195
template <>
1196
DynamicStruct::Reader Orphan<AnyPointer>::getAsReader<DynamicStruct>(StructSchema schema) const;
1197
template <>
1198
DynamicList::Reader Orphan<AnyPointer>::getAsReader<DynamicList>(ListSchema schema) const;
1199
template <>
1200
DynamicCapability::Client Orphan<AnyPointer>::getAsReader<DynamicCapability>(
1201 1202
    InterfaceSchema schema) const;
template <>
1203
Orphan<DynamicStruct> Orphan<AnyPointer>::releaseAs<DynamicStruct>(StructSchema schema);
1204
template <>
1205
Orphan<DynamicList> Orphan<AnyPointer>::releaseAs<DynamicList>(ListSchema schema);
1206
template <>
1207
Orphan<DynamicCapability> Orphan<AnyPointer>::releaseAs<DynamicCapability>(
1208
    InterfaceSchema schema);
1209

Kenton Varda's avatar
Kenton Varda committed
1210
// =======================================================================================
Kenton Varda's avatar
Kenton Varda committed
1211
// Inline implementation details.
Kenton Varda's avatar
Kenton Varda committed
1212

1213
template <typename T>
1214
struct ToDynamic_<T, Kind::STRUCT> {
1215
  static inline DynamicStruct::Reader apply(const typename T::Reader& value) {
1216
    return DynamicStruct::Reader(Schema::from<T>(), value._reader);
1217
  }
1218
  static inline DynamicStruct::Builder apply(typename T::Builder& value) {
1219
    return DynamicStruct::Builder(Schema::from<T>(), value._builder);
1220 1221 1222 1223
  }
};

template <typename T>
1224
struct ToDynamic_<T, Kind::LIST> {
1225
  static inline DynamicList::Reader apply(const typename T::Reader& value) {
1226
    return DynamicList::Reader(Schema::from<T>(), value.reader);
1227
  }
1228
  static inline DynamicList::Builder apply(typename T::Builder& value) {
1229
    return DynamicList::Builder(Schema::from<T>(), value.builder);
1230 1231 1232
  }
};

1233 1234
template <typename T>
struct ToDynamic_<T, Kind::INTERFACE> {
1235 1236
  static inline DynamicCapability::Client apply(typename T::Client value) {
    return DynamicCapability::Client(kj::mv(value));
1237 1238 1239 1240 1241 1242
  }
  static inline DynamicCapability::Client apply(typename T::Client&& value) {
    return DynamicCapability::Client(kj::mv(value));
  }
};

1243
template <typename T>
1244 1245
ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromReader<T>>::apply(value);
1246 1247
}
template <typename T>
1248 1249
BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromBuilder<T>>::apply(value);
1250
}
1251
template <typename T>
1252
DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) {
1253
  return DynamicEnum(Schema::from<kj::Decay<T>>(), static_cast<uint16_t>(value));
1254
}
1255 1256 1257 1258
template <typename T>
typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value) {
  return typename FromServer<T>::Client(kj::mv(value));
}
1259

1260 1261 1262
inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {}
inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {}

1263
#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
1264 1265 1266
inline DynamicValue::Reader::Reader(cppType value) \
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType value) \
1267 1268 1269
    : type(typeTag), fieldName##Value(value) {} \
inline Orphan<DynamicValue>::Orphan(cppType value) \
    : type(DynamicValue::typeTag), fieldName##Value(value) {}
1270

Kenton Varda's avatar
Kenton Varda committed
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
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) \
1290
inline DynamicValue::Reader::Reader(const cppType::Reader& value) \
1291 1292 1293 1294
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType::Builder value) \
    : type(typeTag), fieldName##Value(value) {}

Kenton Varda's avatar
Kenton Varda committed
1295 1296 1297 1298
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);
1299
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(AnyPointer, ANY_POINTER, anyPointer);
1300

Kenton Varda's avatar
Kenton Varda committed
1301
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
1302

1303
inline DynamicValue::Reader::Reader(DynamicCapability::Client& value)
1304 1305 1306 1307 1308 1309
    : 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)) {}
1310
inline DynamicValue::Builder::Builder(DynamicCapability::Client& value)
1311 1312 1313 1314
    : type(CAPABILITY), capabilityValue(value) {}
inline DynamicValue::Builder::Builder(DynamicCapability::Client&& value)
    : type(CAPABILITY), capabilityValue(kj::mv(value)) {}

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

1317
#define CAPNP_DECLARE_TYPE(discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1318
template <> \
1319
struct DynamicValue::Reader::AsImpl<typeName> { \
1320
  static ReaderFor<typeName> apply(const Reader& reader); \
Kenton Varda's avatar
Kenton Varda committed
1321 1322
}; \
template <> \
1323
struct DynamicValue::Builder::AsImpl<typeName> { \
1324
  static BuilderFor<typeName> apply(Builder& builder); \
Kenton Varda's avatar
Kenton Varda committed
1325 1326
};

1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
//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
1347 1348 1349
#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
1350 1351
// ReaderFor<> and BuilderFor<> wrappers, it works.
template <>
1352
struct DynamicValue::Reader::AsImpl<Void> {
1353
  static Void apply(const Reader& reader);
Kenton Varda's avatar
Kenton Varda committed
1354 1355
};
template <>
1356
struct DynamicValue::Builder::AsImpl<Void> {
1357
  static Void apply(Builder& builder);
Kenton Varda's avatar
Kenton Varda committed
1358 1359 1360
};

template <typename T>
1361
struct DynamicValue::Reader::AsImpl<T, Kind::ENUM> {
1362
  static T apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1363
    return reader.as<DynamicEnum>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1364 1365 1366
  }
};
template <typename T>
1367
struct DynamicValue::Builder::AsImpl<T, Kind::ENUM> {
1368
  static T apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1369
    return builder.as<DynamicEnum>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1370 1371 1372 1373
  }
};

template <typename T>
1374
struct DynamicValue::Reader::AsImpl<T, Kind::STRUCT> {
1375
  static typename T::Reader apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1376
    return reader.as<DynamicStruct>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1377 1378 1379
  }
};
template <typename T>
1380
struct DynamicValue::Builder::AsImpl<T, Kind::STRUCT> {
1381
  static typename T::Builder apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1382
    return builder.as<DynamicStruct>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1383 1384 1385 1386
  }
};

template <typename T>
1387
struct DynamicValue::Reader::AsImpl<T, Kind::LIST> {
1388
  static typename T::Reader apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1389
    return reader.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1390 1391 1392
  }
};
template <typename T>
1393
struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
1394
  static typename T::Builder apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1395
    return builder.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1396 1397 1398
  }
};

1399 1400
template <typename T>
struct DynamicValue::Reader::AsImpl<T, Kind::INTERFACE> {
1401
  static typename T::Client apply(const Reader& reader) {
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
    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>();
  }
};

1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424
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;
  }
};

1425
inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {}
1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
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 <>
1444
struct DynamicValue::Pipeline::AsImpl<DynamicStruct, Kind::OTHER> {
1445 1446 1447
  static PipelineFor<DynamicStruct> apply(Pipeline& pipeline);
};
template <>
1448
struct DynamicValue::Pipeline::AsImpl<DynamicCapability, Kind::OTHER> {
1449 1450 1451
  static PipelineFor<DynamicCapability> apply(Pipeline& pipeline);
};

Kenton Varda's avatar
Kenton Varda committed
1452 1453
// -------------------------------------------------------------------

Kenton Varda's avatar
Kenton Varda committed
1454
template <typename T>
1455
typename T::Reader DynamicStruct::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1456 1457
  static_assert(kind<T>() == Kind::STRUCT,
                "DynamicStruct::Reader::as<T>() can only convert to struct types.");
1458
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1459 1460
  return typename T::Reader(reader);
}
1461

Kenton Varda's avatar
Kenton Varda committed
1462 1463 1464 1465
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.");
1466
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1467 1468 1469
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
1470
template <>
1471
inline DynamicStruct::Reader DynamicStruct::Reader::as<DynamicStruct>() const {
Kenton Varda's avatar
Kenton Varda committed
1472 1473 1474 1475 1476 1477 1478
  return *this;
}
template <>
inline DynamicStruct::Builder DynamicStruct::Builder::as<DynamicStruct>() {
  return *this;
}

1479
inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const {
1480
  return DynamicStruct::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
1481 1482
}

1483 1484 1485 1486 1487 1488 1489 1490 1491 1492
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);
}

1493 1494 1495 1496 1497 1498 1499 1500
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
1501 1502 1503
// -------------------------------------------------------------------

template <typename T>
1504
typename T::Reader DynamicList::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1505 1506
  static_assert(kind<T>() == Kind::LIST,
                "DynamicStruct::Reader::as<T>() can only convert to list types.");
1507
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1508 1509 1510 1511 1512 1513
  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.");
1514
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1515 1516 1517
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
1518
template <>
1519
inline DynamicList::Reader DynamicList::Reader::as<DynamicList>() const {
Kenton Varda's avatar
Kenton Varda committed
1520 1521 1522 1523 1524 1525 1526
  return *this;
}
template <>
inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
  return *this;
}

1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
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);
}

1537 1538
// -------------------------------------------------------------------

1539 1540 1541 1542 1543
template <typename T, typename>
inline DynamicCapability::Client::Client(T&& client)
    : Capability::Client(kj::mv(client)), schema(Schema::from<FromClient<T>>()) {}

template <typename T, typename>
1544 1545
inline DynamicCapability::Client::Client(kj::Own<T>&& server)
    : Client(server->getSchema(), kj::mv(server)) {}
1546
template <typename T>
1547 1548
inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own<T>&& server)
    : Capability::Client(kj::mv(server)), schema(schema) {}
1549 1550

template <typename T, typename>
1551
typename T::Client DynamicCapability::Client::as() {
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575
  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(
1576 1577
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).getAs<DynamicStruct>(resultType);
1578 1579
}
inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::initResults(
1580 1581
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).initAs<DynamicStruct>(resultType);
1582 1583
}
inline void CallContext<DynamicStruct, DynamicStruct>::setResults(DynamicStruct::Reader value) {
1584
  hook->getResults(value.totalSize()).setAs<DynamicStruct>(value);
1585 1586
}
inline void CallContext<DynamicStruct, DynamicStruct>::adoptResults(Orphan<DynamicStruct>&& value) {
1587
  hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value));
1588 1589
}
inline Orphanage CallContext<DynamicStruct, DynamicStruct>::getResultsOrphanage(
1590 1591
    kj::Maybe<MessageSize> sizeHint) {
  return Orphanage::getForMessageContaining(hook->getResults(sizeHint));
1592
}
Kenton Varda's avatar
Kenton Varda committed
1593 1594 1595 1596 1597
template <typename SubParams>
inline kj::Promise<void> CallContext<DynamicStruct, DynamicStruct>::tailCall(
    Request<SubParams, DynamicStruct>&& tailRequest) {
  return hook->tailCall(kj::mv(tailRequest.hook));
}
1598 1599
inline void CallContext<DynamicStruct, DynamicStruct>::allowCancellation() {
  hook->allowCancellation();
1600 1601 1602 1603
}

template <>
inline DynamicCapability::Client Capability::Client::castAs<DynamicCapability>(
1604
    InterfaceSchema schema) {
1605 1606 1607 1608 1609
  return DynamicCapability::Client(schema, hook->addRef());
}

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

1610 1611 1612 1613 1614
template <typename T>
ReaderFor<T> ConstSchema::as() const {
  return DynamicValue::Reader(*this).as<T>();
}

1615
}  // namespace capnp
Kenton Varda's avatar
Kenton Varda committed
1616

Kenton Varda's avatar
Kenton Varda committed
1617
#endif  // CAPNP_DYNAMIC_H_