dynamic.h 56.8 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)

Kenton Varda's avatar
Kenton Varda committed
125 126 127 128 129
// -------------------------------------------------------------------

class DynamicEnum {
public:
  DynamicEnum() = default;
130 131
  inline DynamicEnum(EnumSchema::Enumerant enumerant)
      : schema(enumerant.getContainingEnum()), value(enumerant.getOrdinal()) {}
132 133
  inline DynamicEnum(EnumSchema schema, uint16_t value)
      : schema(schema), value(value) {}
Kenton Varda's avatar
Kenton Varda committed
134

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

Kenton Varda's avatar
Kenton Varda committed
138
  template <typename T>
139
  inline T as() const { return static_cast<T>(asImpl(typeId<T>())); }
Kenton Varda's avatar
Kenton Varda committed
140 141
  // Cast to a native enum type.

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

144
  kj::Maybe<EnumSchema::Enumerant> getEnumerant() const;
Kenton Varda's avatar
Kenton Varda committed
145 146 147 148
  // 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.

149
  inline uint16_t getRaw() const { return value; }
Kenton Varda's avatar
Kenton Varda committed
150 151 152
  // Returns the raw underlying enum value.

private:
153
  EnumSchema schema;
Kenton Varda's avatar
Kenton Varda committed
154 155
  uint16_t value;

156
  uint16_t asImpl(uint64_t requestedTypeId) const;
Kenton Varda's avatar
Kenton Varda committed
157 158

  friend struct DynamicStruct;
Kenton Varda's avatar
Kenton Varda committed
159
  friend struct DynamicList;
160
  friend struct DynamicValue;
161 162
  template <typename T>
  friend DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value);
Kenton Varda's avatar
Kenton Varda committed
163 164 165 166 167 168
};

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

class DynamicStruct::Reader {
public:
169 170
  typedef DynamicStruct Reads;

Kenton Varda's avatar
Kenton Varda committed
171 172
  Reader() = default;

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

176
  inline MessageSize totalSize() const { return reader.totalSize().asPublic(); }
177

Kenton Varda's avatar
Kenton Varda committed
178
  template <typename T>
179
  typename T::Reader as() const;
Kenton Varda's avatar
Kenton Varda committed
180 181
  // Convert the dynamic struct to its compiled-in type.

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

Kenton Varda's avatar
Kenton Varda committed
184 185
  DynamicValue::Reader get(StructSchema::Field field) const;
  // Read the given field value.
Kenton Varda's avatar
Kenton Varda committed
186

Kenton Varda's avatar
Kenton Varda committed
187 188
  bool has(StructSchema::Field field) const;
  // Tests whether the given field is set to its default value.  For pointer values, this does
189
  // not actually traverse the value comparing it with the default, but simply returns true if the
190 191 192
  // 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
193 194 195 196 197 198 199

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

201 202
  DynamicValue::Reader get(kj::StringPtr name) const;
  bool has(kj::StringPtr name) const;
Kenton Varda's avatar
Kenton Varda committed
203
  // Shortcuts to access fields by name.  These throw exceptions if no such field exists.
Kenton Varda's avatar
Kenton Varda committed
204 205

private:
206
  StructSchema schema;
207
  _::StructReader reader;
Kenton Varda's avatar
Kenton Varda committed
208

209
  inline Reader(StructSchema schema, _::StructReader reader)
210
      : schema(schema), reader(reader) {}
Kenton Varda's avatar
Kenton Varda committed
211

Kenton Varda's avatar
Kenton Varda committed
212 213 214
  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
215

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

class DynamicStruct::Builder {
public:
234 235
  typedef DynamicStruct Builds;

236
  Builder() = default;
237
  inline Builder(decltype(nullptr)) {}
Kenton Varda's avatar
Kenton Varda committed
238

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

242
  inline MessageSize totalSize() const { return asReader().totalSize(); }
243

Kenton Varda's avatar
Kenton Varda committed
244
  template <typename T>
Kenton Varda's avatar
Kenton Varda committed
245
  typename T::Builder as();
Kenton Varda's avatar
Kenton Varda committed
246 247
  // Cast to a particular struct type.

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

Kenton Varda's avatar
Kenton Varda committed
250 251
  DynamicValue::Builder get(StructSchema::Field field);
  // Read the given field value.
252

Kenton Varda's avatar
Kenton Varda committed
253 254
  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
255
  // not actually traverse the value comparing it with the default, but simply returns true if the
Kenton Varda's avatar
Kenton Varda committed
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
  // 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);
272 273
  // Init a struct, list, or blob field.

274 275 276 277 278
  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
279 280 281 282
  void clear(StructSchema::Field field);
  // Clear a field, setting it to its default value.  For pointer fields, this actually makes the
  // field null.

283 284 285 286 287 288
  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);
289 290
  void adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan);
  Orphan<DynamicValue> disown(kj::StringPtr name);
Kenton Varda's avatar
Kenton Varda committed
291 292
  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
293

294
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
295 296

private:
297
  StructSchema schema;
298
  _::StructBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
299

300
  inline Builder(StructSchema schema, _::StructBuilder builder)
301
      : schema(schema), builder(builder) {}
Kenton Varda's avatar
Kenton Varda committed
302

Kenton Varda's avatar
Kenton Varda committed
303 304 305 306
  bool isSetInUnion(StructSchema::Field field);
  void verifySetInUnion(StructSchema::Field field);
  void setInUnion(StructSchema::Field field);

Kenton Varda's avatar
Kenton Varda committed
307
  template <typename T, Kind k>
308
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
309 310 311
  friend struct DynamicList;
  friend class MessageReader;
  friend class MessageBuilder;
312 313
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
314 315
  friend class Orphanage;
  friend class Orphan<DynamicStruct>;
316
  friend class Orphan<DynamicValue>;
317
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
318 319
};

320 321 322 323 324 325 326 327 328 329
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.

330
  inline StructSchema getSchema() { return schema; }
331

332
  DynamicValue::Pipeline get(StructSchema::Field field);
333 334
  // Read the given field value.

335
  DynamicValue::Pipeline get(kj::StringPtr name);
336 337 338 339
  // Get by string name.

private:
  StructSchema schema;
340
  AnyPointer::Pipeline typeless;
341

342
  inline explicit Pipeline(StructSchema schema, AnyPointer::Pipeline&& typeless)
343 344 345 346 347
      : schema(schema), typeless(kj::mv(typeless)) {}

  friend class Request<DynamicStruct, DynamicStruct>;
};

Kenton Varda's avatar
Kenton Varda committed
348 349 350 351
// -------------------------------------------------------------------

class DynamicList::Reader {
public:
352 353
  typedef DynamicList Reads;

Kenton Varda's avatar
Kenton Varda committed
354 355
  Reader() = default;

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

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

364
  inline ListSchema getSchema() const { return schema; }
365

366 367
  inline uint size() const { return reader.size() / ELEMENTS; }
  DynamicValue::Reader operator[](uint index) const;
Kenton Varda's avatar
Kenton Varda committed
368

369
  typedef _::IndexingIterator<const Reader, DynamicValue::Reader> Iterator;
370 371
  inline Iterator begin() const { return Iterator(this, 0); }
  inline Iterator end() const { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
372 373

private:
374
  ListSchema schema;
375
  _::ListReader reader;
Kenton Varda's avatar
Kenton Varda committed
376

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

Kenton Varda's avatar
Kenton Varda committed
379
  template <typename T, Kind k>
380
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
381 382
  friend struct DynamicStruct;
  friend class DynamicList::Builder;
383 384
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
385
  friend class Orphanage;
386
  friend class Orphan<DynamicList>;
387
  friend class Orphan<DynamicValue>;
388
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
389 390 391 392
};

class DynamicList::Builder {
public:
393 394
  typedef DynamicList Builds;

395
  Builder() = default;
396
  inline Builder(decltype(nullptr)) {}
Kenton Varda's avatar
Kenton Varda committed
397

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

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

406
  inline ListSchema getSchema() const { return schema; }
407

408
  inline uint size() const { return builder.size() / ELEMENTS; }
409 410
  DynamicValue::Builder operator[](uint index);
  void set(uint index, const DynamicValue::Reader& value);
Kenton Varda's avatar
Kenton Varda committed
411
  DynamicValue::Builder init(uint index, uint size);
412 413
  void adopt(uint index, Orphan<DynamicValue>&& orphan);
  Orphan<DynamicValue> disown(uint index);
Kenton Varda's avatar
Kenton Varda committed
414

415
  typedef _::IndexingIterator<Builder, DynamicStruct::Builder> Iterator;
416 417
  inline Iterator begin() { return Iterator(this, 0); }
  inline Iterator end() { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
418

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

421
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
422 423

private:
424
  ListSchema schema;
425
  _::ListBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
426

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

Kenton Varda's avatar
Kenton Varda committed
429
  template <typename T, Kind k>
430
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
431
  friend struct DynamicStruct;
432 433
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
434 435 436 437
  friend class Orphanage;
  template <typename T, Kind k>
  friend struct _::OrphanGetImpl;
  friend class Orphan<DynamicList>;
438
  friend class Orphan<DynamicValue>;
439
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
440 441 442 443
};

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

444 445 446 447 448 449 450 451 452 453 454
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*>()>>
455
  inline Client(kj::Own<T>&& server);
456 457

  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
458
  typename T::Client as();
459 460 461 462
  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
  typename T::Client releaseAs();
  // Convert to any client type.

463
  Client upcast(InterfaceSchema requestedSchema);
464 465
  // Upcast to a superclass.  Throws an exception if `schema` is not a superclass.

466
  inline InterfaceSchema getSchema() { return schema; }
467 468

  Request<DynamicStruct, DynamicStruct> newRequest(
469
      InterfaceSchema::Method method, kj::Maybe<MessageSize> sizeHint = nullptr);
470
  Request<DynamicStruct, DynamicStruct> newRequest(
471
      kj::StringPtr methodName, kj::Maybe<MessageSize> sizeHint = nullptr);
472 473 474 475

private:
  InterfaceSchema schema;

476
  Client(InterfaceSchema schema, kj::Own<ClientHook>&& hook)
477 478 479
      : Capability::Client(kj::mv(hook)), schema(schema) {}

  template <typename T>
480
  inline Client(InterfaceSchema schema, kj::Own<T>&& server);
481 482 483 484 485 486 487

  friend struct Capability;
  friend struct DynamicStruct;
  friend struct DynamicList;
  friend struct DynamicValue;
  friend class Orphan<DynamicCapability>;
  friend class Orphan<DynamicValue>;
488
  friend class Orphan<AnyPointer>;
489 490 491 492 493 494 495 496 497 498 499 500 501 502
  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,
503
                                 CallContext<AnyPointer, AnyPointer> context) override final;
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528

  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;
529 530 531
  template <typename, typename>
  friend class CallContext;
  friend class RequestHook;
532 533 534 535 536 537 538 539 540 541 542 543 544 545
};

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

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

  friend class DynamicCapability::Server;
};

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

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

568 569 570 571 572 573 574 575 576
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
577 578 579

class DynamicValue::Reader {
public:
580 581
  typedef DynamicValue Reads;

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

Kenton Varda's avatar
Kenton Varda committed
611
  template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
612 613 614
  inline Reader(T&& value): Reader(toDynamic(kj::mv(value))) {}

  Reader(const Reader& other);
Kenton Varda's avatar
Kenton Varda committed
615 616
  Reader(Reader&& other) noexcept;
  ~Reader() noexcept(false);
617 618 619 620
  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
621 622

  template <typename T>
623
  inline ReaderFor<T> as() const { return AsImpl<T>::apply(*this); }
624
  // Use to interpret the value as some Cap'n Proto type.  Allowed types are:
Kenton Varda's avatar
Kenton Varda committed
625
  // - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum:  Returns the raw value.
626
  // - Text, Data, AnyPointer, any struct type:  Returns the corresponding Reader.
Kenton Varda's avatar
Kenton Varda committed
627
  // - List<T> for any T listed above:  Returns List<T>::Reader.
628
  // - DynamicEnum:  Returns the corresponding type.
Kenton Varda's avatar
Kenton Varda committed
629
  // - DynamicStruct, DynamicList:  Returns the corresponding Reader.
630 631 632
  // - 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.)
633
  //
634
  // DynamicValue allows various implicit conversions, mostly just to make the interface friendlier.
635 636 637 638 639 640 641
  // - 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.
642 643
  // - Text can be converted to an enum, if the Text matches one of the enumerant names (but not
  //   vice-versa).
644
  // - Capabilities can be upcast (cast to a supertype), but not downcast.
645 646
  //
  // Any other conversion attempt will throw an exception.
Kenton Varda's avatar
Kenton Varda committed
647

648
  inline Type getType() const { return type; }
Kenton Varda's avatar
Kenton Varda committed
649 650 651
  // Get the type of this value.

private:
652
  Type type;
Kenton Varda's avatar
Kenton Varda committed
653 654 655 656

  union {
    Void voidValue;
    bool boolValue;
657 658 659
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
660 661 662 663 664
    Text::Reader textValue;
    Data::Reader dataValue;
    DynamicList::Reader listValue;
    DynamicEnum enumValue;
    DynamicStruct::Reader structValue;
665
    AnyPointer::Reader anyPointerValue;
666 667 668

    mutable DynamicCapability::Client capabilityValue;
    // Declared mutable because `Client`s normally cannot be const.
669 670 671

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

674
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
675
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
676
  // specialization.  Has a method apply() which does the work.
677 678

  friend class Orphanage;  // to speed up newOrphanCopy(DynamicValue::Reader)
Kenton Varda's avatar
Kenton Varda committed
679 680 681 682
};

class DynamicValue::Builder {
public:
683 684
  typedef DynamicValue Builds;

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

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

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

725
  inline Type getType() { return type; }
Kenton Varda's avatar
Kenton Varda committed
726 727
  // Get the type of this value.

728
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
729 730

private:
731
  Type type;
Kenton Varda's avatar
Kenton Varda committed
732 733 734 735

  union {
    Void voidValue;
    bool boolValue;
736 737 738
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
739 740 741 742 743
    Text::Builder textValue;
    Data::Builder dataValue;
    DynamicList::Builder listValue;
    DynamicEnum enumValue;
    DynamicStruct::Builder structValue;
744
    AnyPointer::Builder anyPointerValue;
745 746 747

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

750
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
751
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
752
  // specialization.  Has a method apply() which does the work.
753 754

  friend class Orphan<DynamicValue>;
Kenton Varda's avatar
Kenton Varda committed
755 756
};

757 758 759 760
class DynamicValue::Pipeline {
public:
  typedef DynamicValue Pipelines;

761
  inline Pipeline(decltype(nullptr) n = nullptr);
762 763 764
  inline Pipeline(DynamicStruct::Pipeline&& value);
  inline Pipeline(DynamicCapability::Client&& value);

765
  Pipeline(Pipeline&& other) noexcept;
766 767 768 769 770 771
  Pipeline& operator=(Pipeline&& other);
  ~Pipeline() noexcept(false);

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

772 773 774
  inline Type getType() { return type; }
  // Get the type of this value.

775 776 777 778 779 780 781 782 783 784 785 786
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.
};

787 788 789 790 791 792 793
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
794

795 796 797 798 799 800 801 802 803 804 805
// -------------------------------------------------------------------
// Orphan <-> Dynamic glue

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

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

809
  DynamicStruct::Builder get();
810
  DynamicStruct::Reader getReader() const;
811

812 813 814 815 816 817 818 819
  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; }
820 821 822 823 824 825 826 827 828 829 830 831

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;
832
  friend class Orphan<DynamicValue>;
833
  friend class Orphan<AnyPointer>;
834
  friend class MessageBuilder;
835 836 837 838 839 840 841 842 843 844
};

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

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

848
  DynamicList::Builder get();
849
  DynamicList::Reader getReader() const;
850

851 852 853 854 855 856
  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>.

857 858
  // TODO(someday): Support truncate().

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

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;
873
  friend class Orphan<DynamicValue>;
874
  friend class Orphan<AnyPointer>;
875 876
};

877 878 879 880 881 882 883 884
template <>
class Orphan<DynamicCapability> {
public:
  Orphan() = default;
  KJ_DISALLOW_COPY(Orphan);
  Orphan(Orphan&&) = default;
  Orphan& operator=(Orphan&&) = default;

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

888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
  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>;
912
  friend class Orphan<AnyPointer>;
913 914
};

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

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

  _::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;
984
  friend struct AnyPointer;
985 986 987 988
  friend class Orphanage;
};

template <typename T>
989
inline Orphan<DynamicValue>::Orphan(Orphan<T>&& other)
990 991
    : Orphan(other.get(), kj::mv(other.builder)) {}

992 993
inline Orphan<DynamicValue>::Orphan(Orphan<AnyPointer>&& other)
    : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {}
994

995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
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));
}

1007 1008 1009 1010 1011 1012
template <typename T>
Orphan<T> Orphan<DynamicCapability>::releaseAs() {
  get().as<T>();  // type check
  return Orphan<T>(kj::mv(builder));
}

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

1020
template <>
1021
Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>();
1022 1023 1024 1025
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>();
template <>
Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>();
1026 1027
template <>
Orphan<DynamicCapability> Orphan<DynamicValue>::releaseAs<DynamicCapability>();
1028

1029
template <>
1030
struct Orphanage::GetInnerBuilder<DynamicStruct, Kind::OTHER> {
1031 1032 1033 1034 1035 1036
  static inline _::StructBuilder apply(DynamicStruct::Builder& t) {
    return t.builder;
  }
};

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

template <>
inline Orphan<DynamicStruct> Orphanage::newOrphanCopy<DynamicStruct::Reader>(
1045
    const DynamicStruct::Reader& copyFrom) const {
1046 1047 1048 1049 1050 1051
  return Orphan<DynamicStruct>(
      copyFrom.getSchema(), _::OrphanBuilder::copy(arena, copyFrom.reader));
}

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

1056 1057
template <>
inline Orphan<DynamicCapability> Orphanage::newOrphanCopy<DynamicCapability::Client>(
1058
    DynamicCapability::Client& copyFrom) const {
1059 1060 1061 1062
  return Orphan<DynamicCapability>(
      copyFrom.getSchema(), _::OrphanBuilder::copy(arena, copyFrom.hook->addRef()));
}

1063 1064 1065 1066
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
    const DynamicValue::Reader& copyFrom) const;

1067
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
1068 1069

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

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

1103
template <>
1104
struct PointerHelpers<DynamicCapability, Kind::OTHER> {
1105
  // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1106 1107 1108 1109
  // 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);
1110
  static void set(PointerBuilder builder, DynamicCapability::Client& value);
1111 1112 1113 1114 1115 1116 1117 1118 1119
  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());
  }
};

1120
}  // namespace _ (private)
Kenton Varda's avatar
Kenton Varda committed
1121

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

1181
template <>
1182
DynamicStruct::Builder Orphan<AnyPointer>::getAs<DynamicStruct>(StructSchema schema);
1183
template <>
1184
DynamicList::Builder Orphan<AnyPointer>::getAs<DynamicList>(ListSchema schema);
1185
template <>
1186
DynamicCapability::Client Orphan<AnyPointer>::getAs<DynamicCapability>(InterfaceSchema schema);
1187
template <>
1188
DynamicStruct::Reader Orphan<AnyPointer>::getAsReader<DynamicStruct>(StructSchema schema) const;
1189
template <>
1190
DynamicList::Reader Orphan<AnyPointer>::getAsReader<DynamicList>(ListSchema schema) const;
1191
template <>
1192
DynamicCapability::Client Orphan<AnyPointer>::getAsReader<DynamicCapability>(
1193 1194
    InterfaceSchema schema) const;
template <>
1195
Orphan<DynamicStruct> Orphan<AnyPointer>::releaseAs<DynamicStruct>(StructSchema schema);
1196
template <>
1197
Orphan<DynamicList> Orphan<AnyPointer>::releaseAs<DynamicList>(ListSchema schema);
1198
template <>
1199
Orphan<DynamicCapability> Orphan<AnyPointer>::releaseAs<DynamicCapability>(
1200
    InterfaceSchema schema);
1201

Kenton Varda's avatar
Kenton Varda committed
1202
// =======================================================================================
Kenton Varda's avatar
Kenton Varda committed
1203
// Inline implementation details.
Kenton Varda's avatar
Kenton Varda committed
1204

1205
template <typename T>
1206
struct ToDynamic_<T, Kind::STRUCT> {
1207
  static inline DynamicStruct::Reader apply(const typename T::Reader& value) {
1208
    return DynamicStruct::Reader(Schema::from<T>(), value._reader);
1209
  }
1210
  static inline DynamicStruct::Builder apply(typename T::Builder& value) {
1211
    return DynamicStruct::Builder(Schema::from<T>(), value._builder);
1212 1213 1214 1215
  }
};

template <typename T>
1216
struct ToDynamic_<T, Kind::LIST> {
1217
  static inline DynamicList::Reader apply(const typename T::Reader& value) {
1218
    return DynamicList::Reader(Schema::from<T>(), value.reader);
1219
  }
1220
  static inline DynamicList::Builder apply(typename T::Builder& value) {
1221
    return DynamicList::Builder(Schema::from<T>(), value.builder);
1222 1223 1224
  }
};

1225 1226
template <typename T>
struct ToDynamic_<T, Kind::INTERFACE> {
1227 1228
  static inline DynamicCapability::Client apply(typename T::Client value) {
    return DynamicCapability::Client(kj::mv(value));
1229 1230 1231 1232 1233 1234
  }
  static inline DynamicCapability::Client apply(typename T::Client&& value) {
    return DynamicCapability::Client(kj::mv(value));
  }
};

1235
template <typename T>
1236 1237
ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromReader<T>>::apply(value);
1238 1239
}
template <typename T>
1240 1241
BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromBuilder<T>>::apply(value);
1242
}
1243
template <typename T>
1244
DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) {
1245
  return DynamicEnum(Schema::from<kj::Decay<T>>(), static_cast<uint16_t>(value));
1246
}
1247 1248 1249 1250
template <typename T>
typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value) {
  return typename FromServer<T>::Client(kj::mv(value));
}
1251

1252 1253 1254
inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {}
inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {}

1255
#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
1256 1257 1258
inline DynamicValue::Reader::Reader(cppType value) \
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType value) \
1259 1260 1261
    : type(typeTag), fieldName##Value(value) {} \
inline Orphan<DynamicValue>::Orphan(cppType value) \
    : type(DynamicValue::typeTag), fieldName##Value(value) {}
1262

Kenton Varda's avatar
Kenton Varda committed
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281
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) \
1282
inline DynamicValue::Reader::Reader(const cppType::Reader& value) \
1283 1284 1285 1286
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType::Builder value) \
    : type(typeTag), fieldName##Value(value) {}

Kenton Varda's avatar
Kenton Varda committed
1287 1288 1289 1290
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);
1291
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(AnyPointer, ANY_POINTER, anyPointer);
1292

Kenton Varda's avatar
Kenton Varda committed
1293
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
1294

1295
inline DynamicValue::Reader::Reader(DynamicCapability::Client& value)
1296 1297 1298 1299 1300 1301
    : 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)) {}
1302
inline DynamicValue::Builder::Builder(DynamicCapability::Client& value)
1303 1304 1305 1306
    : type(CAPABILITY), capabilityValue(value) {}
inline DynamicValue::Builder::Builder(DynamicCapability::Client&& value)
    : type(CAPABILITY), capabilityValue(kj::mv(value)) {}

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

1309
#define CAPNP_DECLARE_TYPE(discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1310
template <> \
1311
struct DynamicValue::Reader::AsImpl<typeName> { \
1312
  static ReaderFor<typeName> apply(const Reader& reader); \
Kenton Varda's avatar
Kenton Varda committed
1313 1314
}; \
template <> \
1315
struct DynamicValue::Builder::AsImpl<typeName> { \
1316
  static BuilderFor<typeName> apply(Builder& builder); \
Kenton Varda's avatar
Kenton Varda committed
1317 1318
};

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

template <typename T>
1353
struct DynamicValue::Reader::AsImpl<T, Kind::ENUM> {
1354
  static T apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1355
    return reader.as<DynamicEnum>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1356 1357 1358
  }
};
template <typename T>
1359
struct DynamicValue::Builder::AsImpl<T, Kind::ENUM> {
1360
  static T apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1361
    return builder.as<DynamicEnum>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1362 1363 1364 1365
  }
};

template <typename T>
1366
struct DynamicValue::Reader::AsImpl<T, Kind::STRUCT> {
1367
  static typename T::Reader apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1368
    return reader.as<DynamicStruct>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1369 1370 1371
  }
};
template <typename T>
1372
struct DynamicValue::Builder::AsImpl<T, Kind::STRUCT> {
1373
  static typename T::Builder apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1374
    return builder.as<DynamicStruct>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1375 1376 1377 1378
  }
};

template <typename T>
1379
struct DynamicValue::Reader::AsImpl<T, Kind::LIST> {
1380
  static typename T::Reader apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1381
    return reader.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1382 1383 1384
  }
};
template <typename T>
1385
struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
1386
  static typename T::Builder apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1387
    return builder.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1388 1389 1390
  }
};

1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403
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>();
  }
};

1404
inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {}
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422
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 <>
1423
struct DynamicValue::Pipeline::AsImpl<DynamicStruct, Kind::OTHER> {
1424 1425 1426
  static PipelineFor<DynamicStruct> apply(Pipeline& pipeline);
};
template <>
1427
struct DynamicValue::Pipeline::AsImpl<DynamicCapability, Kind::OTHER> {
1428 1429 1430
  static PipelineFor<DynamicCapability> apply(Pipeline& pipeline);
};

Kenton Varda's avatar
Kenton Varda committed
1431 1432
// -------------------------------------------------------------------

Kenton Varda's avatar
Kenton Varda committed
1433
template <typename T>
1434
typename T::Reader DynamicStruct::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1435 1436
  static_assert(kind<T>() == Kind::STRUCT,
                "DynamicStruct::Reader::as<T>() can only convert to struct types.");
1437
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1438 1439
  return typename T::Reader(reader);
}
1440

Kenton Varda's avatar
Kenton Varda committed
1441 1442 1443 1444
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.");
1445
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1446 1447 1448
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
1449
template <>
1450
inline DynamicStruct::Reader DynamicStruct::Reader::as<DynamicStruct>() const {
Kenton Varda's avatar
Kenton Varda committed
1451 1452 1453 1454 1455 1456 1457
  return *this;
}
template <>
inline DynamicStruct::Builder DynamicStruct::Builder::as<DynamicStruct>() {
  return *this;
}

1458
inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const {
1459
  return DynamicStruct::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
1460 1461
}

1462 1463 1464 1465 1466 1467 1468 1469 1470 1471
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);
}

1472 1473 1474 1475 1476 1477 1478 1479
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
1480 1481 1482
// -------------------------------------------------------------------

template <typename T>
1483
typename T::Reader DynamicList::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1484 1485
  static_assert(kind<T>() == Kind::LIST,
                "DynamicStruct::Reader::as<T>() can only convert to list types.");
1486
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1487 1488 1489 1490 1491 1492
  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.");
1493
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1494 1495 1496
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
1497
template <>
1498
inline DynamicList::Reader DynamicList::Reader::as<DynamicList>() const {
Kenton Varda's avatar
Kenton Varda committed
1499 1500 1501 1502 1503 1504 1505
  return *this;
}
template <>
inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
  return *this;
}

1506 1507
// -------------------------------------------------------------------

1508 1509 1510 1511 1512
template <typename T, typename>
inline DynamicCapability::Client::Client(T&& client)
    : Capability::Client(kj::mv(client)), schema(Schema::from<FromClient<T>>()) {}

template <typename T, typename>
1513 1514
inline DynamicCapability::Client::Client(kj::Own<T>&& server)
    : Client(server->getSchema(), kj::mv(server)) {}
1515
template <typename T>
1516 1517
inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own<T>&& server)
    : Capability::Client(kj::mv(server)), schema(schema) {}
1518 1519

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

template <>
inline DynamicCapability::Client Capability::Client::castAs<DynamicCapability>(
1573
    InterfaceSchema schema) {
1574 1575 1576 1577 1578
  return DynamicCapability::Client(schema, hook->addRef());
}

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

1579 1580 1581 1582 1583
template <typename T>
ReaderFor<T> ConstSchema::as() const {
  return DynamicValue::Reader(*this).as<T>();
}

1584
}  // namespace capnp
Kenton Varda's avatar
Kenton Varda committed
1585

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