dynamic.h 59 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
Kenton Varda's avatar
Kenton Varda committed
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
Kenton Varda's avatar
Kenton Varda committed
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
Kenton Varda's avatar
Kenton Varda committed
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
Kenton Varda's avatar
Kenton Varda committed
21 22 23 24 25 26 27 28 29 30 31 32

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

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

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

40
#include "schema.h"
Kenton Varda's avatar
Kenton Varda committed
41
#include "layout.h"
Kenton Varda's avatar
Kenton Varda committed
42
#include "message.h"
43
#include "any.h"
44
#include "capability.h"
Kenton Varda's avatar
Kenton Varda committed
45

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

class MessageReader;
class MessageBuilder;

struct DynamicValue {
52 53
  DynamicValue() = delete;

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

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

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

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

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

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

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

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

}  // namespace _ (private)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

215
  inline Reader(StructSchema schema, _::StructReader reader)
216
      : schema(schema), reader(reader) {}
217
  Reader(StructSchema schema, const _::OrphanBuilder& orphan);
Kenton Varda's avatar
Kenton Varda committed
218

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

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

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

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

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

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

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

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

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

Kenton Varda's avatar
Kenton Varda committed
260 261
  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
262
  // not actually traverse the value comparing it with the default, but simply returns true if the
Kenton Varda's avatar
Kenton Varda committed
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
  // 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);
279 280
  // Init a struct, list, or blob field.

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

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

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

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

307
  inline Builder(StructSchema schema, _::StructBuilder builder)
308
      : schema(schema), builder(builder) {}
309
  Builder(StructSchema schema, _::OrphanBuilder& orphan);
Kenton Varda's avatar
Kenton Varda committed
310

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

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

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

338
  inline StructSchema getSchema() { return schema; }
339

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

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

private:
  StructSchema schema;
348
  AnyPointer::Pipeline typeless;
349

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

  friend class Request<DynamicStruct, DynamicStruct>;
};

Kenton Varda's avatar
Kenton Varda committed
356 357 358 359
// -------------------------------------------------------------------

class DynamicList::Reader {
public:
360 361
  typedef DynamicList Reads;

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

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

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

372
  inline ListSchema getSchema() const { return schema; }
373

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

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

private:
382
  ListSchema schema;
383
  _::ListReader reader;
Kenton Varda's avatar
Kenton Varda committed
384

385
  Reader(ListSchema schema, _::ListReader reader): schema(schema), reader(reader) {}
386
  Reader(ListSchema schema, const _::OrphanBuilder& orphan);
Kenton Varda's avatar
Kenton Varda committed
387

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

class DynamicList::Builder {
public:
402 403
  typedef DynamicList Builds;

404 405
  inline Builder(): builder(ElementSize::VOID) {}
  inline Builder(decltype(nullptr)): builder(ElementSize::VOID) {}
Kenton Varda's avatar
Kenton Varda committed
406

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

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

415
  inline ListSchema getSchema() const { return schema; }
416

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

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

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

430
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
431 432

private:
433
  ListSchema schema;
434
  _::ListBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
435

436
  Builder(ListSchema schema, _::ListBuilder builder): schema(schema), builder(builder) {}
437
  Builder(ListSchema schema, _::OrphanBuilder& orphan);
Kenton Varda's avatar
Kenton Varda committed
438

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

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

454 455 456 457 458 459 460 461 462 463 464
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*>()>>
465
  inline Client(kj::Own<T>&& server);
466 467

  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
468
  typename T::Client as();
469 470 471 472
  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
  typename T::Client releaseAs();
  // Convert to any client type.

473
  Client upcast(InterfaceSchema requestedSchema);
474 475
  // Upcast to a superclass.  Throws an exception if `schema` is not a superclass.

476
  inline InterfaceSchema getSchema() { return schema; }
477 478

  Request<DynamicStruct, DynamicStruct> newRequest(
479
      InterfaceSchema::Method method, kj::Maybe<MessageSize> sizeHint = nullptr);
480
  Request<DynamicStruct, DynamicStruct> newRequest(
481
      kj::StringPtr methodName, kj::Maybe<MessageSize> sizeHint = nullptr);
482 483 484 485

private:
  InterfaceSchema schema;

486
  Client(InterfaceSchema schema, kj::Own<ClientHook>&& hook)
487 488 489
      : Capability::Client(kj::mv(hook)), schema(schema) {}

  template <typename T>
490
  inline Client(InterfaceSchema schema, kj::Own<T>&& server);
491 492 493 494 495 496 497

  friend struct Capability;
  friend struct DynamicStruct;
  friend struct DynamicList;
  friend struct DynamicValue;
  friend class Orphan<DynamicCapability>;
  friend class Orphan<DynamicValue>;
498
  friend class Orphan<AnyPointer>;
499 500 501 502 503 504 505 506 507 508 509 510 511 512
  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,
513
                                 CallContext<AnyPointer, AnyPointer> context) override final;
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538

  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;
539 540 541
  template <typename, typename>
  friend class CallContext;
  friend class RequestHook;
542 543 544 545 546 547 548 549 550 551 552 553 554 555
};

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

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

  friend class DynamicCapability::Server;
};

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

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

578 579 580 581 582 583 584 585 586
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
587 588 589

class DynamicValue::Reader {
public:
590 591
  typedef DynamicValue Reads;

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

Kenton Varda's avatar
Kenton Varda committed
621
  template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
622 623 624
  inline Reader(T&& value): Reader(toDynamic(kj::mv(value))) {}

  Reader(const Reader& other);
Kenton Varda's avatar
Kenton Varda committed
625 626
  Reader(Reader&& other) noexcept;
  ~Reader() noexcept(false);
627 628 629 630
  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
631 632

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

659
  inline Type getType() const { return type; }
Kenton Varda's avatar
Kenton Varda committed
660 661 662
  // Get the type of this value.

private:
663
  Type type;
Kenton Varda's avatar
Kenton Varda committed
664 665 666 667

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

    mutable DynamicCapability::Client capabilityValue;
    // Declared mutable because `Client`s normally cannot be const.
680 681 682

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

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

  friend class Orphanage;  // to speed up newOrphanCopy(DynamicValue::Reader)
Kenton Varda's avatar
Kenton Varda committed
690 691 692 693
};

class DynamicValue::Builder {
public:
694 695
  typedef DynamicValue Builds;

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

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

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

736
  inline Type getType() { return type; }
Kenton Varda's avatar
Kenton Varda committed
737 738
  // Get the type of this value.

739
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
740 741

private:
742
  Type type;
Kenton Varda's avatar
Kenton Varda committed
743 744 745 746

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

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

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

  friend class Orphan<DynamicValue>;
Kenton Varda's avatar
Kenton Varda committed
766 767
};

768 769 770 771
class DynamicValue::Pipeline {
public:
  typedef DynamicValue Pipelines;

772
  inline Pipeline(decltype(nullptr) n = nullptr);
773 774 775
  inline Pipeline(DynamicStruct::Pipeline&& value);
  inline Pipeline(DynamicCapability::Client&& value);

776
  Pipeline(Pipeline&& other) noexcept;
777 778 779 780 781 782
  Pipeline& operator=(Pipeline&& other);
  ~Pipeline() noexcept(false);

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

783 784 785
  inline Type getType() { return type; }
  // Get the type of this value.

786 787 788 789 790 791 792 793 794 795 796 797
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.
};

798 799 800 801 802 803 804
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
805

806 807 808 809 810 811 812 813 814 815 816
// -------------------------------------------------------------------
// Orphan <-> Dynamic glue

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

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

820
  DynamicStruct::Builder get();
821
  DynamicStruct::Reader getReader() const;
822

823 824 825 826 827 828 829 830
  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; }
831 832 833 834 835 836 837 838 839 840 841 842

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;
843
  friend class Orphan<DynamicValue>;
844
  friend class Orphan<AnyPointer>;
845
  friend class MessageBuilder;
846 847 848 849 850 851 852 853 854 855
};

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

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

859
  DynamicList::Builder get();
860
  DynamicList::Reader getReader() const;
861

862 863 864 865 866 867
  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>.

868 869
  // TODO(someday): Support truncate().

870 871
  inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
  inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
872 873 874 875 876 877 878 879 880 881 882 883

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;
884
  friend class Orphan<DynamicValue>;
885
  friend class Orphan<AnyPointer>;
886 887
};

888 889 890 891 892 893 894 895
template <>
class Orphan<DynamicCapability> {
public:
  Orphan() = default;
  KJ_DISALLOW_COPY(Orphan);
  Orphan(Orphan&&) = default;
  Orphan& operator=(Orphan&&) = default;

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

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

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

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

  _::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;
995
  friend struct AnyPointer;
996 997 998 999
  friend class Orphanage;
};

template <typename T>
1000
inline Orphan<DynamicValue>::Orphan(Orphan<T>&& other)
1001 1002
    : Orphan(other.get(), kj::mv(other.builder)) {}

1003 1004
inline Orphan<DynamicValue>::Orphan(Orphan<AnyPointer>&& other)
    : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {}
1005

1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
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));
}

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

1024 1025 1026
template <typename T>
Orphan<T> Orphan<DynamicValue>::releaseAs() {
  get().as<T>();  // type check
1027
  type = DynamicValue::UNKNOWN;
1028 1029 1030
  return Orphan<T>(kj::mv(builder));
}

1031
template <>
1032
Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>();
1033 1034 1035 1036
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>();
template <>
Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>();
1037 1038
template <>
Orphan<DynamicCapability> Orphan<DynamicValue>::releaseAs<DynamicCapability>();
1039

1040
template <>
1041
struct Orphanage::GetInnerBuilder<DynamicStruct, Kind::OTHER> {
1042 1043 1044 1045 1046 1047
  static inline _::StructBuilder apply(DynamicStruct::Builder& t) {
    return t.builder;
  }
};

template <>
1048
struct Orphanage::GetInnerBuilder<DynamicList, Kind::OTHER> {
1049 1050 1051 1052 1053 1054 1055
  static inline _::ListBuilder apply(DynamicList::Builder& t) {
    return t.builder;
  }
};

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

template <>
inline Orphan<DynamicList> Orphanage::newOrphanCopy<DynamicList::Reader>(
1063
    DynamicList::Reader copyFrom) const {
1064 1065
  return Orphan<DynamicList>(copyFrom.getSchema(),
      _::OrphanBuilder::copy(arena, capTable, copyFrom.reader));
1066 1067
}

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

1075 1076
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
1077
    DynamicValue::Reader copyFrom) const;
1078

1079
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
1080 1081

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

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

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

1132
}  // namespace _ (private)
Kenton Varda's avatar
Kenton Varda committed
1133

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

1193 1194
// We have to declare the methods below inline because Clang and GCC disagree about how to mangle
// their symbol names.
1195
template <>
1196 1197 1198
inline DynamicStruct::Builder Orphan<AnyPointer>::getAs<DynamicStruct>(StructSchema schema) {
  return DynamicStruct::Builder(schema, builder);
}
1199
template <>
1200 1201 1202 1203
inline DynamicStruct::Reader Orphan<AnyPointer>::getAsReader<DynamicStruct>(
    StructSchema schema) const {
  return DynamicStruct::Reader(schema, builder);
}
1204
template <>
1205 1206 1207
inline Orphan<DynamicStruct> Orphan<AnyPointer>::releaseAs<DynamicStruct>(StructSchema schema) {
  return Orphan<DynamicStruct>(schema, kj::mv(builder));
}
1208
template <>
1209 1210 1211
inline DynamicList::Builder Orphan<AnyPointer>::getAs<DynamicList>(ListSchema schema) {
  return DynamicList::Builder(schema, builder);
}
1212
template <>
1213 1214 1215
inline DynamicList::Reader Orphan<AnyPointer>::getAsReader<DynamicList>(ListSchema schema) const {
  return DynamicList::Reader(schema, builder);
}
1216
template <>
1217 1218 1219
inline Orphan<DynamicList> Orphan<AnyPointer>::releaseAs<DynamicList>(ListSchema schema) {
  return Orphan<DynamicList>(schema, kj::mv(builder));
}
1220
template <>
1221 1222 1223 1224
inline DynamicCapability::Client Orphan<AnyPointer>::getAs<DynamicCapability>(
    InterfaceSchema schema) {
  return DynamicCapability::Client(schema, builder.asCapability());
}
1225
template <>
1226 1227 1228 1229
inline DynamicCapability::Client Orphan<AnyPointer>::getAsReader<DynamicCapability>(
    InterfaceSchema schema) const {
  return DynamicCapability::Client(schema, builder.asCapability());
}
1230
template <>
1231 1232 1233 1234
inline Orphan<DynamicCapability> Orphan<AnyPointer>::releaseAs<DynamicCapability>(
    InterfaceSchema schema) {
  return Orphan<DynamicCapability>(schema, kj::mv(builder));
}
1235

Kenton Varda's avatar
Kenton Varda committed
1236
// =======================================================================================
Kenton Varda's avatar
Kenton Varda committed
1237
// Inline implementation details.
Kenton Varda's avatar
Kenton Varda committed
1238

1239
template <typename T>
1240
struct ToDynamic_<T, Kind::STRUCT> {
1241
  static inline DynamicStruct::Reader apply(const typename T::Reader& value) {
1242
    return DynamicStruct::Reader(Schema::from<T>(), value._reader);
1243
  }
1244
  static inline DynamicStruct::Builder apply(typename T::Builder& value) {
1245
    return DynamicStruct::Builder(Schema::from<T>(), value._builder);
1246 1247 1248 1249
  }
};

template <typename T>
1250
struct ToDynamic_<T, Kind::LIST> {
1251
  static inline DynamicList::Reader apply(const typename T::Reader& value) {
1252
    return DynamicList::Reader(Schema::from<T>(), value.reader);
1253
  }
1254
  static inline DynamicList::Builder apply(typename T::Builder& value) {
1255
    return DynamicList::Builder(Schema::from<T>(), value.builder);
1256 1257 1258
  }
};

1259 1260
template <typename T>
struct ToDynamic_<T, Kind::INTERFACE> {
1261 1262
  static inline DynamicCapability::Client apply(typename T::Client value) {
    return DynamicCapability::Client(kj::mv(value));
1263 1264 1265 1266 1267 1268
  }
  static inline DynamicCapability::Client apply(typename T::Client&& value) {
    return DynamicCapability::Client(kj::mv(value));
  }
};

1269
template <typename T>
1270 1271
ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromReader<T>>::apply(value);
1272 1273
}
template <typename T>
1274 1275
BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromBuilder<T>>::apply(value);
1276
}
1277
template <typename T>
1278
DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) {
1279
  return DynamicEnum(Schema::from<kj::Decay<T>>(), static_cast<uint16_t>(value));
1280
}
1281 1282 1283 1284
template <typename T>
typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value) {
  return typename FromServer<T>::Client(kj::mv(value));
}
1285

1286 1287 1288
inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {}
inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {}

1289
#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
1290 1291 1292
inline DynamicValue::Reader::Reader(cppType value) \
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType value) \
1293 1294 1295
    : type(typeTag), fieldName##Value(value) {} \
inline Orphan<DynamicValue>::Orphan(cppType value) \
    : type(DynamicValue::typeTag), fieldName##Value(value) {}
1296

Kenton Varda's avatar
Kenton Varda committed
1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315
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) \
1316
inline DynamicValue::Reader::Reader(const cppType::Reader& value) \
1317 1318 1319 1320
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType::Builder value) \
    : type(typeTag), fieldName##Value(value) {}

Kenton Varda's avatar
Kenton Varda committed
1321 1322 1323 1324
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);
1325
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(AnyPointer, ANY_POINTER, anyPointer);
1326

Kenton Varda's avatar
Kenton Varda committed
1327
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
1328

1329
inline DynamicValue::Reader::Reader(DynamicCapability::Client& value)
1330 1331 1332 1333 1334 1335
    : 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)) {}
1336
inline DynamicValue::Builder::Builder(DynamicCapability::Client& value)
1337 1338 1339 1340
    : type(CAPABILITY), capabilityValue(value) {}
inline DynamicValue::Builder::Builder(DynamicCapability::Client&& value)
    : type(CAPABILITY), capabilityValue(kj::mv(value)) {}

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

1343
#define CAPNP_DECLARE_TYPE(discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1344
template <> \
1345
struct DynamicValue::Reader::AsImpl<typeName> { \
1346
  static ReaderFor<typeName> apply(const Reader& reader); \
Kenton Varda's avatar
Kenton Varda committed
1347 1348
}; \
template <> \
1349
struct DynamicValue::Builder::AsImpl<typeName> { \
1350
  static BuilderFor<typeName> apply(Builder& builder); \
Kenton Varda's avatar
Kenton Varda committed
1351 1352
};

1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372
//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
1373 1374 1375
#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
1376 1377
// ReaderFor<> and BuilderFor<> wrappers, it works.
template <>
1378
struct DynamicValue::Reader::AsImpl<Void> {
1379
  static Void apply(const Reader& reader);
Kenton Varda's avatar
Kenton Varda committed
1380 1381
};
template <>
1382
struct DynamicValue::Builder::AsImpl<Void> {
1383
  static Void apply(Builder& builder);
Kenton Varda's avatar
Kenton Varda committed
1384 1385 1386
};

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

template <typename T>
1400
struct DynamicValue::Reader::AsImpl<T, Kind::STRUCT> {
1401
  static typename T::Reader apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1402
    return reader.as<DynamicStruct>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1403 1404 1405
  }
};
template <typename T>
1406
struct DynamicValue::Builder::AsImpl<T, Kind::STRUCT> {
1407
  static typename T::Builder apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1408
    return builder.as<DynamicStruct>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1409 1410 1411 1412
  }
};

template <typename T>
1413
struct DynamicValue::Reader::AsImpl<T, Kind::LIST> {
1414
  static typename T::Reader apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1415
    return reader.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1416 1417 1418
  }
};
template <typename T>
1419
struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
1420
  static typename T::Builder apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1421
    return builder.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1422 1423 1424
  }
};

1425 1426
template <typename T>
struct DynamicValue::Reader::AsImpl<T, Kind::INTERFACE> {
1427
  static typename T::Client apply(const Reader& reader) {
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
    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>();
  }
};

1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
template <>
struct DynamicValue::Reader::AsImpl<DynamicValue> {
  static DynamicValue::Reader apply(const Reader& reader) {
    return reader;
  }
};
template <>
struct DynamicValue::Builder::AsImpl<DynamicValue> {
  static DynamicValue::Builder apply(Builder& builder) {
    return builder;
  }
};

1451
inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {}
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469
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 <>
1470
struct DynamicValue::Pipeline::AsImpl<DynamicStruct, Kind::OTHER> {
1471 1472 1473
  static PipelineFor<DynamicStruct> apply(Pipeline& pipeline);
};
template <>
1474
struct DynamicValue::Pipeline::AsImpl<DynamicCapability, Kind::OTHER> {
1475 1476 1477
  static PipelineFor<DynamicCapability> apply(Pipeline& pipeline);
};

Kenton Varda's avatar
Kenton Varda committed
1478 1479
// -------------------------------------------------------------------

Kenton Varda's avatar
Kenton Varda committed
1480
template <typename T>
1481
typename T::Reader DynamicStruct::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1482 1483
  static_assert(kind<T>() == Kind::STRUCT,
                "DynamicStruct::Reader::as<T>() can only convert to struct types.");
1484
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1485 1486
  return typename T::Reader(reader);
}
1487

Kenton Varda's avatar
Kenton Varda committed
1488 1489 1490 1491
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.");
1492
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1493 1494 1495
  return typename T::Builder(builder);
}

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

1505
inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const {
1506
  return DynamicStruct::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
1507 1508
}

1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
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);
}

1519 1520 1521 1522 1523 1524 1525 1526
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
1527 1528 1529
// -------------------------------------------------------------------

template <typename T>
1530
typename T::Reader DynamicList::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1531 1532
  static_assert(kind<T>() == Kind::LIST,
                "DynamicStruct::Reader::as<T>() can only convert to list types.");
1533
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1534 1535 1536 1537 1538 1539
  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.");
1540
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1541 1542 1543
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
1544
template <>
1545
inline DynamicList::Reader DynamicList::Reader::as<DynamicList>() const {
Kenton Varda's avatar
Kenton Varda committed
1546 1547 1548 1549 1550 1551 1552
  return *this;
}
template <>
inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
  return *this;
}

1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
template <>
inline AnyList::Reader DynamicList::Reader::as<AnyList>() const {
  return AnyList::Reader(reader);
}

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

1563 1564
// -------------------------------------------------------------------

1565 1566 1567 1568 1569
template <typename T, typename>
inline DynamicCapability::Client::Client(T&& client)
    : Capability::Client(kj::mv(client)), schema(Schema::from<FromClient<T>>()) {}

template <typename T, typename>
1570 1571
inline DynamicCapability::Client::Client(kj::Own<T>&& server)
    : Client(server->getSchema(), kj::mv(server)) {}
1572
template <typename T>
1573 1574
inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own<T>&& server)
    : Capability::Client(kj::mv(server)), schema(schema) {}
1575 1576

template <typename T, typename>
1577
typename T::Client DynamicCapability::Client::as() {
1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601
  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(
1602 1603
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).getAs<DynamicStruct>(resultType);
1604 1605
}
inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::initResults(
1606 1607
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).initAs<DynamicStruct>(resultType);
1608 1609
}
inline void CallContext<DynamicStruct, DynamicStruct>::setResults(DynamicStruct::Reader value) {
1610
  hook->getResults(value.totalSize()).setAs<DynamicStruct>(value);
1611 1612
}
inline void CallContext<DynamicStruct, DynamicStruct>::adoptResults(Orphan<DynamicStruct>&& value) {
1613
  hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value));
1614 1615
}
inline Orphanage CallContext<DynamicStruct, DynamicStruct>::getResultsOrphanage(
1616 1617
    kj::Maybe<MessageSize> sizeHint) {
  return Orphanage::getForMessageContaining(hook->getResults(sizeHint));
1618
}
Kenton Varda's avatar
Kenton Varda committed
1619 1620 1621 1622 1623
template <typename SubParams>
inline kj::Promise<void> CallContext<DynamicStruct, DynamicStruct>::tailCall(
    Request<SubParams, DynamicStruct>&& tailRequest) {
  return hook->tailCall(kj::mv(tailRequest.hook));
}
1624 1625
inline void CallContext<DynamicStruct, DynamicStruct>::allowCancellation() {
  hook->allowCancellation();
1626 1627 1628 1629
}

template <>
inline DynamicCapability::Client Capability::Client::castAs<DynamicCapability>(
1630
    InterfaceSchema schema) {
1631 1632 1633 1634 1635
  return DynamicCapability::Client(schema, hook->addRef());
}

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

1636 1637 1638 1639 1640
template <typename T>
ReaderFor<T> ConstSchema::as() const {
  return DynamicValue::Reader(*this).as<T>();
}

1641
}  // namespace capnp
Kenton Varda's avatar
Kenton Varda committed
1642

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