dynamic.h 59.6 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 183
  inline operator AnyStruct::Reader() const { return AnyStruct::Reader(reader); }

184
  inline MessageSize totalSize() const { return reader.totalSize().asPublic(); }
185

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

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

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

Kenton Varda's avatar
Kenton Varda committed
195 196
  bool has(StructSchema::Field field) const;
  // Tests whether the given field is set to its default value.  For pointer values, this does
197
  // not actually traverse the value comparing it with the default, but simply returns true if the
198 199 200
  // 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
201 202 203 204 205 206 207

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

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

private:
214
  StructSchema schema;
215
  _::StructReader reader;
Kenton Varda's avatar
Kenton Varda committed
216

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

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

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

class DynamicStruct::Builder {
public:
244 245
  typedef DynamicStruct Builds;

246
  Builder() = default;
247
  inline Builder(decltype(nullptr)) {}
Kenton Varda's avatar
Kenton Varda committed
248

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

252 253
  inline operator AnyStruct::Reader() { return AnyStruct::Builder(builder); }

254
  inline MessageSize totalSize() const { return asReader().totalSize(); }
255

Kenton Varda's avatar
Kenton Varda committed
256
  template <typename T>
Kenton Varda's avatar
Kenton Varda committed
257
  typename T::Builder as();
Kenton Varda's avatar
Kenton Varda committed
258 259
  // Cast to a particular struct type.

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

Kenton Varda's avatar
Kenton Varda committed
262 263
  DynamicValue::Builder get(StructSchema::Field field);
  // Read the given field value.
264

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

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

295 296 297 298 299 300
  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);
301 302
  void adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan);
  Orphan<DynamicValue> disown(kj::StringPtr name);
Kenton Varda's avatar
Kenton Varda committed
303 304
  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
305

306
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
307 308

private:
309
  StructSchema schema;
310
  _::StructBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
311

312
  inline Builder(StructSchema schema, _::StructBuilder builder)
313
      : schema(schema), builder(builder) {}
314
  Builder(StructSchema schema, _::OrphanBuilder& orphan);
Kenton Varda's avatar
Kenton Varda committed
315

Kenton Varda's avatar
Kenton Varda committed
316 317 318 319
  bool isSetInUnion(StructSchema::Field field);
  void verifySetInUnion(StructSchema::Field field);
  void setInUnion(StructSchema::Field field);

Kenton Varda's avatar
Kenton Varda committed
320
  template <typename T, Kind k>
321
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
322 323 324
  friend struct DynamicList;
  friend class MessageReader;
  friend class MessageBuilder;
325 326
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
327 328
  friend class Orphanage;
  friend class Orphan<DynamicStruct>;
329
  friend class Orphan<DynamicValue>;
330
  friend class Orphan<AnyPointer>;
331
  friend class AnyStruct::Builder;
Kenton Varda's avatar
Kenton Varda committed
332 333
};

334 335 336 337 338 339 340 341 342 343
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.

344
  inline StructSchema getSchema() { return schema; }
345

346
  DynamicValue::Pipeline get(StructSchema::Field field);
347 348
  // Read the given field value.

349
  DynamicValue::Pipeline get(kj::StringPtr name);
350 351 352 353
  // Get by string name.

private:
  StructSchema schema;
354
  AnyPointer::Pipeline typeless;
355

356
  inline explicit Pipeline(StructSchema schema, AnyPointer::Pipeline&& typeless)
357 358 359 360 361
      : schema(schema), typeless(kj::mv(typeless)) {}

  friend class Request<DynamicStruct, DynamicStruct>;
};

Kenton Varda's avatar
Kenton Varda committed
362 363 364 365
// -------------------------------------------------------------------

class DynamicList::Reader {
public:
366 367
  typedef DynamicList Reads;

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

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

373 374
  inline operator AnyList::Reader() const { return AnyList::Reader(reader); }

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

380
  inline ListSchema getSchema() const { return schema; }
381

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

385
  typedef _::IndexingIterator<const Reader, DynamicValue::Reader> Iterator;
386 387
  inline Iterator begin() const { return Iterator(this, 0); }
  inline Iterator end() const { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
388 389

private:
390
  ListSchema schema;
391
  _::ListReader reader;
Kenton Varda's avatar
Kenton Varda committed
392

393
  Reader(ListSchema schema, _::ListReader reader): schema(schema), reader(reader) {}
394
  Reader(ListSchema schema, const _::OrphanBuilder& orphan);
Kenton Varda's avatar
Kenton Varda committed
395

Kenton Varda's avatar
Kenton Varda committed
396
  template <typename T, Kind k>
397
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
398 399
  friend struct DynamicStruct;
  friend class DynamicList::Builder;
400 401
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
402
  friend class Orphanage;
403
  friend class Orphan<DynamicList>;
404
  friend class Orphan<DynamicValue>;
405
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
406 407 408 409
};

class DynamicList::Builder {
public:
410 411
  typedef DynamicList Builds;

412 413
  inline Builder(): builder(ElementSize::VOID) {}
  inline Builder(decltype(nullptr)): builder(ElementSize::VOID) {}
Kenton Varda's avatar
Kenton Varda committed
414

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

418 419
  inline operator AnyList::Builder() { return AnyList::Builder(builder); }

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

425
  inline ListSchema getSchema() const { return schema; }
426

427
  inline uint size() const { return unbound(builder.size() / ELEMENTS); }
428 429
  DynamicValue::Builder operator[](uint index);
  void set(uint index, const DynamicValue::Reader& value);
Kenton Varda's avatar
Kenton Varda committed
430
  DynamicValue::Builder init(uint index, uint size);
431 432
  void adopt(uint index, Orphan<DynamicValue>&& orphan);
  Orphan<DynamicValue> disown(uint index);
Kenton Varda's avatar
Kenton Varda committed
433

434
  typedef _::IndexingIterator<Builder, DynamicStruct::Builder> Iterator;
435 436
  inline Iterator begin() { return Iterator(this, 0); }
  inline Iterator end() { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
437

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

440
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
441 442

private:
443
  ListSchema schema;
444
  _::ListBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
445

446
  Builder(ListSchema schema, _::ListBuilder builder): schema(schema), builder(builder) {}
447
  Builder(ListSchema schema, _::OrphanBuilder& orphan);
Kenton Varda's avatar
Kenton Varda committed
448

Kenton Varda's avatar
Kenton Varda committed
449
  template <typename T, Kind k>
450
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
451
  friend struct DynamicStruct;
452 453
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
454 455 456 457
  friend class Orphanage;
  template <typename T, Kind k>
  friend struct _::OrphanGetImpl;
  friend class Orphan<DynamicList>;
458
  friend class Orphan<DynamicValue>;
459
  friend class Orphan<AnyPointer>;
Kenton Varda's avatar
Kenton Varda committed
460 461 462 463
};

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

464 465 466 467 468 469 470 471 472 473 474
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*>()>>
475
  inline Client(kj::Own<T>&& server);
476 477

  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
478
  typename T::Client as();
479 480 481 482
  template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
  typename T::Client releaseAs();
  // Convert to any client type.

483
  Client upcast(InterfaceSchema requestedSchema);
484 485
  // Upcast to a superclass.  Throws an exception if `schema` is not a superclass.

486
  inline InterfaceSchema getSchema() { return schema; }
487 488

  Request<DynamicStruct, DynamicStruct> newRequest(
489
      InterfaceSchema::Method method, kj::Maybe<MessageSize> sizeHint = nullptr);
490
  Request<DynamicStruct, DynamicStruct> newRequest(
491
      kj::StringPtr methodName, kj::Maybe<MessageSize> sizeHint = nullptr);
492 493 494 495

private:
  InterfaceSchema schema;

496
  Client(InterfaceSchema schema, kj::Own<ClientHook>&& hook)
497 498 499
      : Capability::Client(kj::mv(hook)), schema(schema) {}

  template <typename T>
500
  inline Client(InterfaceSchema schema, kj::Own<T>&& server);
501 502 503 504 505 506 507

  friend struct Capability;
  friend struct DynamicStruct;
  friend struct DynamicList;
  friend struct DynamicValue;
  friend class Orphan<DynamicCapability>;
  friend class Orphan<DynamicValue>;
508
  friend class Orphan<AnyPointer>;
509 510 511 512 513 514 515 516 517 518 519 520 521 522
  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,
523
                                 CallContext<AnyPointer, AnyPointer> context) override final;
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548

  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;
549 550 551
  template <typename, typename>
  friend class CallContext;
  friend class RequestHook;
552 553 554 555 556 557 558 559 560 561 562 563 564 565
};

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();
566 567
  DynamicStruct::Builder getResults(kj::Maybe<MessageSize> sizeHint = nullptr);
  DynamicStruct::Builder initResults(kj::Maybe<MessageSize> sizeHint = nullptr);
568 569
  void setResults(DynamicStruct::Reader value);
  void adoptResults(Orphan<DynamicStruct>&& value);
570
  Orphanage getResultsOrphanage(kj::Maybe<MessageSize> sizeHint = nullptr);
Kenton Varda's avatar
Kenton Varda committed
571 572
  template <typename SubParams>
  kj::Promise<void> tailCall(Request<SubParams, DynamicStruct>&& tailRequest);
573
  void allowCancellation();
574 575 576 577 578 579 580 581 582 583 584

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

  friend class DynamicCapability::Server;
};

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

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

588 589 590 591 592 593 594 595 596
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
597 598 599

class DynamicValue::Reader {
public:
600 601
  typedef DynamicValue Reads;

602
  inline Reader(decltype(nullptr) n = nullptr);  // UNKNOWN
603
  inline Reader(Void value);
604 605 606 607 608 609 610 611 612 613 614 615 616 617
  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
618
  inline Reader(const char* value);  // Text
619 620 621
  inline Reader(const Text::Reader& value);
  inline Reader(const Data::Reader& value);
  inline Reader(const DynamicList::Reader& value);
622
  inline Reader(DynamicEnum value);
623
  inline Reader(const DynamicStruct::Reader& value);
624
  inline Reader(const AnyPointer::Reader& value);
625
  inline Reader(DynamicCapability::Client& value);
626 627 628
  inline Reader(DynamicCapability::Client&& value);
  template <typename T, typename = kj::EnableIf<kj::canConvert<T*, DynamicCapability::Server*>()>>
  inline Reader(kj::Own<T>&& value);
629
  Reader(ConstSchema constant);
Kenton Varda's avatar
Kenton Varda committed
630

Kenton Varda's avatar
Kenton Varda committed
631
  template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
632 633 634
  inline Reader(T&& value): Reader(toDynamic(kj::mv(value))) {}

  Reader(const Reader& other);
Kenton Varda's avatar
Kenton Varda committed
635 636
  Reader(Reader&& other) noexcept;
  ~Reader() noexcept(false);
637 638 639 640
  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
641 642

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

669
  inline Type getType() const { return type; }
Kenton Varda's avatar
Kenton Varda committed
670 671 672
  // Get the type of this value.

private:
673
  Type type;
Kenton Varda's avatar
Kenton Varda committed
674 675 676 677

  union {
    Void voidValue;
    bool boolValue;
678 679 680
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
681 682 683 684 685
    Text::Reader textValue;
    Data::Reader dataValue;
    DynamicList::Reader listValue;
    DynamicEnum enumValue;
    DynamicStruct::Reader structValue;
686
    AnyPointer::Reader anyPointerValue;
687 688 689

    mutable DynamicCapability::Client capabilityValue;
    // Declared mutable because `Client`s normally cannot be const.
690 691 692

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

695
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
696
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
697
  // specialization.  Has a method apply() which does the work.
698 699

  friend class Orphanage;  // to speed up newOrphanCopy(DynamicValue::Reader)
Kenton Varda's avatar
Kenton Varda committed
700 701 702 703
};

class DynamicValue::Builder {
public:
704 705
  typedef DynamicValue Builds;

706
  inline Builder(decltype(nullptr) n = nullptr);  // UNKNOWN
707
  inline Builder(Void value);
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
  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);
727
  inline Builder(AnyPointer::Builder value);
728
  inline Builder(DynamicCapability::Client& value);
729
  inline Builder(DynamicCapability::Client&& value);
Kenton Varda's avatar
Kenton Varda committed
730

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

734
  Builder(Builder& other);
Kenton Varda's avatar
Kenton Varda committed
735 736
  Builder(Builder&& other) noexcept;
  ~Builder() noexcept(false);
737 738 739 740 741
  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
742
  template <typename T>
743
  inline BuilderFor<T> as() { return AsImpl<T>::apply(*this); }
Kenton Varda's avatar
Kenton Varda committed
744
  // See DynamicValue::Reader::as().
Kenton Varda's avatar
Kenton Varda committed
745

746
  inline Type getType() { return type; }
Kenton Varda's avatar
Kenton Varda committed
747 748
  // Get the type of this value.

749
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
750 751

private:
752
  Type type;
Kenton Varda's avatar
Kenton Varda committed
753 754 755 756

  union {
    Void voidValue;
    bool boolValue;
757 758 759
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
760 761 762 763 764
    Text::Builder textValue;
    Data::Builder dataValue;
    DynamicList::Builder listValue;
    DynamicEnum enumValue;
    DynamicStruct::Builder structValue;
765
    AnyPointer::Builder anyPointerValue;
766 767 768

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

771
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
772
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
773
  // specialization.  Has a method apply() which does the work.
774 775

  friend class Orphan<DynamicValue>;
Kenton Varda's avatar
Kenton Varda committed
776 777
};

778 779 780 781
class DynamicValue::Pipeline {
public:
  typedef DynamicValue Pipelines;

782
  inline Pipeline(decltype(nullptr) n = nullptr);
783 784 785
  inline Pipeline(DynamicStruct::Pipeline&& value);
  inline Pipeline(DynamicCapability::Client&& value);

786
  Pipeline(Pipeline&& other) noexcept;
787 788 789 790 791 792
  Pipeline& operator=(Pipeline&& other);
  ~Pipeline() noexcept(false);

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

793 794 795
  inline Type getType() { return type; }
  // Get the type of this value.

796 797 798 799 800 801 802 803 804 805 806 807
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.
};

808 809 810 811 812 813 814
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
815

816 817 818 819 820 821 822 823 824 825 826
// -------------------------------------------------------------------
// Orphan <-> Dynamic glue

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

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

830
  DynamicStruct::Builder get();
831
  DynamicStruct::Reader getReader() const;
832

833 834 835 836 837 838 839 840
  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; }
841 842 843 844 845 846 847 848 849 850 851 852

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;
853
  friend class Orphan<DynamicValue>;
854
  friend class Orphan<AnyPointer>;
855
  friend class MessageBuilder;
856 857 858 859 860 861 862 863 864 865
};

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

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

869
  DynamicList::Builder get();
870
  DynamicList::Reader getReader() const;
871

872 873 874 875 876 877
  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>.

878 879
  // TODO(someday): Support truncate().

880 881
  inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
  inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
882 883 884 885 886 887 888 889 890 891 892 893

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;
894
  friend class Orphan<DynamicValue>;
895
  friend class Orphan<AnyPointer>;
896 897
};

898 899 900 901 902 903 904 905
template <>
class Orphan<DynamicCapability> {
public:
  Orphan() = default;
  KJ_DISALLOW_COPY(Orphan);
  Orphan(Orphan&&) = default;
  Orphan& operator=(Orphan&&) = default;

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

909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
  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>;
933
  friend class Orphan<AnyPointer>;
934 935
};

936 937 938
template <>
class Orphan<DynamicValue> {
public:
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
  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);
956 957 958
  Orphan(Orphan&&) = default;
  template <typename T>
  Orphan(Orphan<T>&&);
959
  Orphan(Orphan<AnyPointer>&&);
960
  Orphan(void*) = delete;  // So Orphan(bool) doesn't accept pointers.
961 962
  KJ_DISALLOW_COPY(Orphan);

963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986
  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;
987
    InterfaceSchema interfaceSchema;
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004
  };

  _::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;
1005
  friend struct AnyPointer;
1006 1007 1008 1009
  friend class Orphanage;
};

template <typename T>
1010
inline Orphan<DynamicValue>::Orphan(Orphan<T>&& other)
1011 1012
    : Orphan(other.get(), kj::mv(other.builder)) {}

1013 1014
inline Orphan<DynamicValue>::Orphan(Orphan<AnyPointer>&& other)
    : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {}
1015

1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
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));
}

1028 1029 1030 1031 1032 1033
template <typename T>
Orphan<T> Orphan<DynamicCapability>::releaseAs() {
  get().as<T>();  // type check
  return Orphan<T>(kj::mv(builder));
}

1034 1035 1036
template <typename T>
Orphan<T> Orphan<DynamicValue>::releaseAs() {
  get().as<T>();  // type check
1037
  type = DynamicValue::UNKNOWN;
1038 1039 1040
  return Orphan<T>(kj::mv(builder));
}

1041
template <>
1042
Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>();
1043 1044 1045 1046
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>();
template <>
Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>();
1047 1048
template <>
Orphan<DynamicCapability> Orphan<DynamicValue>::releaseAs<DynamicCapability>();
1049

1050
template <>
1051
struct Orphanage::GetInnerBuilder<DynamicStruct, Kind::OTHER> {
1052 1053 1054 1055 1056 1057
  static inline _::StructBuilder apply(DynamicStruct::Builder& t) {
    return t.builder;
  }
};

template <>
1058
struct Orphanage::GetInnerBuilder<DynamicList, Kind::OTHER> {
1059 1060 1061 1062 1063 1064 1065
  static inline _::ListBuilder apply(DynamicList::Builder& t) {
    return t.builder;
  }
};

template <>
inline Orphan<DynamicStruct> Orphanage::newOrphanCopy<DynamicStruct::Reader>(
1066
    DynamicStruct::Reader copyFrom) const {
1067
  return Orphan<DynamicStruct>(
1068
      copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.reader));
1069 1070 1071 1072
}

template <>
inline Orphan<DynamicList> Orphanage::newOrphanCopy<DynamicList::Reader>(
1073
    DynamicList::Reader copyFrom) const {
1074 1075
  return Orphan<DynamicList>(copyFrom.getSchema(),
      _::OrphanBuilder::copy(arena, capTable, copyFrom.reader));
1076 1077
}

1078 1079
template <>
inline Orphan<DynamicCapability> Orphanage::newOrphanCopy<DynamicCapability::Client>(
1080
    DynamicCapability::Client copyFrom) const {
1081
  return Orphan<DynamicCapability>(
1082
      copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.hook->addRef()));
1083 1084
}

1085 1086
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
1087
    DynamicValue::Reader copyFrom) const;
1088

1089
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
1090 1091

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

template <>
1109
struct PointerHelpers<DynamicList, Kind::OTHER> {
1110
  // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1111 1112
  // 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.
1113 1114 1115 1116 1117 1118
  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));
1119
  }
1120 1121
  static inline Orphan<DynamicList> disown(PointerBuilder builder, ListSchema schema) {
    return Orphan<DynamicList>(schema, builder.disown());
1122
  }
Kenton Varda's avatar
Kenton Varda committed
1123 1124
};

1125
template <>
1126
struct PointerHelpers<DynamicCapability, Kind::OTHER> {
1127
  // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1128 1129 1130 1131
  // 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);
1132
  static void set(PointerBuilder builder, DynamicCapability::Client& value);
1133 1134 1135 1136 1137 1138 1139 1140 1141
  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());
  }
};

1142
}  // namespace _ (private)
Kenton Varda's avatar
Kenton Varda committed
1143

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

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

Kenton Varda's avatar
Kenton Varda committed
1246
// =======================================================================================
Kenton Varda's avatar
Kenton Varda committed
1247
// Inline implementation details.
Kenton Varda's avatar
Kenton Varda committed
1248

1249
template <typename T>
1250
struct ToDynamic_<T, Kind::STRUCT> {
1251
  static inline DynamicStruct::Reader apply(const typename T::Reader& value) {
1252
    return DynamicStruct::Reader(Schema::from<T>(), value._reader);
1253
  }
1254
  static inline DynamicStruct::Builder apply(typename T::Builder& value) {
1255
    return DynamicStruct::Builder(Schema::from<T>(), value._builder);
1256 1257 1258 1259
  }
};

template <typename T>
1260
struct ToDynamic_<T, Kind::LIST> {
1261
  static inline DynamicList::Reader apply(const typename T::Reader& value) {
1262
    return DynamicList::Reader(Schema::from<T>(), value.reader);
1263
  }
1264
  static inline DynamicList::Builder apply(typename T::Builder& value) {
1265
    return DynamicList::Builder(Schema::from<T>(), value.builder);
1266 1267 1268
  }
};

1269 1270
template <typename T>
struct ToDynamic_<T, Kind::INTERFACE> {
1271 1272
  static inline DynamicCapability::Client apply(typename T::Client value) {
    return DynamicCapability::Client(kj::mv(value));
1273 1274 1275 1276 1277 1278
  }
  static inline DynamicCapability::Client apply(typename T::Client&& value) {
    return DynamicCapability::Client(kj::mv(value));
  }
};

1279
template <typename T>
1280 1281
ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromReader<T>>::apply(value);
1282 1283
}
template <typename T>
1284 1285
BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromBuilder<T>>::apply(value);
1286
}
1287
template <typename T>
1288
DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) {
1289
  return DynamicEnum(Schema::from<kj::Decay<T>>(), static_cast<uint16_t>(value));
1290
}
1291 1292 1293 1294
template <typename T>
typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value) {
  return typename FromServer<T>::Client(kj::mv(value));
}
1295

1296 1297 1298
inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {}
inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {}

1299
#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
1300 1301 1302
inline DynamicValue::Reader::Reader(cppType value) \
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType value) \
1303 1304 1305
    : type(typeTag), fieldName##Value(value) {} \
inline Orphan<DynamicValue>::Orphan(cppType value) \
    : type(DynamicValue::typeTag), fieldName##Value(value) {}
1306

Kenton Varda's avatar
Kenton Varda committed
1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
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) \
1326
inline DynamicValue::Reader::Reader(const cppType::Reader& value) \
1327 1328 1329 1330
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType::Builder value) \
    : type(typeTag), fieldName##Value(value) {}

Kenton Varda's avatar
Kenton Varda committed
1331 1332 1333 1334
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);
1335
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(AnyPointer, ANY_POINTER, anyPointer);
1336

Kenton Varda's avatar
Kenton Varda committed
1337
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
1338

1339
inline DynamicValue::Reader::Reader(DynamicCapability::Client& value)
1340 1341 1342 1343 1344 1345
    : 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)) {}
1346
inline DynamicValue::Builder::Builder(DynamicCapability::Client& value)
1347 1348 1349 1350
    : type(CAPABILITY), capabilityValue(value) {}
inline DynamicValue::Builder::Builder(DynamicCapability::Client&& value)
    : type(CAPABILITY), capabilityValue(kj::mv(value)) {}

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

1353
#define CAPNP_DECLARE_TYPE(discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1354
template <> \
1355
struct DynamicValue::Reader::AsImpl<typeName> { \
1356
  static ReaderFor<typeName> apply(const Reader& reader); \
Kenton Varda's avatar
Kenton Varda committed
1357 1358
}; \
template <> \
1359
struct DynamicValue::Builder::AsImpl<typeName> { \
1360
  static BuilderFor<typeName> apply(Builder& builder); \
Kenton Varda's avatar
Kenton Varda committed
1361 1362
};

1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
//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
1383 1384 1385
#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
1386 1387
// ReaderFor<> and BuilderFor<> wrappers, it works.
template <>
1388
struct DynamicValue::Reader::AsImpl<Void> {
1389
  static Void apply(const Reader& reader);
Kenton Varda's avatar
Kenton Varda committed
1390 1391
};
template <>
1392
struct DynamicValue::Builder::AsImpl<Void> {
1393
  static Void apply(Builder& builder);
Kenton Varda's avatar
Kenton Varda committed
1394 1395 1396
};

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

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

template <typename T>
1423
struct DynamicValue::Reader::AsImpl<T, Kind::LIST> {
1424
  static typename T::Reader apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1425
    return reader.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1426 1427 1428
  }
};
template <typename T>
1429
struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
1430
  static typename T::Builder apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1431
    return builder.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
1432 1433 1434
  }
};

1435 1436
template <typename T>
struct DynamicValue::Reader::AsImpl<T, Kind::INTERFACE> {
1437
  static typename T::Client apply(const Reader& reader) {
1438 1439 1440 1441 1442 1443 1444 1445 1446 1447
    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>();
  }
};

1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460
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;
  }
};

1461
inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {}
1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479
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 <>
1480
struct DynamicValue::Pipeline::AsImpl<DynamicStruct, Kind::OTHER> {
1481 1482 1483
  static PipelineFor<DynamicStruct> apply(Pipeline& pipeline);
};
template <>
1484
struct DynamicValue::Pipeline::AsImpl<DynamicCapability, Kind::OTHER> {
1485 1486 1487
  static PipelineFor<DynamicCapability> apply(Pipeline& pipeline);
};

Kenton Varda's avatar
Kenton Varda committed
1488 1489
// -------------------------------------------------------------------

Kenton Varda's avatar
Kenton Varda committed
1490
template <typename T>
1491
typename T::Reader DynamicStruct::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1492 1493
  static_assert(kind<T>() == Kind::STRUCT,
                "DynamicStruct::Reader::as<T>() can only convert to struct types.");
1494
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1495 1496
  return typename T::Reader(reader);
}
1497

Kenton Varda's avatar
Kenton Varda committed
1498 1499 1500 1501
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.");
1502
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1503 1504 1505
  return typename T::Builder(builder);
}

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

1515
inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const {
1516
  return DynamicStruct::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
1517 1518
}

1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
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);
}

1529 1530 1531 1532 1533 1534 1535 1536 1537 1538
template <>
inline DynamicStruct::Reader AnyStruct::Reader::as<DynamicStruct>(StructSchema schema) const {
  return DynamicStruct::Reader(schema, _reader);
}

template <>
inline DynamicStruct::Builder AnyStruct::Builder::as<DynamicStruct>(StructSchema schema) {
  return DynamicStruct::Builder(schema, _builder);
}

1539 1540 1541 1542 1543 1544 1545 1546
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
1547 1548 1549
// -------------------------------------------------------------------

template <typename T>
1550
typename T::Reader DynamicList::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
1551 1552
  static_assert(kind<T>() == Kind::LIST,
                "DynamicStruct::Reader::as<T>() can only convert to list types.");
1553
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1554 1555 1556 1557 1558 1559
  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.");
1560
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
1561 1562 1563
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
1564
template <>
1565
inline DynamicList::Reader DynamicList::Reader::as<DynamicList>() const {
Kenton Varda's avatar
Kenton Varda committed
1566 1567 1568 1569 1570 1571 1572
  return *this;
}
template <>
inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
  return *this;
}

1573 1574 1575 1576 1577 1578 1579 1580 1581 1582
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);
}

1583 1584
// -------------------------------------------------------------------

1585 1586 1587 1588 1589
template <typename T, typename>
inline DynamicCapability::Client::Client(T&& client)
    : Capability::Client(kj::mv(client)), schema(Schema::from<FromClient<T>>()) {}

template <typename T, typename>
1590 1591
inline DynamicCapability::Client::Client(kj::Own<T>&& server)
    : Client(server->getSchema(), kj::mv(server)) {}
1592
template <typename T>
1593 1594
inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own<T>&& server)
    : Capability::Client(kj::mv(server)), schema(schema) {}
1595 1596

template <typename T, typename>
1597
typename T::Client DynamicCapability::Client::as() {
1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
  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(
1622 1623
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).getAs<DynamicStruct>(resultType);
1624 1625
}
inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::initResults(
1626 1627
    kj::Maybe<MessageSize> sizeHint) {
  return hook->getResults(sizeHint).initAs<DynamicStruct>(resultType);
1628 1629
}
inline void CallContext<DynamicStruct, DynamicStruct>::setResults(DynamicStruct::Reader value) {
1630
  hook->getResults(value.totalSize()).setAs<DynamicStruct>(value);
1631 1632
}
inline void CallContext<DynamicStruct, DynamicStruct>::adoptResults(Orphan<DynamicStruct>&& value) {
1633
  hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value));
1634 1635
}
inline Orphanage CallContext<DynamicStruct, DynamicStruct>::getResultsOrphanage(
1636 1637
    kj::Maybe<MessageSize> sizeHint) {
  return Orphanage::getForMessageContaining(hook->getResults(sizeHint));
1638
}
Kenton Varda's avatar
Kenton Varda committed
1639 1640 1641 1642 1643
template <typename SubParams>
inline kj::Promise<void> CallContext<DynamicStruct, DynamicStruct>::tailCall(
    Request<SubParams, DynamicStruct>&& tailRequest) {
  return hook->tailCall(kj::mv(tailRequest.hook));
}
1644 1645
inline void CallContext<DynamicStruct, DynamicStruct>::allowCancellation() {
  hook->allowCancellation();
1646 1647 1648 1649
}

template <>
inline DynamicCapability::Client Capability::Client::castAs<DynamicCapability>(
1650
    InterfaceSchema schema) {
1651 1652 1653 1654 1655
  return DynamicCapability::Client(schema, hook->addRef());
}

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

1656 1657 1658 1659 1660
template <typename T>
ReaderFor<T> ConstSchema::as() const {
  return DynamicValue::Reader(*this).as<T>();
}

1661
}  // namespace capnp
Kenton Varda's avatar
Kenton Varda committed
1662

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