dynamic.h 57.4 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 37 38 39
#if defined(__GNUC__) && !CAPNP_HEADER_WARNINGS
#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 373
  inline uint size() const { return reader.size() / ELEMENTS; }
  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 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 637 638
  // - Any capability type, including DynamicCapability:  Returns the corresponding Client.
  //   (TODO(perf):  On GCC 4.8 / Clang 3.3, provide rvalue-qualified version that avoids
  //   refcounting.)
639
  //
640
  // DynamicValue allows various implicit conversions, mostly just to make the interface friendlier.
641 642 643 644 645 646 647
  // - 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.
648 649
  // - Text can be converted to an enum, if the Text matches one of the enumerant names (but not
  //   vice-versa).
650
  // - Capabilities can be upcast (cast to a supertype), but not downcast.
651 652
  //
  // Any other conversion attempt will throw an exception.
Kenton Varda's avatar
Kenton Varda committed
653

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1411
inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {}
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429
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 <>
1430
struct DynamicValue::Pipeline::AsImpl<DynamicStruct, Kind::OTHER> {
1431 1432 1433
  static PipelineFor<DynamicStruct> apply(Pipeline& pipeline);
};
template <>
1434
struct DynamicValue::Pipeline::AsImpl<DynamicCapability, Kind::OTHER> {
1435 1436 1437
  static PipelineFor<DynamicCapability> apply(Pipeline& pipeline);
};

Kenton Varda's avatar
Kenton Varda committed
1438 1439
// -------------------------------------------------------------------

Kenton Varda's avatar
Kenton Varda committed
1440
template <typename T>
1441
typename T::Reader DynamicStruct::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1442 1443
  static_assert(kind<T>() == Kind::STRUCT,
                "DynamicStruct::Reader::as<T>() can only convert to struct types.");
1444
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1445 1446
  return typename T::Reader(reader);
}
1447

Kenton Varda's avatar
Kenton Varda committed
1448 1449 1450 1451
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.");
1452
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1453 1454 1455
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
1456
template <>
1457
inline DynamicStruct::Reader DynamicStruct::Reader::as<DynamicStruct>() const {
Kenton Varda's avatar
Kenton Varda committed
1458 1459 1460 1461 1462 1463 1464
  return *this;
}
template <>
inline DynamicStruct::Builder DynamicStruct::Builder::as<DynamicStruct>() {
  return *this;
}

1465
inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const {
1466
  return DynamicStruct::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
1467 1468
}

1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
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);
}

1479 1480 1481 1482 1483 1484 1485 1486
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
1487 1488 1489
// -------------------------------------------------------------------

template <typename T>
1490
typename T::Reader DynamicList::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1491 1492
  static_assert(kind<T>() == Kind::LIST,
                "DynamicStruct::Reader::as<T>() can only convert to list types.");
1493
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1494 1495 1496 1497 1498 1499
  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.");
1500
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1501 1502 1503
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
1504
template <>
1505
inline DynamicList::Reader DynamicList::Reader::as<DynamicList>() const {
Kenton Varda's avatar
Kenton Varda committed
1506 1507 1508 1509 1510 1511 1512
  return *this;
}
template <>
inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
  return *this;
}

1513 1514
// -------------------------------------------------------------------

1515 1516 1517 1518 1519
template <typename T, typename>
inline DynamicCapability::Client::Client(T&& client)
    : Capability::Client(kj::mv(client)), schema(Schema::from<FromClient<T>>()) {}

template <typename T, typename>
1520 1521
inline DynamicCapability::Client::Client(kj::Own<T>&& server)
    : Client(server->getSchema(), kj::mv(server)) {}
1522
template <typename T>
1523 1524
inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own<T>&& server)
    : Capability::Client(kj::mv(server)), schema(schema) {}
1525 1526

template <typename T, typename>
1527
typename T::Client DynamicCapability::Client::as() {
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551
  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(
1552 1553
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).getAs<DynamicStruct>(resultType);
1554 1555
}
inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::initResults(
1556 1557
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).initAs<DynamicStruct>(resultType);
1558 1559
}
inline void CallContext<DynamicStruct, DynamicStruct>::setResults(DynamicStruct::Reader value) {
1560
  hook->getResults(value.totalSize()).setAs<DynamicStruct>(value);
1561 1562
}
inline void CallContext<DynamicStruct, DynamicStruct>::adoptResults(Orphan<DynamicStruct>&& value) {
1563
  hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value));
1564 1565
}
inline Orphanage CallContext<DynamicStruct, DynamicStruct>::getResultsOrphanage(
1566 1567
    kj::Maybe<MessageSize> sizeHint) {
  return Orphanage::getForMessageContaining(hook->getResults(sizeHint));
1568
}
Kenton Varda's avatar
Kenton Varda committed
1569 1570 1571 1572 1573
template <typename SubParams>
inline kj::Promise<void> CallContext<DynamicStruct, DynamicStruct>::tailCall(
    Request<SubParams, DynamicStruct>&& tailRequest) {
  return hook->tailCall(kj::mv(tailRequest.hook));
}
1574 1575
inline void CallContext<DynamicStruct, DynamicStruct>::allowCancellation() {
  hook->allowCancellation();
1576 1577 1578 1579
}

template <>
inline DynamicCapability::Client Capability::Client::castAs<DynamicCapability>(
1580
    InterfaceSchema schema) {
1581 1582 1583 1584 1585
  return DynamicCapability::Client(schema, hook->addRef());
}

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

1586 1587 1588 1589 1590
template <typename T>
ReaderFor<T> ConstSchema::as() const {
  return DynamicValue::Reader(*this).as<T>();
}

1591
}  // namespace capnp
Kenton Varda's avatar
Kenton Varda committed
1592

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