dynamic.h 34 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// 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
35 36
#ifndef CAPNP_DYNAMIC_H_
#define CAPNP_DYNAMIC_H_
Kenton Varda's avatar
Kenton Varda committed
37

38
#include "schema.h"
Kenton Varda's avatar
Kenton Varda committed
39
#include "layout.h"
Kenton Varda's avatar
Kenton Varda committed
40
#include "message.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 66 67 68 69 70
    VOID,
    BOOL,
    INT,
    UINT,
    FLOAT,
    TEXT,
    DATA,
    LIST,
    ENUM,
    STRUCT,
    UNION,
    INTERFACE,
    OBJECT
  };

Kenton Varda's avatar
Kenton Varda committed
71 72 73 74
  class Reader;
  class Builder;
};
class DynamicEnum;
Kenton Varda's avatar
Kenton Varda committed
75
class DynamicObject;
Kenton Varda's avatar
Kenton Varda committed
76
struct DynamicUnion {
77
  DynamicUnion() = delete;
Kenton Varda's avatar
Kenton Varda committed
78 79 80 81
  class Reader;
  class Builder;
};
struct DynamicStruct {
82
  DynamicStruct() = delete;
Kenton Varda's avatar
Kenton Varda committed
83 84 85 86
  class Reader;
  class Builder;
};
struct DynamicList {
87
  DynamicList() = delete;
Kenton Varda's avatar
Kenton Varda committed
88 89 90 91
  class Reader;
  class Builder;
};

92 93 94 95 96 97 98 99
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; };

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

Kenton Varda's avatar
Kenton Varda committed
100
template <typename T>
101
ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value);
Kenton Varda's avatar
Kenton Varda committed
102
template <typename T>
103
BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value);
Kenton Varda's avatar
Kenton Varda committed
104
template <typename T>
105
DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value);
Kenton Varda's avatar
Kenton Varda committed
106 107 108 109 110 111 112

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

class DynamicEnum {
public:
  DynamicEnum() = default;

Kenton Varda's avatar
Kenton Varda committed
113
  template <typename T, typename = TypeIfEnum<T>>
Kenton Varda's avatar
Kenton Varda committed
114 115
  inline DynamicEnum(T&& value): DynamicEnum(toDynamic(value)) {}

Kenton Varda's avatar
Kenton Varda committed
116
  template <typename T>
117
  inline T as() const { return static_cast<T>(asImpl(typeId<T>())); }
Kenton Varda's avatar
Kenton Varda committed
118 119
  // Cast to a native enum type.

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

122
  kj::Maybe<EnumSchema::Enumerant> getEnumerant() const;
Kenton Varda's avatar
Kenton Varda committed
123 124 125 126
  // 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.

127
  inline uint16_t getRaw() const { return value; }
Kenton Varda's avatar
Kenton Varda committed
128 129 130
  // Returns the raw underlying enum value.

private:
131
  EnumSchema schema;
Kenton Varda's avatar
Kenton Varda committed
132 133
  uint16_t value;

134 135
  inline DynamicEnum(EnumSchema schema, uint16_t value)
      : schema(schema), value(value) {}
Kenton Varda's avatar
Kenton Varda committed
136

137
  uint16_t asImpl(uint64_t requestedTypeId) const;
Kenton Varda's avatar
Kenton Varda committed
138 139

  friend struct DynamicStruct;
Kenton Varda's avatar
Kenton Varda committed
140
  friend struct DynamicList;
141 142
  template <typename T>
  friend DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value);
Kenton Varda's avatar
Kenton Varda committed
143 144 145 146
};

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

Kenton Varda's avatar
Kenton Varda committed
147 148 149 150 151
class DynamicObject {
  // Represents an "Object" field of unknown type.  This class behaves as a Reader.  There is no
  // equivalent Builder; you must use getObject() or initObject() on the containing struct and
  // specify a type if you want to build an Object field.

Kenton Varda's avatar
Kenton Varda committed
152
public:
Kenton Varda's avatar
Kenton Varda committed
153
  DynamicObject() = default;
Kenton Varda's avatar
Kenton Varda committed
154 155

  template <typename T>
156
  inline typename T::Reader as() const { return AsImpl<T>::apply(*this); }
Kenton Varda's avatar
Kenton Varda committed
157 158
  // Convert the object to the given struct, list, or blob type.

159 160
  DynamicStruct::Reader as(StructSchema schema) const;
  DynamicList::Reader as(ListSchema schema) const;
Kenton Varda's avatar
Kenton Varda committed
161 162

private:
163
  _::ObjectReader reader;
Kenton Varda's avatar
Kenton Varda committed
164

165
  inline DynamicObject(_::ObjectReader reader): reader(reader) {}
Kenton Varda's avatar
Kenton Varda committed
166

167
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
168
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
169 170 171
  // specialization.  Has a method apply() which does the work.

  friend struct DynamicStruct;
Kenton Varda's avatar
Kenton Varda committed
172
  friend struct DynamicList;
Kenton Varda's avatar
Kenton Varda committed
173 174 175 176 177 178 179 180
};

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

class DynamicUnion::Reader {
public:
  Reader() = default;

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

183
  kj::Maybe<StructSchema::Member> which() const;
Kenton Varda's avatar
Kenton Varda committed
184 185 186
  // Returns which field is set, or nullptr if an unknown field is set (i.e. the schema is old, and
  // the underlying data has the union set to a member we don't know about).

187
  DynamicValue::Reader get() const;
188 189
  // Get the value of whichever field of the union is set.  Throws an exception if which() returns
  // nullptr.
Kenton Varda's avatar
Kenton Varda committed
190 191

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

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

  friend struct DynamicStruct;
Kenton Varda's avatar
Kenton Varda committed
199
  friend class DynamicUnion::Builder;
200 201
  friend kj::String _::unionString(
      _::StructReader reader, const _::RawSchema& schema, uint memberIndex);
Kenton Varda's avatar
Kenton Varda committed
202 203 204 205 206 207
};

class DynamicUnion::Builder {
public:
  Builder() = default;

208
  inline StructSchema::Union getSchema() const { return schema; }
Kenton Varda's avatar
Kenton Varda committed
209

210
  kj::Maybe<StructSchema::Member> which();
Kenton Varda's avatar
Kenton Varda committed
211 212 213 214
  // Returns which field is set, or nullptr if an unknown field is set (i.e. the schema is old, and
  // the underlying data has the union set to a member we don't know about).

  DynamicValue::Builder get();
215
  void set(StructSchema::Member member, const DynamicValue::Reader& value);
216 217
  DynamicValue::Builder init(StructSchema::Member member);
  DynamicValue::Builder init(StructSchema::Member member, uint size);
Kenton Varda's avatar
Kenton Varda committed
218

Kenton Varda's avatar
Kenton Varda committed
219 220 221 222 223 224 225 226 227 228
  DynamicStruct::Builder getObject(StructSchema schema);
  DynamicList::Builder getObject(ListSchema schema);
  Text::Builder getObjectAsText();
  Data::Builder getObjectAsData();
  DynamicStruct::Builder initObject(StructSchema::Member member, StructSchema type);
  DynamicList::Builder initObject(StructSchema::Member member, ListSchema type, uint size);
  Text::Builder initObjectAsText(StructSchema::Member member, uint size);
  Data::Builder initObjectAsData(StructSchema::Member member, uint size);
  // Get/init an "Object" member.  Must specify the type.

229 230 231 232 233 234 235
  void set(kj::StringPtr name, const DynamicValue::Reader& value);
  DynamicValue::Builder init(kj::StringPtr name);
  DynamicValue::Builder init(kj::StringPtr name, uint size);
  DynamicStruct::Builder initObject(kj::StringPtr name, StructSchema type);
  DynamicList::Builder initObject(kj::StringPtr name, ListSchema type, uint size);
  Text::Builder initObjectAsText(kj::StringPtr name, uint size);
  Data::Builder initObjectAsData(kj::StringPtr name, uint size);
Kenton Varda's avatar
Kenton Varda committed
236 237
  // Convenience methods that identify the member by text name.

238
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
239

Kenton Varda's avatar
Kenton Varda committed
240
private:
241
  StructSchema::Union schema;
242
  _::StructBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
243

244
  inline Builder(StructSchema::Union schema, _::StructBuilder builder)
245
      : schema(schema), builder(builder) {}
Kenton Varda's avatar
Kenton Varda committed
246

Kenton Varda's avatar
Kenton Varda committed
247 248 249 250
  StructSchema::Member checkIsObject();
  void setDiscriminant(StructSchema::Member member);
  void setObjectDiscriminant(StructSchema::Member member);

Kenton Varda's avatar
Kenton Varda committed
251
  friend struct DynamicStruct;
Kenton Varda's avatar
Kenton Varda committed
252 253 254 255 256 257 258 259
};

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

class DynamicStruct::Reader {
public:
  Reader() = default;

Kenton Varda's avatar
Kenton Varda committed
260
  template <typename T, typename = FromReader<T>>
Kenton Varda's avatar
Kenton Varda committed
261 262
  inline Reader(T&& value): Reader(toDynamic(value)) {}

Kenton Varda's avatar
Kenton Varda committed
263
  template <typename T>
264
  typename T::Reader as() const;
Kenton Varda's avatar
Kenton Varda committed
265 266
  // Convert the dynamic struct to its compiled-in type.

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

269
  DynamicValue::Reader get(StructSchema::Member member) const;
270
  // Read the given member value.
Kenton Varda's avatar
Kenton Varda committed
271

272
  bool has(StructSchema::Member member) const;
273 274 275 276
  // Tests whether the given member is set to its default value.  For pointer values, this does
  // not actually traverse the value comparing it with the default, but simply returns true if the
  // pointer is non-null.

277 278
  DynamicValue::Reader get(kj::StringPtr name) const;
  bool has(kj::StringPtr name) const;
279
  // Shortcuts to access members by name.  These throw exceptions if no such member exists.
Kenton Varda's avatar
Kenton Varda committed
280 281

private:
282
  StructSchema schema;
283
  _::StructReader reader;
Kenton Varda's avatar
Kenton Varda committed
284

285
  inline Reader(StructSchema schema, _::StructReader reader)
286
      : schema(schema), reader(reader) {}
Kenton Varda's avatar
Kenton Varda committed
287

288
  static DynamicValue::Reader getImpl(_::StructReader reader, StructSchema::Member member);
Kenton Varda's avatar
Kenton Varda committed
289

Kenton Varda's avatar
Kenton Varda committed
290
  template <typename T, Kind K>
291
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
292
  friend class DynamicUnion::Reader;
Kenton Varda's avatar
Kenton Varda committed
293
  friend class DynamicObject;
Kenton Varda's avatar
Kenton Varda committed
294 295 296 297
  friend class DynamicStruct::Builder;
  friend struct DynamicList;
  friend class MessageReader;
  friend class MessageBuilder;
298 299
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
300 301
  friend kj::String _::structString(
      _::StructReader reader, const _::RawSchema& schema);
Kenton Varda's avatar
Kenton Varda committed
302 303 304 305 306 307
};

class DynamicStruct::Builder {
public:
  Builder() = default;

Kenton Varda's avatar
Kenton Varda committed
308
  template <typename T, typename = FromBuilder<T>>
Kenton Varda's avatar
Kenton Varda committed
309 310
  inline Builder(T&& value): Builder(toDynamic(value)) {}

Kenton Varda's avatar
Kenton Varda committed
311
  template <typename T>
Kenton Varda's avatar
Kenton Varda committed
312
  typename T::Builder as();
Kenton Varda's avatar
Kenton Varda committed
313 314
  // Cast to a particular struct type.

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

317
  DynamicValue::Builder get(StructSchema::Member member);
318 319
  // Read the given member value.

320 321 322 323 324
  bool has(StructSchema::Member member);
  // Tests whether the given member is set to its default value.  For pointer values, this does
  // not actually traverse the value comparing it with the default, but simply returns true if the
  // pointer is non-null.

325
  void set(StructSchema::Member member, const DynamicValue::Reader& value);
326 327
  // Set the given member value.

328 329
  DynamicValue::Builder init(StructSchema::Member member);
  DynamicValue::Builder init(StructSchema::Member member, uint size);
330 331
  // Init a struct, list, or blob field.

Kenton Varda's avatar
Kenton Varda committed
332 333 334 335 336 337
  DynamicStruct::Builder getObject(StructSchema::Member member, StructSchema type);
  DynamicList::Builder getObject(StructSchema::Member member, ListSchema type);
  Text::Builder getObjectAsText(StructSchema::Member member);
  Data::Builder getObjectAsData(StructSchema::Member member);
  // Get an object field.  You must specify the type.

338 339 340 341 342
  DynamicStruct::Builder initObject(StructSchema::Member member, StructSchema type);
  DynamicList::Builder initObject(StructSchema::Member member, ListSchema type, uint size);
  Text::Builder initObjectAsText(StructSchema::Member member, uint size);
  Data::Builder initObjectAsData(StructSchema::Member member, uint size);
  // Init an object field.  You must specify the type.
343

344 345 346 347 348 349 350 351 352 353 354 355 356 357
  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);
  DynamicStruct::Builder getObject(kj::StringPtr name, StructSchema type);
  DynamicList::Builder getObject(kj::StringPtr name, ListSchema type);
  Text::Builder getObjectAsText(kj::StringPtr name);
  Data::Builder getObjectAsData(kj::StringPtr name);
  DynamicStruct::Builder initObject(kj::StringPtr name, StructSchema type);
  DynamicList::Builder initObject(kj::StringPtr name, ListSchema type, uint size);
  Text::Builder initObjectAsText(kj::StringPtr name, uint size);
  Data::Builder initObjectAsData(kj::StringPtr name, uint size);
358
  // Shortcuts to access members by name.  These throw exceptions if no such member exists.
Kenton Varda's avatar
Kenton Varda committed
359

360
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
361 362

private:
363
  StructSchema schema;
364
  _::StructBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
365

366
  inline Builder(StructSchema schema, _::StructBuilder builder)
367
      : schema(schema), builder(builder) {}
Kenton Varda's avatar
Kenton Varda committed
368

369
  static DynamicValue::Builder getImpl(
370
      _::StructBuilder builder, StructSchema::Member member);
Kenton Varda's avatar
Kenton Varda committed
371
  static DynamicStruct::Builder getObjectImpl(
372
      _::StructBuilder builder, StructSchema::Member field, StructSchema type);
Kenton Varda's avatar
Kenton Varda committed
373
  static DynamicList::Builder getObjectImpl(
374
      _::StructBuilder builder, StructSchema::Member field, ListSchema type);
Kenton Varda's avatar
Kenton Varda committed
375
  static Text::Builder getObjectAsTextImpl(
376
      _::StructBuilder builder, StructSchema::Member field);
Kenton Varda's avatar
Kenton Varda committed
377
  static Data::Builder getObjectAsDataImpl(
378
      _::StructBuilder builder, StructSchema::Member field);
Kenton Varda's avatar
Kenton Varda committed
379

380
  static void setImpl(
381
      _::StructBuilder builder, StructSchema::Member member,
382
      const DynamicValue::Reader& value);
Kenton Varda's avatar
Kenton Varda committed
383

384
  static DynamicValue::Builder initImpl(
385
      _::StructBuilder builder, StructSchema::Member member, uint size);
386
  static DynamicValue::Builder initImpl(
387
      _::StructBuilder builder, StructSchema::Member member);
388
  static DynamicStruct::Builder initFieldImpl(
389
      _::StructBuilder builder, StructSchema::Member field, StructSchema type);
390
  static DynamicList::Builder initFieldImpl(
391
      _::StructBuilder builder, StructSchema::Member field, ListSchema type, uint size);
392
  static Text::Builder initFieldAsTextImpl(
393
      _::StructBuilder builder, StructSchema::Member field, uint size);
394
  static Data::Builder initFieldAsDataImpl(
395
      _::StructBuilder builder, StructSchema::Member field, uint size);
Kenton Varda's avatar
Kenton Varda committed
396

Kenton Varda's avatar
Kenton Varda committed
397
  template <typename T, Kind k>
398
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
399
  friend class DynamicUnion::Builder;
Kenton Varda's avatar
Kenton Varda committed
400 401 402
  friend struct DynamicList;
  friend class MessageReader;
  friend class MessageBuilder;
403 404
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
Kenton Varda's avatar
Kenton Varda committed
405 406 407 408 409 410 411 412
};

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

class DynamicList::Reader {
public:
  Reader() = default;

Kenton Varda's avatar
Kenton Varda committed
413
  template <typename T, typename = FromReader<T>>
Kenton Varda's avatar
Kenton Varda committed
414 415
  inline Reader(T&& value): Reader(toDynamic(value)) {}

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

421
  inline ListSchema getSchema() const { return schema; }
422

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

426
  typedef _::IndexingIterator<const Reader, DynamicValue::Reader> Iterator;
427 428
  inline Iterator begin() const { return Iterator(this, 0); }
  inline Iterator end() const { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
429 430

private:
431
  ListSchema schema;
432
  _::ListReader reader;
Kenton Varda's avatar
Kenton Varda committed
433

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

Kenton Varda's avatar
Kenton Varda committed
436
  template <typename T, Kind k>
437
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
438
  friend struct DynamicStruct;
Kenton Varda's avatar
Kenton Varda committed
439
  friend class DynamicObject;
Kenton Varda's avatar
Kenton Varda committed
440
  friend class DynamicList::Builder;
441 442
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
Kenton Varda's avatar
Kenton Varda committed
443 444 445 446 447 448
};

class DynamicList::Builder {
public:
  Builder() = default;

Kenton Varda's avatar
Kenton Varda committed
449
  template <typename T, typename = FromBuilder<T>>
Kenton Varda's avatar
Kenton Varda committed
450 451
  inline Builder(T&& value): Builder(toDynamic(value)) {}

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

457
  inline ListSchema getSchema() const { return schema; }
458

459
  inline uint size() const { return builder.size() / ELEMENTS; }
460 461
  DynamicValue::Builder operator[](uint index);
  void set(uint index, const DynamicValue::Reader& value);
Kenton Varda's avatar
Kenton Varda committed
462
  DynamicValue::Builder init(uint index, uint size);
Kenton Varda's avatar
Kenton Varda committed
463

464
  typedef _::IndexingIterator<Builder, DynamicStruct::Builder> Iterator;
465 466
  inline Iterator begin() { return Iterator(this, 0); }
  inline Iterator end() { return Iterator(this, size()); }
Kenton Varda's avatar
Kenton Varda committed
467

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

470
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
471 472

private:
473
  ListSchema schema;
474
  _::ListBuilder builder;
Kenton Varda's avatar
Kenton Varda committed
475

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

Kenton Varda's avatar
Kenton Varda committed
478
  template <typename T, Kind k>
479
  friend struct _::PointerHelpers;
Kenton Varda's avatar
Kenton Varda committed
480
  friend struct DynamicStruct;
481 482
  template <typename T, ::capnp::Kind k>
  friend struct ::capnp::ToDynamic_;
Kenton Varda's avatar
Kenton Varda committed
483 484 485 486 487
};

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

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

490 491 492 493 494 495 496 497
template <> struct ReaderFor_ <DynamicEnum, Kind::UNKNOWN> { typedef DynamicEnum Type; };
template <> struct BuilderFor_<DynamicEnum, Kind::UNKNOWN> { typedef DynamicEnum Type; };
template <> struct ReaderFor_ <DynamicObject, Kind::UNKNOWN> { typedef DynamicObject Type; };
template <> struct BuilderFor_<DynamicObject, Kind::UNKNOWN> { typedef DynamicObject 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; };
Kenton Varda's avatar
Kenton Varda committed
498 499 500

class DynamicValue::Reader {
public:
501 502
  inline Reader(std::nullptr_t n = nullptr);  // UNKNOWN
  inline Reader(Void value);
503 504 505 506 507 508 509 510 511 512 513 514 515 516
  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
517
  inline Reader(const char* value);  // Text
518 519 520
  inline Reader(const Text::Reader& value);
  inline Reader(const Data::Reader& value);
  inline Reader(const DynamicList::Reader& value);
521
  inline Reader(DynamicEnum value);
522 523
  inline Reader(const DynamicStruct::Reader& value);
  inline Reader(const DynamicUnion::Reader& value);
Kenton Varda's avatar
Kenton Varda committed
524 525
  inline Reader(DynamicObject value);

Kenton Varda's avatar
Kenton Varda committed
526
  template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
Kenton Varda's avatar
Kenton Varda committed
527
  inline Reader(T value): Reader(toDynamic(value)) {}
Kenton Varda's avatar
Kenton Varda committed
528 529

  template <typename T>
530
  inline ReaderFor<T> as() const { return AsImpl<T>::apply(*this); }
531
  // Use to interpret the value as some Cap'n Proto type.  Allowed types are:
Kenton Varda's avatar
Kenton Varda committed
532 533 534
  // - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum:  Returns the raw value.
  // - Text, Data, any struct type:  Returns the corresponding Reader.
  // - List<T> for any T listed above:  Returns List<T>::Reader.
Kenton Varda's avatar
Kenton Varda committed
535 536
  // - DynamicEnum, DynamicObject:  Returns the corresponding type.
  // - DynamicStruct, DynamicList, DynamicUnion:  Returns the corresponding Reader.
537
  //
538
  // DynamicValue allows various implicit conversions, mostly just to make the interface friendlier.
539 540 541 542 543 544 545
  // - 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.
546 547
  // - Text can be converted to an enum, if the Text matches one of the enumerant names (but not
  //   vice-versa).
548 549
  //
  // Any other conversion attempt will throw an exception.
Kenton Varda's avatar
Kenton Varda committed
550

551
  inline Type getType() const { return type; }
Kenton Varda's avatar
Kenton Varda committed
552 553 554
  // Get the type of this value.

private:
555
  Type type;
Kenton Varda's avatar
Kenton Varda committed
556 557 558 559

  union {
    Void voidValue;
    bool boolValue;
560 561 562
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
563 564 565 566 567
    Text::Reader textValue;
    Data::Reader dataValue;
    DynamicList::Reader listValue;
    DynamicEnum enumValue;
    DynamicStruct::Reader structValue;
568
    DynamicUnion::Reader unionValue;
Kenton Varda's avatar
Kenton Varda committed
569
    DynamicObject objectValue;
Kenton Varda's avatar
Kenton Varda committed
570 571
  };

572
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
573
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
574 575 576 577 578
  // specialization.  Has a method apply() which does the work.
};

class DynamicValue::Builder {
public:
579 580
  inline Builder(std::nullptr_t n = nullptr);  // UNKNOWN
  inline Builder(Void value);
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
  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);
  inline Builder(DynamicUnion::Builder value);
Kenton Varda's avatar
Kenton Varda committed
601
  inline Builder(DynamicObject value);
Kenton Varda's avatar
Kenton Varda committed
602

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

Kenton Varda's avatar
Kenton Varda committed
606
  template <typename T>
607
  inline BuilderFor<T> as() { return AsImpl<T>::apply(*this); }
Kenton Varda's avatar
Kenton Varda committed
608
  // See DynamicValue::Reader::as().
Kenton Varda's avatar
Kenton Varda committed
609

610
  inline Type getType() { return type; }
Kenton Varda's avatar
Kenton Varda committed
611 612
  // Get the type of this value.

613
  Reader asReader() const;
Kenton Varda's avatar
Kenton Varda committed
614 615

private:
616
  Type type;
Kenton Varda's avatar
Kenton Varda committed
617 618 619 620

  union {
    Void voidValue;
    bool boolValue;
621 622 623
    int64_t intValue;
    uint64_t uintValue;
    double floatValue;
Kenton Varda's avatar
Kenton Varda committed
624 625 626 627 628
    Text::Builder textValue;
    Data::Builder dataValue;
    DynamicList::Builder listValue;
    DynamicEnum enumValue;
    DynamicStruct::Builder structValue;
629
    DynamicUnion::Builder unionValue;
Kenton Varda's avatar
Kenton Varda committed
630
    DynamicObject objectValue;
Kenton Varda's avatar
Kenton Varda committed
631 632
  };

633
  template <typename T, Kind kind = kind<T>()> struct AsImpl;
Kenton Varda's avatar
Kenton Varda committed
634
  // Implementation backing the as() method.  Needs to be a struct to allow partial
Kenton Varda's avatar
Kenton Varda committed
635 636 637
  // specialization.  Has a method apply() which does the work.
};

638 639
kj::String KJ_STRINGIFY(const DynamicValue::Reader& value);
kj::String KJ_STRINGIFY(const DynamicValue::Builder& value);
Kenton Varda's avatar
Kenton Varda committed
640
kj::String KJ_STRINGIFY(DynamicEnum value);
641 642 643 644 645 646 647
kj::String KJ_STRINGIFY(const DynamicObject& value);
kj::String KJ_STRINGIFY(const DynamicUnion::Reader& value);
kj::String KJ_STRINGIFY(const DynamicUnion::Builder& value);
kj::String KJ_STRINGIFY(const DynamicStruct::Reader& value);
kj::String KJ_STRINGIFY(const DynamicStruct::Builder& value);
kj::String KJ_STRINGIFY(const DynamicList::Reader& value);
kj::String KJ_STRINGIFY(const DynamicList::Builder& value);
Kenton Varda's avatar
Kenton Varda committed
648

Kenton Varda's avatar
Kenton Varda committed
649 650 651 652 653
// -------------------------------------------------------------------
// Inject the ability to use DynamicStruct for message roots and Dynamic{Struct,List} for
// generated Object accessors.

template <>
654
DynamicStruct::Reader MessageReader::getRoot<DynamicStruct>(StructSchema schema);
Kenton Varda's avatar
Kenton Varda committed
655
template <>
656
DynamicStruct::Builder MessageBuilder::initRoot<DynamicStruct>(StructSchema schema);
Kenton Varda's avatar
Kenton Varda committed
657
template <>
658
DynamicStruct::Builder MessageBuilder::getRoot<DynamicStruct>(StructSchema schema);
Kenton Varda's avatar
Kenton Varda committed
659

660
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
661 662 663

template <>
struct PointerHelpers<DynamicStruct, Kind::UNKNOWN> {
664 665 666 667
  // getDynamic() is used when an Object's get() accessor is passed arguments, because for
  // 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 DynamicStruct::Reader getDynamic(
668
      StructReader reader, WirePointerCount index, StructSchema schema);
669
  static DynamicStruct::Builder getDynamic(
670
      StructBuilder builder, WirePointerCount index, StructSchema schema);
671
  static void set(
672
      StructBuilder builder, WirePointerCount index, const DynamicStruct::Reader& value);
673
  static DynamicStruct::Builder init(
674
      StructBuilder builder, WirePointerCount index, StructSchema schema);
Kenton Varda's avatar
Kenton Varda committed
675 676 677 678
};

template <>
struct PointerHelpers<DynamicList, Kind::UNKNOWN> {
679 680 681 682
  // getDynamic() is used when an Object's get() accessor is passed arguments, because for
  // 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 DynamicList::Reader getDynamic(
683
      StructReader reader, WirePointerCount index, ListSchema schema);
684
  static DynamicList::Builder getDynamic(
685
      StructBuilder builder, WirePointerCount index, ListSchema schema);
686
  static void set(
687
      StructBuilder builder, WirePointerCount index, const DynamicList::Reader& value);
688
  static DynamicList::Builder init(
689
      StructBuilder builder, WirePointerCount index, ListSchema schema, uint size);
Kenton Varda's avatar
Kenton Varda committed
690 691
};

692
}  // namespace _ (private)
Kenton Varda's avatar
Kenton Varda committed
693

Kenton Varda's avatar
Kenton Varda committed
694
// =======================================================================================
Kenton Varda's avatar
Kenton Varda committed
695
// Inline implementation details.
Kenton Varda's avatar
Kenton Varda committed
696

697
template <typename T>
698
struct ToDynamic_<T, Kind::STRUCT> {
699
  static inline DynamicStruct::Reader apply(const typename T::Reader& value) {
700
    return DynamicStruct::Reader(Schema::from<T>(), value._reader);
701
  }
702
  static inline DynamicStruct::Builder apply(typename T::Builder& value) {
703
    return DynamicStruct::Builder(Schema::from<T>(), value._builder);
704 705 706 707
  }
};

template <typename T>
708
struct ToDynamic_<T, Kind::LIST> {
709
  static inline DynamicList::Reader apply(const typename T::Reader& value) {
710
    return DynamicList::Reader(Schema::from<T>(), value.reader);
711
  }
712
  static inline DynamicList::Builder apply(typename T::Builder& value) {
713
    return DynamicList::Builder(Schema::from<T>(), value.builder);
714 715 716 717
  }
};

template <typename T>
718 719
ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromReader<T>>::apply(value);
720 721
}
template <typename T>
722 723
BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value) {
  return ToDynamic_<FromBuilder<T>>::apply(value);
724
}
725
template <typename T>
726
DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) {
727
  return DynamicEnum(Schema::from<kj::Decay<T>>(), static_cast<uint16_t>(value));
728
}
729

730 731 732
inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {}
inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {}

Kenton Varda's avatar
Kenton Varda committed
733
    #define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
734 735 736 737 738
inline DynamicValue::Reader::Reader(cppType value) \
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType value) \
    : type(typeTag), fieldName##Value(value) {}

Kenton Varda's avatar
Kenton Varda committed
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
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);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicObject, OBJECT, object);
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR

#define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
759
inline DynamicValue::Reader::Reader(const cppType::Reader& value) \
760 761 762 763
    : type(typeTag), fieldName##Value(value) {} \
inline DynamicValue::Builder::Builder(cppType::Builder value) \
    : type(typeTag), fieldName##Value(value) {}

Kenton Varda's avatar
Kenton Varda committed
764 765 766 767 768
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);
CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicUnion, UNION, union);
769

Kenton Varda's avatar
Kenton Varda committed
770
#undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
771

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

Kenton Varda's avatar
Kenton Varda committed
774
#define CAPNP_DECLARE_TYPE(name, discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
775
template <> \
776
struct DynamicValue::Reader::AsImpl<typeName> { \
777
  static ReaderFor<typeName> apply(const Reader& reader); \
Kenton Varda's avatar
Kenton Varda committed
778 779
}; \
template <> \
780
struct DynamicValue::Builder::AsImpl<typeName> { \
781
  static BuilderFor<typeName> apply(Builder& builder); \
Kenton Varda's avatar
Kenton Varda committed
782 783
};

Kenton Varda's avatar
Kenton Varda committed
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
//CAPNP_DECLARE_TYPE(void, VOID, Void)
CAPNP_DECLARE_TYPE(bool, BOOL, bool)
CAPNP_DECLARE_TYPE(int8, INT8, int8_t)
CAPNP_DECLARE_TYPE(int16, INT16, int16_t)
CAPNP_DECLARE_TYPE(int32, INT32, int32_t)
CAPNP_DECLARE_TYPE(int64, INT64, int64_t)
CAPNP_DECLARE_TYPE(uint8, UINT8, uint8_t)
CAPNP_DECLARE_TYPE(uint16, UINT16, uint16_t)
CAPNP_DECLARE_TYPE(uint32, UINT32, uint32_t)
CAPNP_DECLARE_TYPE(uint64, UINT64, uint64_t)
CAPNP_DECLARE_TYPE(float32, FLOAT32, float)
CAPNP_DECLARE_TYPE(float64, FLOAT64, double)

CAPNP_DECLARE_TYPE(text, TEXT, Text)
CAPNP_DECLARE_TYPE(data, DATA, Data)
CAPNP_DECLARE_TYPE(list, LIST, DynamicList)
CAPNP_DECLARE_TYPE(struct, STRUCT, DynamicStruct)
CAPNP_DECLARE_TYPE(enum, ENUM, DynamicEnum)
CAPNP_DECLARE_TYPE(object, OBJECT, DynamicObject)
CAPNP_DECLARE_TYPE(union, UNION, DynamicUnion)
#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
807 808
// ReaderFor<> and BuilderFor<> wrappers, it works.
template <>
809
struct DynamicValue::Reader::AsImpl<Void> {
810
  static Void apply(const Reader& reader);
Kenton Varda's avatar
Kenton Varda committed
811 812
};
template <>
813
struct DynamicValue::Builder::AsImpl<Void> {
814
  static Void apply(Builder& builder);
Kenton Varda's avatar
Kenton Varda committed
815 816 817
};

template <typename T>
818
struct DynamicValue::Reader::AsImpl<T, Kind::ENUM> {
819
  static T apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
820
    return reader.as<DynamicEnum>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
821 822 823
  }
};
template <typename T>
824
struct DynamicValue::Builder::AsImpl<T, Kind::ENUM> {
825
  static T apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
826
    return builder.as<DynamicEnum>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
827 828 829 830
  }
};

template <typename T>
831
struct DynamicValue::Reader::AsImpl<T, Kind::STRUCT> {
832
  static typename T::Reader apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
833
    return reader.as<DynamicStruct>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
834 835 836
  }
};
template <typename T>
837
struct DynamicValue::Builder::AsImpl<T, Kind::STRUCT> {
838
  static typename T::Builder apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
839
    return builder.as<DynamicStruct>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
840 841 842 843
  }
};

template <typename T>
844
struct DynamicValue::Reader::AsImpl<T, Kind::LIST> {
845
  static typename T::Reader apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
846
    return reader.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
847 848 849
  }
};
template <typename T>
850
struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
851
  static typename T::Builder apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
852
    return builder.as<DynamicList>().as<T>();
Kenton Varda's avatar
Kenton Varda committed
853 854 855 856 857 858
  }
};

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

template <typename T>
Kenton Varda's avatar
Kenton Varda committed
859 860
struct DynamicObject::AsImpl<T, Kind::STRUCT> {
  static T apply(DynamicObject value) {
Kenton Varda's avatar
Kenton Varda committed
861
    return value.as(Schema::from<T>()).template as<T>();
Kenton Varda's avatar
Kenton Varda committed
862 863 864 865
  }
};

template <typename T>
Kenton Varda's avatar
Kenton Varda committed
866 867
struct DynamicObject::AsImpl<T, Kind::LIST> {
  static T apply(DynamicObject value) {
Kenton Varda's avatar
Kenton Varda committed
868
    return value.as(Schema::from<T>()).template as<T>();
Kenton Varda's avatar
Kenton Varda committed
869 870 871
  }
};

Kenton Varda's avatar
Kenton Varda committed
872 873
// -------------------------------------------------------------------

874
inline DynamicUnion::Reader DynamicUnion::Builder::asReader() const {
Kenton Varda's avatar
Kenton Varda committed
875 876 877 878 879
  return DynamicUnion::Reader(schema, builder.asReader());
}

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

Kenton Varda's avatar
Kenton Varda committed
880
template <typename T>
881
typename T::Reader DynamicStruct::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
882 883
  static_assert(kind<T>() == Kind::STRUCT,
                "DynamicStruct::Reader::as<T>() can only convert to struct types.");
884
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
885 886 887 888 889 890
  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.");
891
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
892 893 894
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
895
template <>
896
inline DynamicStruct::Reader DynamicStruct::Reader::as<DynamicStruct>() const {
Kenton Varda's avatar
Kenton Varda committed
897 898 899 900 901 902 903
  return *this;
}
template <>
inline DynamicStruct::Builder DynamicStruct::Builder::as<DynamicStruct>() {
  return *this;
}

904
inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const {
905
  return DynamicStruct::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
906 907 908 909 910
}

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

template <typename T>
911
typename T::Reader DynamicList::Reader::as() const {
Kenton Varda's avatar
Kenton Varda committed
912 913
  static_assert(kind<T>() == Kind::LIST,
                "DynamicStruct::Reader::as<T>() can only convert to list types.");
914
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
915 916 917 918 919 920
  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.");
921
  schema.requireUsableAs<T>();
Kenton Varda's avatar
Kenton Varda committed
922 923 924
  return typename T::Builder(builder);
}

Kenton Varda's avatar
Kenton Varda committed
925
template <>
926
inline DynamicList::Reader DynamicList::Reader::as<DynamicList>() const {
Kenton Varda's avatar
Kenton Varda committed
927 928 929 930 931 932 933
  return *this;
}
template <>
inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
  return *this;
}

934
}  // namespace capnp
Kenton Varda's avatar
Kenton Varda committed
935

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