dynamic.h 56 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
#include "schema.h"
Kenton Varda's avatar
Kenton Varda committed
37
#include "layout.h"
Kenton Varda's avatar
Kenton Varda committed
38
#include "message.h"
39
#include "any.h"
40
#include "capability.h"
Kenton Varda's avatar
Kenton Varda committed
41

42
namespace capnp {
Kenton Varda's avatar
Kenton Varda committed
43 44 45 46 47

class MessageReader;
class MessageBuilder;

struct DynamicValue {
48 49
  DynamicValue() = delete;

50
  enum Type {
51 52 53 54 55
    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.

56 57 58 59 60 61 62 63 64 65
    VOID,
    BOOL,
    INT,
    UINT,
    FLOAT,
    TEXT,
    DATA,
    LIST,
    ENUM,
    STRUCT,
66
    CAPABILITY,
67
    ANY_POINTER
68 69
  };

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

93 94 95 96
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; };
97
template <> struct DynamicTypeFor_<Kind::INTERFACE> { typedef DynamicCapability Type; };
98 99 100 101

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

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

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

class DynamicEnum {
public:
  DynamicEnum() = default;
116 117
  inline DynamicEnum(EnumSchema::Enumerant enumerant)
      : schema(enumerant.getContainingEnum()), value(enumerant.getOrdinal()) {}
118 119
  inline DynamicEnum(EnumSchema schema, uint16_t value)
      : schema(schema), value(value) {}
Kenton Varda's avatar
Kenton Varda committed
120

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

Kenton Varda's avatar
Kenton Varda committed
124
  template <typename T>
125
  inline T as() const { return static_cast<T>(asImpl(typeId<T>())); }
Kenton Varda's avatar
Kenton Varda committed
126 127
  // Cast to a native enum type.

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

130
  kj::Maybe<EnumSchema::Enumerant> getEnumerant() const;
Kenton Varda's avatar
Kenton Varda committed
131 132 133 134
  // 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.

135
  inline uint16_t getRaw() const { return value; }
Kenton Varda's avatar
Kenton Varda committed
136 137 138
  // Returns the raw underlying enum value.

private:
139
  EnumSchema schema;
Kenton Varda's avatar
Kenton Varda committed
140 141
  uint16_t value;

142
  uint16_t asImpl(uint64_t requestedTypeId) const;
Kenton Varda's avatar
Kenton Varda committed
143 144

  friend struct DynamicStruct;
Kenton Varda's avatar
Kenton Varda committed
145
  friend struct DynamicList;
146
  friend struct DynamicValue;
147 148
  template <typename T>
  friend DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value);
Kenton Varda's avatar
Kenton Varda committed
149 150 151 152 153 154
};

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

class DynamicStruct::Reader {
public:
155 156
  typedef DynamicStruct Reads;

Kenton Varda's avatar
Kenton Varda committed
157 158
  Reader() = default;

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

162
  inline MessageSize totalSize() const { return reader.totalSize().asPublic(); }
163

Kenton Varda's avatar
Kenton Varda committed
164
  template <typename T>
165
  typename T::Reader as() const;
Kenton Varda's avatar
Kenton Varda committed
166 167
  // Convert the dynamic struct to its compiled-in type.

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

Kenton Varda's avatar
Kenton Varda committed
170 171
  DynamicValue::Reader get(StructSchema::Field field) const;
  // Read the given field value.
Kenton Varda's avatar
Kenton Varda committed
172

Kenton Varda's avatar
Kenton Varda committed
173 174
  bool has(StructSchema::Field field) const;
  // Tests whether the given field is set to its default value.  For pointer values, this does
175
  // not actually traverse the value comparing it with the default, but simply returns true if the
176 177 178
  // 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
179 180 181 182 183 184 185

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

187 188
  DynamicValue::Reader get(kj::StringPtr name) const;
  bool has(kj::StringPtr name) const;
Kenton Varda's avatar
Kenton Varda committed
189
  // Shortcuts to access fields by name.  These throw exceptions if no such field exists.
Kenton Varda's avatar
Kenton Varda committed
190 191

private:
192
  StructSchema schema;
193
  _::StructReader reader;
Kenton Varda's avatar
Kenton Varda committed
194

195
  inline Reader(StructSchema schema, _::StructReader reader)
196
      : schema(schema), reader(reader) {}
Kenton Varda's avatar
Kenton Varda committed
197

Kenton Varda's avatar
Kenton Varda committed
198 199 200
  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
201

Kenton Varda's avatar
Kenton Varda committed
202
  template <typename T, Kind K>
203
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
204 205 206 207
  friend class DynamicStruct::Builder;
  friend struct DynamicList;
  friend class MessageReader;
  friend class MessageBuilder;
208 209
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
210
  friend kj::StringTree _::structString(
211
      _::StructReader reader, const _::RawSchema& schema);
212
  friend class Orphanage;
213
  friend class Orphan<DynamicStruct>;
214
  friend class Orphan<DynamicValue>;
215
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
216 217 218 219
};

class DynamicStruct::Builder {
public:
220 221
  typedef DynamicStruct Builds;

222
  Builder() = default;
223
  inline Builder(decltype(nullptr)) {}
Kenton Varda's avatar
Kenton Varda committed
224

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

228
  inline MessageSize totalSize() const { return asReader().totalSize(); }
229

Kenton Varda's avatar
Kenton Varda committed
230
  template <typename T>
Kenton Varda's avatar
Kenton Varda committed
231
  typename T::Builder as();
Kenton Varda's avatar
Kenton Varda committed
232 233
  // Cast to a particular struct type.

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

Kenton Varda's avatar
Kenton Varda committed
236 237
  DynamicValue::Builder get(StructSchema::Field field);
  // Read the given field value.
238

Kenton Varda's avatar
Kenton Varda committed
239 240
  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
241
  // not actually traverse the value comparing it with the default, but simply returns true if the
Kenton Varda's avatar
Kenton Varda committed
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
  // 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);
258 259
  // Init a struct, list, or blob field.

260 261 262 263 264
  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
265 266 267 268
  void clear(StructSchema::Field field);
  // Clear a field, setting it to its default value.  For pointer fields, this actually makes the
  // field null.

269 270 271 272 273 274
  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);
275 276
  void adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan);
  Orphan<DynamicValue> disown(kj::StringPtr name);
Kenton Varda's avatar
Kenton Varda committed
277 278
  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
279

280
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
281 282

private:
283
  StructSchema schema;
284
  _::StructBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
285

286
  inline Builder(StructSchema schema, _::StructBuilder builder)
287
      : schema(schema), builder(builder) {}
Kenton Varda's avatar
Kenton Varda committed
288

Kenton Varda's avatar
Kenton Varda committed
289 290 291 292
  bool isSetInUnion(StructSchema::Field field);
  void verifySetInUnion(StructSchema::Field field);
  void setInUnion(StructSchema::Field field);

Kenton Varda's avatar
Kenton Varda committed
293
  template <typename T, Kind k>
294
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
295 296 297
  friend struct DynamicList;
  friend class MessageReader;
  friend class MessageBuilder;
298 299
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
300 301
  friend class Orphanage;
  friend class Orphan<DynamicStruct>;
302
  friend class Orphan<DynamicValue>;
303
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
304 305
};

306 307 308 309 310 311 312 313 314 315
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.

316
  inline StructSchema getSchema() { return schema; }
317

318
  DynamicValue::Pipeline get(StructSchema::Field field);
319 320
  // Read the given field value.

321
  DynamicValue::Pipeline get(kj::StringPtr name);
322 323 324 325
  // Get by string name.

private:
  StructSchema schema;
326
  AnyPointer::Pipeline typeless;
327

328
  inline explicit Pipeline(StructSchema schema, AnyPointer::Pipeline&& typeless)
329 330 331 332 333
      : schema(schema), typeless(kj::mv(typeless)) {}

  friend class Request<DynamicStruct, DynamicStruct>;
};

Kenton Varda's avatar
Kenton Varda committed
334 335 336 337
// -------------------------------------------------------------------

class DynamicList::Reader {
public:
338 339
  typedef DynamicList Reads;

Kenton Varda's avatar
Kenton Varda committed
340 341
  Reader() = default;

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

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

350
  inline ListSchema getSchema() const { return schema; }
351

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

355
  typedef _::IndexingIterator<const Reader, DynamicValue::Reader> Iterator;
356 357
  inline Iterator begin() const { return Iterator(this, 0); }
  inline Iterator end() const { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
358 359

private:
360
  ListSchema schema;
361
  _::ListReader reader;
Kenton Varda's avatar
Kenton Varda committed
362

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

Kenton Varda's avatar
Kenton Varda committed
365
  template <typename T, Kind k>
366
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
367 368
  friend struct DynamicStruct;
  friend class DynamicList::Builder;
369 370
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
371
  friend class Orphanage;
372
  friend class Orphan<DynamicList>;
373
  friend class Orphan<DynamicValue>;
374
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
375 376 377 378
};

class DynamicList::Builder {
public:
379 380
  typedef DynamicList Builds;

381
  Builder() = default;
382
  inline Builder(decltype(nullptr)) {}
Kenton Varda's avatar
Kenton Varda committed
383

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

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

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

394
  inline uint size() const { return builder.size() / ELEMENTS; }
395 396
  DynamicValue::Builder operator[](uint index);
  void set(uint index, const DynamicValue::Reader& value);
Kenton Varda's avatar
Kenton Varda committed
397
  DynamicValue::Builder init(uint index, uint size);
398 399
  void adopt(uint index, Orphan<DynamicValue>&& orphan);
  Orphan<DynamicValue> disown(uint index);
Kenton Varda's avatar
Kenton Varda committed
400

401
  typedef _::IndexingIterator<Builder, DynamicStruct::Builder> Iterator;
402 403
  inline Iterator begin() { return Iterator(this, 0); }
  inline Iterator end() { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
404

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

407
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
408 409

private:
410
  ListSchema schema;
411
  _::ListBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
412

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

Kenton Varda's avatar
Kenton Varda committed
415
  template <typename T, Kind k>
416
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
417
  friend struct DynamicStruct;
418 419
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
420 421 422 423
  friend class Orphanage;
  template <typename T, Kind k>
  friend struct _::OrphanGetImpl;
  friend class Orphan<DynamicList>;
424
  friend class Orphan<DynamicValue>;
425
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
426 427 428 429
};

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

430 431 432 433 434 435 436 437 438 439 440
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*>()>>
441
  inline Client(kj::Own<T>&& server);
442 443

  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
444
  typename T::Client as();
445 446 447 448
  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
  typename T::Client releaseAs();
  // Convert to any client type.

449
  Client upcast(InterfaceSchema requestedSchema);
450 451
  // Upcast to a superclass.  Throws an exception if `schema` is not a superclass.

452
  inline InterfaceSchema getSchema() { return schema; }
453 454

  Request<DynamicStruct, DynamicStruct> newRequest(
455
      InterfaceSchema::Method method, kj::Maybe<MessageSize> sizeHint = nullptr);
456
  Request<DynamicStruct, DynamicStruct> newRequest(
457
      kj::StringPtr methodName, kj::Maybe<MessageSize> sizeHint = nullptr);
458 459 460 461

private:
  InterfaceSchema schema;

462
  Client(InterfaceSchema schema, kj::Own<ClientHook>&& hook)
463 464 465
      : Capability::Client(kj::mv(hook)), schema(schema) {}

  template <typename T>
466
  inline Client(InterfaceSchema schema, kj::Own<T>&& server);
467 468 469 470 471 472 473

  friend struct Capability;
  friend struct DynamicStruct;
  friend struct DynamicList;
  friend struct DynamicValue;
  friend class Orphan<DynamicCapability>;
  friend class Orphan<DynamicValue>;
474
  friend class Orphan<AnyPointer>;
475 476 477 478 479 480 481 482 483 484 485 486 487 488
  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,
489
                                 CallContext<AnyPointer, AnyPointer> context) override final;
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514

  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;
515 516 517
  template <typename, typename>
  friend class CallContext;
  friend class RequestHook;
518 519 520 521 522 523 524 525 526 527 528 529 530 531
};

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();
532 533
  DynamicStruct::Builder getResults(kj::Maybe<MessageSize> sizeHint = nullptr);
  DynamicStruct::Builder initResults(kj::Maybe<MessageSize> sizeHint = nullptr);
534 535
  void setResults(DynamicStruct::Reader value);
  void adoptResults(Orphan<DynamicStruct>&& value);
536
  Orphanage getResultsOrphanage(kj::Maybe<MessageSize> sizeHint = nullptr);
Kenton Varda's avatar
Kenton Varda committed
537 538
  template <typename SubParams>
  kj::Promise<void> tailCall(Request<SubParams, DynamicStruct>&& tailRequest);
539
  void allowCancellation();
540 541 542 543 544 545 546 547 548 549 550

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

  friend class DynamicCapability::Server;
};

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

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

554 555 556 557 558 559
template <> struct ReaderFor_ <DynamicEnum, Kind::UNKNOWN> { typedef DynamicEnum Type; };
template <> struct BuilderFor_<DynamicEnum, Kind::UNKNOWN> { typedef DynamicEnum Type; };
template <> struct ReaderFor_ <DynamicStruct, Kind::UNKNOWN> { typedef DynamicStruct::Reader Type; };
template <> struct BuilderFor_<DynamicStruct, Kind::UNKNOWN> { typedef DynamicStruct::Builder Type; };
template <> struct ReaderFor_ <DynamicList, Kind::UNKNOWN> { typedef DynamicList::Reader Type; };
template <> struct BuilderFor_<DynamicList, Kind::UNKNOWN> { typedef DynamicList::Builder Type; };
560 561 562
template <> struct ReaderFor_ <DynamicCapability, Kind::UNKNOWN> { typedef DynamicCapability::Client Type; };
template <> struct BuilderFor_<DynamicCapability, Kind::UNKNOWN> { typedef DynamicCapability::Client Type; };
template <> struct PipelineFor_<DynamicCapability, Kind::UNKNOWN> { typedef DynamicCapability::Client Type; };
Kenton Varda's avatar
Kenton Varda committed
563 564 565

class DynamicValue::Reader {
public:
566 567
  typedef DynamicValue Reads;

568
  inline Reader(decltype(nullptr) n = nullptr);  // UNKNOWN
569
  inline Reader(Void value);
570 571 572 573 574 575 576 577 578 579 580 581 582 583
  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
584
  inline Reader(const char* value);  // Text
585 586 587
  inline Reader(const Text::Reader& value);
  inline Reader(const Data::Reader& value);
  inline Reader(const DynamicList::Reader& value);
588
  inline Reader(DynamicEnum value);
589
  inline Reader(const DynamicStruct::Reader& value);
590
  inline Reader(const AnyPointer::Reader& value);
591
  inline Reader(DynamicCapability::Client& value);
592 593 594
  inline Reader(DynamicCapability::Client&& value);
  template <typename T, typename = kj::EnableIf<kj::canConvert<T*, DynamicCapability::Server*>()>>
  inline Reader(kj::Own<T>&& value);
595
  Reader(ConstSchema constant);
Kenton Varda's avatar
Kenton Varda committed
596

Kenton Varda's avatar
Kenton Varda committed
597
  template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
598 599 600
  inline Reader(T&& value): Reader(toDynamic(kj::mv(value))) {}

  Reader(const Reader& other);
Kenton Varda's avatar
Kenton Varda committed
601 602
  Reader(Reader&& other) noexcept;
  ~Reader() noexcept(false);
603 604 605 606
  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
607 608

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

634
  inline Type getType() const { return type; }
Kenton Varda's avatar
Kenton Varda committed
635 636 637
  // Get the type of this value.

private:
638
  Type type;
Kenton Varda's avatar
Kenton Varda committed
639 640 641 642

  union {
    Void voidValue;
    bool boolValue;
643 644 645
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
646 647 648 649 650
    Text::Reader textValue;
    Data::Reader dataValue;
    DynamicList::Reader listValue;
    DynamicEnum enumValue;
    DynamicStruct::Reader structValue;
651
    AnyPointer::Reader anyPointerValue;
652 653 654

    mutable DynamicCapability::Client capabilityValue;
    // Declared mutable because `Client`s normally cannot be const.
655 656 657

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

660
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
661
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
662
  // specialization.  Has a method apply() which does the work.
663 664

  friend class Orphanage;  // to speed up newOrphanCopy(DynamicValue::Reader)
Kenton Varda's avatar
Kenton Varda committed
665 666 667 668
};

class DynamicValue::Builder {
public:
669 670
  typedef DynamicValue Builds;

671
  inline Builder(decltype(nullptr) n = nullptr);  // UNKNOWN
672
  inline Builder(Void value);
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
  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);
692
  inline Builder(AnyPointer::Builder value);
693
  inline Builder(DynamicCapability::Client& value);
694
  inline Builder(DynamicCapability::Client&& value);
Kenton Varda's avatar
Kenton Varda committed
695

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

699
  Builder(Builder& other);
Kenton Varda's avatar
Kenton Varda committed
700 701
  Builder(Builder&& other) noexcept;
  ~Builder() noexcept(false);
702 703 704 705 706
  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
707
  template <typename T>
708
  inline BuilderFor<T> as() { return AsImpl<T>::apply(*this); }
Kenton Varda's avatar
Kenton Varda committed
709
  // See DynamicValue::Reader::as().
Kenton Varda's avatar
Kenton Varda committed
710

711
  inline Type getType() { return type; }
Kenton Varda's avatar
Kenton Varda committed
712 713
  // Get the type of this value.

714
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
715 716

private:
717
  Type type;
Kenton Varda's avatar
Kenton Varda committed
718 719 720 721

  union {
    Void voidValue;
    bool boolValue;
722 723 724
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
725 726 727 728 729
    Text::Builder textValue;
    Data::Builder dataValue;
    DynamicList::Builder listValue;
    DynamicEnum enumValue;
    DynamicStruct::Builder structValue;
730
    AnyPointer::Builder anyPointerValue;
731 732 733

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

736
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
737
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
738
  // specialization.  Has a method apply() which does the work.
739 740

  friend class Orphan<DynamicValue>;
Kenton Varda's avatar
Kenton Varda committed
741 742
};

743 744 745 746
class DynamicValue::Pipeline {
public:
  typedef DynamicValue Pipelines;

747
  inline Pipeline(decltype(nullptr) n = nullptr);
748 749 750
  inline Pipeline(DynamicStruct::Pipeline&& value);
  inline Pipeline(DynamicCapability::Client&& value);

751
  Pipeline(Pipeline&& other) noexcept;
752 753 754 755 756 757
  Pipeline& operator=(Pipeline&& other);
  ~Pipeline() noexcept(false);

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

758 759 760
  inline Type getType() { return type; }
  // Get the type of this value.

761 762 763 764 765 766 767 768 769 770 771 772
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.
};

773 774 775 776 777 778 779
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
780

781 782 783 784 785 786 787 788 789 790 791
// -------------------------------------------------------------------
// Orphan <-> Dynamic glue

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

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

795
  DynamicStruct::Builder get();
796
  DynamicStruct::Reader getReader() const;
797

798 799 800 801 802 803 804 805
  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; }
806 807 808 809 810 811 812 813 814 815 816 817

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;
818
  friend class Orphan<DynamicValue>;
819
  friend class Orphan<AnyPointer>;
820
  friend class MessageBuilder;
821 822 823 824 825 826 827 828 829 830
};

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

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

834
  DynamicList::Builder get();
835
  DynamicList::Reader getReader() const;
836

837 838 839 840 841 842 843 844
  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>.

  inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
  inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
845 846 847 848 849 850 851 852 853 854 855 856

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;
857
  friend class Orphan<DynamicValue>;
858
  friend class Orphan<AnyPointer>;
859 860
};

861 862 863 864 865 866 867 868
template <>
class Orphan<DynamicCapability> {
public:
  Orphan() = default;
  KJ_DISALLOW_COPY(Orphan);
  Orphan(Orphan&&) = default;
  Orphan& operator=(Orphan&&) = default;

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

872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
  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>;
896
  friend class Orphan<AnyPointer>;
897 898
};

899 900 901
template <>
class Orphan<DynamicValue> {
public:
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918
  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);
919 920 921
  Orphan(Orphan&&) = default;
  template <typename T>
  Orphan(Orphan<T>&&);
922
  Orphan(Orphan<AnyPointer>&&);
923
  Orphan(void*) = delete;  // So Orphan(bool) doesn't accept pointers.
924 925
  KJ_DISALLOW_COPY(Orphan);

926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
  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;
950
    InterfaceSchema interfaceSchema;
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
  };

  _::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;
968
  friend struct AnyPointer;
969 970 971 972
  friend class Orphanage;
};

template <typename T>
973
inline Orphan<DynamicValue>::Orphan(Orphan<T>&& other)
974 975
    : Orphan(other.get(), kj::mv(other.builder)) {}

976 977
inline Orphan<DynamicValue>::Orphan(Orphan<AnyPointer>&& other)
    : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {}
978

979 980 981 982 983 984 985 986 987 988 989 990
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));
}

991 992 993 994 995 996
template <typename T>
Orphan<T> Orphan<DynamicCapability>::releaseAs() {
  get().as<T>();  // type check
  return Orphan<T>(kj::mv(builder));
}

997 998 999
template <typename T>
Orphan<T> Orphan<DynamicValue>::releaseAs() {
  get().as<T>();  // type check
1000
  type = DynamicValue::UNKNOWN;
1001 1002 1003
  return Orphan<T>(kj::mv(builder));
}

1004
template <>
1005
Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>();
1006 1007 1008 1009
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>();
template <>
Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>();
1010 1011
template <>
Orphan<DynamicCapability> Orphan<DynamicValue>::releaseAs<DynamicCapability>();
1012

1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
template <>
struct Orphanage::GetInnerBuilder<DynamicStruct, Kind::UNKNOWN> {
  static inline _::StructBuilder apply(DynamicStruct::Builder& t) {
    return t.builder;
  }
};

template <>
struct Orphanage::GetInnerBuilder<DynamicList, Kind::UNKNOWN> {
  static inline _::ListBuilder apply(DynamicList::Builder& t) {
    return t.builder;
  }
};

template <>
inline Orphan<DynamicStruct> Orphanage::newOrphanCopy<DynamicStruct::Reader>(
1029
    const DynamicStruct::Reader& copyFrom) const {
1030 1031 1032 1033 1034 1035
  return Orphan<DynamicStruct>(
      copyFrom.getSchema(), _::OrphanBuilder::copy(arena, copyFrom.reader));
}

template <>
inline Orphan<DynamicList> Orphanage::newOrphanCopy<DynamicList::Reader>(
1036
    const DynamicList::Reader& copyFrom) const {
1037 1038 1039
  return Orphan<DynamicList>(copyFrom.getSchema(), _::OrphanBuilder::copy(arena, copyFrom.reader));
}

1040 1041
template <>
inline Orphan<DynamicCapability> Orphanage::newOrphanCopy<DynamicCapability::Client>(
1042
    DynamicCapability::Client& copyFrom) const {
1043 1044 1045 1046
  return Orphan<DynamicCapability>(
      copyFrom.getSchema(), _::OrphanBuilder::copy(arena, copyFrom.hook->addRef()));
}

1047 1048 1049 1050
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
    const DynamicValue::Reader& copyFrom) const;

1051
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
1052 1053 1054

template <>
struct PointerHelpers<DynamicStruct, Kind::UNKNOWN> {
1055
  // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1056 1057
  // 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.
1058 1059 1060 1061 1062 1063
  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));
1064
  }
1065 1066
  static inline Orphan<DynamicStruct> disown(PointerBuilder builder, StructSchema schema) {
    return Orphan<DynamicStruct>(schema, builder.disown());
1067
  }
Kenton Varda's avatar
Kenton Varda committed
1068 1069 1070 1071
};

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

1087 1088
template <>
struct PointerHelpers<DynamicCapability, Kind::UNKNOWN> {
1089
  // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1090 1091 1092 1093
  // 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);
1094
  static void set(PointerBuilder builder, DynamicCapability::Client& value);
1095 1096 1097 1098 1099 1100 1101 1102 1103
  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());
  }
};

1104
}  // namespace _ (private)
Kenton Varda's avatar
Kenton Varda committed
1105

1106
template <typename T>
1107
inline ReaderFor<T> AnyPointer::Reader::getAs(StructSchema schema) const {
1108 1109 1110
  return _::PointerHelpers<T>::getDynamic(reader, schema);
}
template <typename T>
1111
inline ReaderFor<T> AnyPointer::Reader::getAs(ListSchema schema) const {
1112 1113 1114
  return _::PointerHelpers<T>::getDynamic(reader, schema);
}
template <typename T>
1115
inline ReaderFor<T> AnyPointer::Reader::getAs(InterfaceSchema schema) const {
1116 1117 1118
  return _::PointerHelpers<T>::getDynamic(reader, schema);
}
template <typename T>
1119
inline BuilderFor<T> AnyPointer::Builder::getAs(StructSchema schema) {
1120 1121 1122
  return _::PointerHelpers<T>::getDynamic(builder, schema);
}
template <typename T>
1123
inline BuilderFor<T> AnyPointer::Builder::getAs(ListSchema schema) {
1124 1125 1126
  return _::PointerHelpers<T>::getDynamic(builder, schema);
}
template <typename T>
1127
inline BuilderFor<T> AnyPointer::Builder::getAs(InterfaceSchema schema) {
1128 1129 1130
  return _::PointerHelpers<T>::getDynamic(builder, schema);
}
template <typename T>
1131
inline BuilderFor<T> AnyPointer::Builder::initAs(StructSchema schema) {
1132 1133 1134
  return _::PointerHelpers<T>::init(builder, schema);
}
template <typename T>
1135
inline BuilderFor<T> AnyPointer::Builder::initAs(ListSchema schema, uint elementCount) {
1136 1137 1138
  return _::PointerHelpers<T>::init(builder, schema, elementCount);
}
template <>
1139
inline void AnyPointer::Builder::setAs<DynamicStruct>(DynamicStruct::Reader value) {
1140 1141 1142
  return _::PointerHelpers<DynamicStruct>::set(builder, value);
}
template <>
1143
inline void AnyPointer::Builder::setAs<DynamicList>(DynamicList::Reader value) {
1144 1145 1146
  return _::PointerHelpers<DynamicList>::set(builder, value);
}
template <>
1147
inline void AnyPointer::Builder::setAs<DynamicCapability>(DynamicCapability::Client value) {
1148 1149 1150
  return _::PointerHelpers<DynamicCapability>::set(builder, kj::mv(value));
}
template <>
1151
void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan);
1152
template <typename T>
1153
inline Orphan<T> AnyPointer::Builder::disownAs(StructSchema schema) {
1154 1155 1156
  return _::PointerHelpers<T>::disown(builder, schema);
}
template <typename T>
1157
inline Orphan<T> AnyPointer::Builder::disownAs(ListSchema schema) {
1158 1159
  return _::PointerHelpers<T>::disown(builder, schema);
}
1160
template <typename T>
1161
inline Orphan<T> AnyPointer::Builder::disownAs(InterfaceSchema schema) {
1162 1163
  return _::PointerHelpers<T>::disown(builder, schema);
}
1164

1165
template <>
1166
DynamicStruct::Builder Orphan<AnyPointer>::getAs<DynamicStruct>(StructSchema schema);
1167
template <>
1168
DynamicList::Builder Orphan<AnyPointer>::getAs<DynamicList>(ListSchema schema);
1169
template <>
1170
DynamicCapability::Client Orphan<AnyPointer>::getAs<DynamicCapability>(InterfaceSchema schema);
1171
template <>
1172
DynamicStruct::Reader Orphan<AnyPointer>::getAsReader<DynamicStruct>(StructSchema schema) const;
1173
template <>
1174
DynamicList::Reader Orphan<AnyPointer>::getAsReader<DynamicList>(ListSchema schema) const;
1175
template <>
1176
DynamicCapability::Client Orphan<AnyPointer>::getAsReader<DynamicCapability>(
1177 1178
    InterfaceSchema schema) const;
template <>
1179
Orphan<DynamicStruct> Orphan<AnyPointer>::releaseAs<DynamicStruct>(StructSchema schema);
1180
template <>
1181
Orphan<DynamicList> Orphan<AnyPointer>::releaseAs<DynamicList>(ListSchema schema);
1182
template <>
1183
Orphan<DynamicCapability> Orphan<AnyPointer>::releaseAs<DynamicCapability>(
1184
    InterfaceSchema schema);
1185

Kenton Varda's avatar
Kenton Varda committed
1186
// =======================================================================================
Kenton Varda's avatar
Kenton Varda committed
1187
// Inline implementation details.
Kenton Varda's avatar
Kenton Varda committed
1188

1189
template <typename T>
1190
struct ToDynamic_<T, Kind::STRUCT> {
1191
  static inline DynamicStruct::Reader apply(const typename T::Reader& value) {
1192
    return DynamicStruct::Reader(Schema::from<T>(), value._reader);
1193
  }
1194
  static inline DynamicStruct::Builder apply(typename T::Builder& value) {
1195
    return DynamicStruct::Builder(Schema::from<T>(), value._builder);
1196 1197 1198 1199
  }
};

template <typename T>
1200
struct ToDynamic_<T, Kind::LIST> {
1201
  static inline DynamicList::Reader apply(const typename T::Reader& value) {
1202
    return DynamicList::Reader(Schema::from<T>(), value.reader);
1203
  }
1204
  static inline DynamicList::Builder apply(typename T::Builder& value) {
1205
    return DynamicList::Builder(Schema::from<T>(), value.builder);
1206 1207 1208
  }
};

1209 1210
template <typename T>
struct ToDynamic_<T, Kind::INTERFACE> {
1211 1212
  static inline DynamicCapability::Client apply(typename T::Client value) {
    return DynamicCapability::Client(kj::mv(value));
1213 1214 1215 1216 1217 1218
  }
  static inline DynamicCapability::Client apply(typename T::Client&& value) {
    return DynamicCapability::Client(kj::mv(value));
  }
};

1219
template <typename T>
1220 1221
ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromReader<T>>::apply(value);
1222 1223
}
template <typename T>
1224 1225
BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromBuilder<T>>::apply(value);
1226
}
1227
template <typename T>
1228
DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) {
1229
  return DynamicEnum(Schema::from<kj::Decay<T>>(), static_cast<uint16_t>(value));
1230
}
1231 1232 1233 1234
template <typename T>
typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value) {
  return typename FromServer<T>::Client(kj::mv(value));
}
1235

1236 1237 1238
inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {}
inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {}

1239
#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
1240 1241 1242
inline DynamicValue::Reader::Reader(cppType value) \
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType value) \
1243 1244 1245
    : type(typeTag), fieldName##Value(value) {} \
inline Orphan<DynamicValue>::Orphan(cppType value) \
    : type(DynamicValue::typeTag), fieldName##Value(value) {}
1246

Kenton Varda's avatar
Kenton Varda committed
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
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) \
1266
inline DynamicValue::Reader::Reader(const cppType::Reader& value) \
1267 1268 1269 1270
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType::Builder value) \
    : type(typeTag), fieldName##Value(value) {}

Kenton Varda's avatar
Kenton Varda committed
1271 1272 1273 1274
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);
1275
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(AnyPointer, ANY_POINTER, anyPointer);
1276

Kenton Varda's avatar
Kenton Varda committed
1277
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
1278

1279
inline DynamicValue::Reader::Reader(DynamicCapability::Client& value)
1280 1281 1282 1283 1284 1285
    : 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)) {}
1286
inline DynamicValue::Builder::Builder(DynamicCapability::Client& value)
1287 1288 1289 1290
    : type(CAPABILITY), capabilityValue(value) {}
inline DynamicValue::Builder::Builder(DynamicCapability::Client&& value)
    : type(CAPABILITY), capabilityValue(kj::mv(value)) {}

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

1293
#define CAPNP_DECLARE_TYPE(discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1294
template <> \
1295
struct DynamicValue::Reader::AsImpl<typeName> { \
1296
  static ReaderFor<typeName> apply(const Reader& reader); \
Kenton Varda's avatar
Kenton Varda committed
1297 1298
}; \
template <> \
1299
struct DynamicValue::Builder::AsImpl<typeName> { \
1300
  static BuilderFor<typeName> apply(Builder& builder); \
Kenton Varda's avatar
Kenton Varda committed
1301 1302
};

1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322
//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
1323 1324 1325
#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
1326 1327
// ReaderFor<> and BuilderFor<> wrappers, it works.
template <>
1328
struct DynamicValue::Reader::AsImpl<Void> {
1329
  static Void apply(const Reader& reader);
Kenton Varda's avatar
Kenton Varda committed
1330 1331
};
template <>
1332
struct DynamicValue::Builder::AsImpl<Void> {
1333
  static Void apply(Builder& builder);
Kenton Varda's avatar
Kenton Varda committed
1334 1335 1336
};

template <typename T>
1337
struct DynamicValue::Reader::AsImpl<T, Kind::ENUM> {
1338
  static T apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1339
    return reader.as<DynamicEnum>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1340 1341 1342
  }
};
template <typename T>
1343
struct DynamicValue::Builder::AsImpl<T, Kind::ENUM> {
1344
  static T apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1345
    return builder.as<DynamicEnum>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1346 1347 1348 1349
  }
};

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

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

1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
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>();
  }
};

1388
inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {}
1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414
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 <>
struct DynamicValue::Pipeline::AsImpl<DynamicStruct, Kind::UNKNOWN> {
  static PipelineFor<DynamicStruct> apply(Pipeline& pipeline);
};
template <>
struct DynamicValue::Pipeline::AsImpl<DynamicCapability, Kind::UNKNOWN> {
  static PipelineFor<DynamicCapability> apply(Pipeline& pipeline);
};

Kenton Varda's avatar
Kenton Varda committed
1415 1416
// -------------------------------------------------------------------

Kenton Varda's avatar
Kenton Varda committed
1417
template <typename T>
1418
typename T::Reader DynamicStruct::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1419 1420
  static_assert(kind<T>() == Kind::STRUCT,
                "DynamicStruct::Reader::as<T>() can only convert to struct types.");
1421
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1422 1423 1424 1425 1426 1427
  return typename T::Reader(reader);
}
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.");
1428
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1429 1430 1431
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
1432
template <>
1433
inline DynamicStruct::Reader DynamicStruct::Reader::as<DynamicStruct>() const {
Kenton Varda's avatar
Kenton Varda committed
1434 1435 1436 1437 1438 1439 1440
  return *this;
}
template <>
inline DynamicStruct::Builder DynamicStruct::Builder::as<DynamicStruct>() {
  return *this;
}

1441
inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const {
1442
  return DynamicStruct::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
1443 1444
}

1445 1446 1447 1448 1449 1450 1451 1452
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
1453 1454 1455
// -------------------------------------------------------------------

template <typename T>
1456
typename T::Reader DynamicList::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1457 1458
  static_assert(kind<T>() == Kind::LIST,
                "DynamicStruct::Reader::as<T>() can only convert to list types.");
1459
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1460 1461 1462 1463 1464 1465
  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.");
1466
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1467 1468 1469
  return typename T::Builder(builder);
}

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

1479 1480
// -------------------------------------------------------------------

1481 1482 1483 1484 1485
template <typename T, typename>
inline DynamicCapability::Client::Client(T&& client)
    : Capability::Client(kj::mv(client)), schema(Schema::from<FromClient<T>>()) {}

template <typename T, typename>
1486 1487
inline DynamicCapability::Client::Client(kj::Own<T>&& server)
    : Client(server->getSchema(), kj::mv(server)) {}
1488
template <typename T>
1489 1490
inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own<T>&& server)
    : Capability::Client(kj::mv(server)), schema(schema) {}
1491 1492

template <typename T, typename>
1493
typename T::Client DynamicCapability::Client::as() {
1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
  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(
1518 1519
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).getAs<DynamicStruct>(resultType);
1520 1521
}
inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::initResults(
1522 1523
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).initAs<DynamicStruct>(resultType);
1524 1525
}
inline void CallContext<DynamicStruct, DynamicStruct>::setResults(DynamicStruct::Reader value) {
1526
  hook->getResults(value.totalSize()).setAs<DynamicStruct>(value);
1527 1528
}
inline void CallContext<DynamicStruct, DynamicStruct>::adoptResults(Orphan<DynamicStruct>&& value) {
1529
  hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value));
1530 1531
}
inline Orphanage CallContext<DynamicStruct, DynamicStruct>::getResultsOrphanage(
1532 1533
    kj::Maybe<MessageSize> sizeHint) {
  return Orphanage::getForMessageContaining(hook->getResults(sizeHint));
1534
}
Kenton Varda's avatar
Kenton Varda committed
1535 1536 1537 1538 1539
template <typename SubParams>
inline kj::Promise<void> CallContext<DynamicStruct, DynamicStruct>::tailCall(
    Request<SubParams, DynamicStruct>&& tailRequest) {
  return hook->tailCall(kj::mv(tailRequest.hook));
}
1540 1541
inline void CallContext<DynamicStruct, DynamicStruct>::allowCancellation() {
  hook->allowCancellation();
1542 1543 1544 1545
}

template <>
inline DynamicCapability::Client Capability::Client::castAs<DynamicCapability>(
1546
    InterfaceSchema schema) {
1547 1548 1549 1550 1551
  return DynamicCapability::Client(schema, hook->addRef());
}

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

1552 1553 1554 1555 1556
template <typename T>
ReaderFor<T> ConstSchema::as() const {
  return DynamicValue::Reader(*this).as<T>();
}

1557
}  // namespace capnp
Kenton Varda's avatar
Kenton Varda committed
1558

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