dynamic.c++ 61.3 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
// 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.

#include "dynamic.h"
Kenton Varda's avatar
Kenton Varda committed
25
#include <kj/debug.h>
Kenton Varda's avatar
Kenton Varda committed
26

27
namespace capnp {
Kenton Varda's avatar
Kenton Varda committed
28 29 30 31

namespace {

template <typename T, typename U>
32
KJ_ALWAYS_INLINE(T bitCast(U value));
Kenton Varda's avatar
Kenton Varda committed
33 34 35 36 37 38

template <typename T, typename U>
inline T bitCast(U value) {
  static_assert(sizeof(T) == sizeof(U), "Size must match.");
  return value;
}
Kenton Varda's avatar
Kenton Varda committed
39 40 41 42 43 44 45 46 47 48 49 50
//template <>
//inline float bitCast<float, uint32_t>(uint32_t value) {
//  float result;
//  memcpy(&result, &value, sizeof(value));
//  return result;
//}
//template <>
//inline double bitCast<double, uint64_t>(uint64_t value) {
//  double result;
//  memcpy(&result, &value, sizeof(value));
//  return result;
//}
Kenton Varda's avatar
Kenton Varda committed
51 52 53 54 55 56 57 58 59 60 61 62 63
template <>
inline uint32_t bitCast<uint32_t, float>(float value) {
  uint32_t result;
  memcpy(&result, &value, sizeof(value));
  return result;
}
template <>
inline uint64_t bitCast<uint64_t, double>(double value) {
  uint64_t result;
  memcpy(&result, &value, sizeof(value));
  return result;
}

64
_::FieldSize elementSizeFor(schema::Type::Body::Which elementType) {
Kenton Varda's avatar
Kenton Varda committed
65
  switch (elementType) {
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
    case schema::Type::Body::VOID_TYPE: return _::FieldSize::VOID;
    case schema::Type::Body::BOOL_TYPE: return _::FieldSize::BIT;
    case schema::Type::Body::INT8_TYPE: return _::FieldSize::BYTE;
    case schema::Type::Body::INT16_TYPE: return _::FieldSize::TWO_BYTES;
    case schema::Type::Body::INT32_TYPE: return _::FieldSize::FOUR_BYTES;
    case schema::Type::Body::INT64_TYPE: return _::FieldSize::EIGHT_BYTES;
    case schema::Type::Body::UINT8_TYPE: return _::FieldSize::BYTE;
    case schema::Type::Body::UINT16_TYPE: return _::FieldSize::TWO_BYTES;
    case schema::Type::Body::UINT32_TYPE: return _::FieldSize::FOUR_BYTES;
    case schema::Type::Body::UINT64_TYPE: return _::FieldSize::EIGHT_BYTES;
    case schema::Type::Body::FLOAT32_TYPE: return _::FieldSize::FOUR_BYTES;
    case schema::Type::Body::FLOAT64_TYPE: return _::FieldSize::EIGHT_BYTES;

    case schema::Type::Body::TEXT_TYPE: return _::FieldSize::POINTER;
    case schema::Type::Body::DATA_TYPE: return _::FieldSize::POINTER;
    case schema::Type::Body::LIST_TYPE: return _::FieldSize::POINTER;
    case schema::Type::Body::ENUM_TYPE: return _::FieldSize::TWO_BYTES;
    case schema::Type::Body::STRUCT_TYPE: return _::FieldSize::INLINE_COMPOSITE;
    case schema::Type::Body::INTERFACE_TYPE: return _::FieldSize::POINTER;
85
    case schema::Type::Body::OBJECT_TYPE: KJ_FAIL_ASSERT("List(Object) not supported."); break;
Kenton Varda's avatar
Kenton Varda committed
86
  }
87 88

  // Unknown type.  Treat it as zero-size.
89
  return _::FieldSize::VOID;
Kenton Varda's avatar
Kenton Varda committed
90 91
}

92
inline _::StructSize structSizeFromSchema(StructSchema schema) {
93
  auto node = schema.getProto().getBody().getStructNode();
94
  return _::StructSize(
95
      node.getDataSectionWordSize() * WORDS,
96
      node.getPointerSectionSize() * POINTERS,
97
      static_cast<_::FieldSize>(node.getPreferredListEncoding()));
Kenton Varda's avatar
Kenton Varda committed
98 99
}

Kenton Varda's avatar
Kenton Varda committed
100 101 102 103
}  // namespace

// =======================================================================================

104
kj::Maybe<EnumSchema::Enumerant> DynamicEnum::getEnumerant() const {
105
  auto enumerants = schema.getEnumerants();
Kenton Varda's avatar
Kenton Varda committed
106 107 108 109 110 111 112
  if (value < enumerants.size()) {
    return enumerants[value];
  } else {
    return nullptr;
  }
}

113
uint16_t DynamicEnum::asImpl(uint64_t requestedTypeId) const {
114 115
  KJ_REQUIRE(requestedTypeId == schema.getProto().getId(),
             "Type mismatch in DynamicEnum.as().") {
116
    // use it anyway
117
    break;
Kenton Varda's avatar
Kenton Varda committed
118 119 120 121 122 123
  }
  return value;
}

// =======================================================================================

124
DynamicStruct::Reader DynamicObject::as(StructSchema schema) const {
125 126
  if (reader.kind == _::ObjectKind::NULL_POINTER) {
    return DynamicStruct::Reader(schema, _::StructReader());
Kenton Varda's avatar
Kenton Varda committed
127
  }
128
  KJ_REQUIRE(reader.kind == _::ObjectKind::STRUCT, "Object is not a struct.") {
129
    // Return default struct.
130
    return DynamicStruct::Reader(schema, _::StructReader());
Kenton Varda's avatar
Kenton Varda committed
131
  }
132
  return DynamicStruct::Reader(schema, reader.structReader);
Kenton Varda's avatar
Kenton Varda committed
133 134
}

135
DynamicList::Reader DynamicObject::as(ListSchema schema) const {
136 137
  if (reader.kind == _::ObjectKind::NULL_POINTER) {
    return DynamicList::Reader(schema, _::ListReader());
Kenton Varda's avatar
Kenton Varda committed
138
  }
139
  KJ_REQUIRE(reader.kind == _::ObjectKind::LIST, "Object is not a list.") {
140
    // Return empty list.
141
    return DynamicList::Reader(schema, _::ListReader());
Kenton Varda's avatar
Kenton Varda committed
142
  }
143
  return DynamicList::Reader(schema, reader.listReader);
Kenton Varda's avatar
Kenton Varda committed
144 145 146 147
}

// =======================================================================================

148
kj::Maybe<StructSchema::Member> DynamicUnion::Reader::which() const {
149
  auto members = schema.getMembers();
Kenton Varda's avatar
Kenton Varda committed
150
  uint16_t discrim = reader.getDataField<uint16_t>(
151
      schema.getProto().getBody().getUnionMember().getDiscriminantOffset() * ELEMENTS);
Kenton Varda's avatar
Kenton Varda committed
152 153 154 155 156 157 158

  if (discrim < members.size()) {
    return members[discrim];
  } else {
    return nullptr;
  }
}
159
kj::Maybe<StructSchema::Member> DynamicUnion::Builder::which() {
160
  auto members = schema.getMembers();
Kenton Varda's avatar
Kenton Varda committed
161
  uint16_t discrim = builder.getDataField<uint16_t>(
162
      schema.getProto().getBody().getUnionMember().getDiscriminantOffset() * ELEMENTS);
Kenton Varda's avatar
Kenton Varda committed
163 164 165 166 167 168 169 170

  if (discrim < members.size()) {
    return members[discrim];
  } else {
    return nullptr;
  }
}

171
DynamicValue::Reader DynamicUnion::Reader::get() const {
172
  KJ_IF_MAYBE(w, which()) {
173
    return DynamicValue::Reader(DynamicStruct::Reader::getImpl(reader, *w));
174 175
  } else {
    return nullptr;
176
  }
Kenton Varda's avatar
Kenton Varda committed
177 178 179
}

DynamicValue::Builder DynamicUnion::Builder::get() {
180
  KJ_IF_MAYBE(w, which()) {
181
    return DynamicValue::Builder(DynamicStruct::Builder::getImpl(builder, *w));
182 183
  } else {
    return nullptr;
184
  }
Kenton Varda's avatar
Kenton Varda committed
185 186
}

187
void DynamicUnion::Builder::set(StructSchema::Member member, const DynamicValue::Reader& value) {
Kenton Varda's avatar
Kenton Varda committed
188
  setDiscriminant(member);
189
  DynamicStruct::Builder::setImpl(builder, member, value);
Kenton Varda's avatar
Kenton Varda committed
190 191
}

192
DynamicValue::Builder DynamicUnion::Builder::init(StructSchema::Member member) {
Kenton Varda's avatar
Kenton Varda committed
193
  setDiscriminant(member);
194
  return DynamicStruct::Builder::initImpl(builder, member);
Kenton Varda's avatar
Kenton Varda committed
195 196
}

197
DynamicValue::Builder DynamicUnion::Builder::init(StructSchema::Member member, uint size) {
Kenton Varda's avatar
Kenton Varda committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
  setDiscriminant(member);
  return DynamicStruct::Builder::initImpl(builder, member, size);
}

DynamicStruct::Builder DynamicUnion::Builder::getObject(StructSchema schema) {
  return DynamicStruct::Builder::getObjectImpl(builder, checkIsObject(), schema);
}
DynamicList::Builder DynamicUnion::Builder::getObject(ListSchema schema) {
  return DynamicStruct::Builder::getObjectImpl(builder, checkIsObject(), schema);
}
Text::Builder DynamicUnion::Builder::getObjectAsText() {
  return DynamicStruct::Builder::getObjectAsTextImpl(builder, checkIsObject());
}
Data::Builder DynamicUnion::Builder::getObjectAsData() {
  return DynamicStruct::Builder::getObjectAsDataImpl(builder, checkIsObject());
}
DynamicStruct::Builder DynamicUnion::Builder::initObject(
    StructSchema::Member member, StructSchema type) {
  setObjectDiscriminant(member);
  return DynamicStruct::Builder::initFieldImpl(builder, member, type);
}
DynamicList::Builder DynamicUnion::Builder::initObject(
    StructSchema::Member member, ListSchema type, uint size) {
  setObjectDiscriminant(member);
  return DynamicStruct::Builder::initFieldImpl(builder, member, type, size);
}
Text::Builder DynamicUnion::Builder::initObjectAsText(StructSchema::Member member, uint size) {
  setObjectDiscriminant(member);
  return DynamicStruct::Builder::initFieldAsTextImpl(builder, member, size);
}
Data::Builder DynamicUnion::Builder::initObjectAsData(StructSchema::Member member, uint size) {
  setObjectDiscriminant(member);
  return DynamicStruct::Builder::initFieldAsDataImpl(builder, member, size);
}

233
void DynamicUnion::Builder::set(kj::StringPtr name, const DynamicValue::Reader& value) {
Kenton Varda's avatar
Kenton Varda committed
234 235
  set(schema.getMemberByName(name), value);
}
236
DynamicValue::Builder DynamicUnion::Builder::init(kj::StringPtr name) {
Kenton Varda's avatar
Kenton Varda committed
237 238
  return init(schema.getMemberByName(name));
}
239
DynamicValue::Builder DynamicUnion::Builder::init(kj::StringPtr name, uint size) {
Kenton Varda's avatar
Kenton Varda committed
240 241
  return init(schema.getMemberByName(name), size);
}
242
DynamicStruct::Builder DynamicUnion::Builder::initObject(kj::StringPtr name, StructSchema type) {
Kenton Varda's avatar
Kenton Varda committed
243 244 245
  return initObject(schema.getMemberByName(name), type);
}
DynamicList::Builder DynamicUnion::Builder::initObject(
246
    kj::StringPtr name, ListSchema type, uint size) {
Kenton Varda's avatar
Kenton Varda committed
247 248
  return initObject(schema.getMemberByName(name), type, size);
}
249
Text::Builder DynamicUnion::Builder::initObjectAsText(kj::StringPtr name, uint size) {
Kenton Varda's avatar
Kenton Varda committed
250 251
  return initObjectAsText(schema.getMemberByName(name), size);
}
252
Data::Builder DynamicUnion::Builder::initObjectAsData(kj::StringPtr name, uint size) {
Kenton Varda's avatar
Kenton Varda committed
253 254 255
  return initObjectAsData(schema.getMemberByName(name), size);
}

256
StructSchema::Member DynamicUnion::Builder::checkIsObject() {
257
  KJ_IF_MAYBE(w, which()) {
258
    KJ_ASSERT(w->getProto().getBody().which() == schema::StructNode::Member::Body::FIELD_MEMBER,
259
          "Unsupported union member type.");
260
    KJ_REQUIRE(w->getProto().getBody().getFieldMember().getType().getBody().which() ==
261 262 263
            schema::Type::Body::OBJECT_TYPE, "Expected Object.");
    return *w;
  } else {
264
    KJ_FAIL_REQUIRE("Can't get() unknown union value.");
265
  }
Kenton Varda's avatar
Kenton Varda committed
266 267 268
}

void DynamicUnion::Builder::setDiscriminant(StructSchema::Member member) {
269
  KJ_IF_MAYBE(containingUnion, member.getContainingUnion()) {
270
    KJ_REQUIRE(*containingUnion == schema, "`member` is not a member of this union.");
271 272 273 274
    builder.setDataField<uint16_t>(
        schema.getProto().getBody().getUnionMember().getDiscriminantOffset() * ELEMENTS,
        member.getIndex());
  } else {
275
    KJ_FAIL_REQUIRE("`member` is not a member of this union.");
276
  }
Kenton Varda's avatar
Kenton Varda committed
277 278 279
}

void DynamicUnion::Builder::setObjectDiscriminant(StructSchema::Member member) {
280
  KJ_REQUIRE(member.getProto().getBody().getFieldMember().getType().getBody().which() ==
Kenton Varda's avatar
Kenton Varda committed
281 282
          schema::Type::Body::OBJECT_TYPE, "Expected Object.");
  setDiscriminant(member);
Kenton Varda's avatar
Kenton Varda committed
283 284
}

Kenton Varda's avatar
Kenton Varda committed
285 286
// =======================================================================================

287
DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Member member) const {
288
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
289
  return getImpl(reader, member);
Kenton Varda's avatar
Kenton Varda committed
290
}
291
DynamicValue::Builder DynamicStruct::Builder::get(StructSchema::Member member) {
292
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
293
  return getImpl(builder, member);
Kenton Varda's avatar
Kenton Varda committed
294
}
295

296
bool DynamicStruct::Reader::has(StructSchema::Member member) const {
297
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358

  auto body = member.getProto().getBody();
  switch (body.which()) {
    case schema::StructNode::Member::Body::UNION_MEMBER: {
      auto u = body.getUnionMember();
      if (reader.getDataField<uint16_t>(u.getDiscriminantOffset() * ELEMENTS) != 0) {
        // Union has non-default member set.
        return true;
      }
      auto members = member.asUnion().getMembers();
      if (members.size() == 0) {
        // Union has no defined members.  This should probably be disallowed?
        return false;
      }

      // The union has the default member set, so now the question is whether that member is set
      // to its default value.  So, continue on with the function using that member.
      member = members[0];
      break;
    }

    case schema::StructNode::Member::Body::FIELD_MEMBER:
      // Continue to below.
      break;
  }

  auto field = member.getProto().getBody().getFieldMember();
  auto type = field.getType().getBody();

  switch (type.which()) {
    case schema::Type::Body::VOID_TYPE:
      return false;

#define HANDLE_TYPE(discrim, type) \
    case schema::Type::Body::discrim##_TYPE: \
      return reader.getDataField<type>(field.getOffset() * ELEMENTS) != 0;

    HANDLE_TYPE(BOOL, bool)
    HANDLE_TYPE(INT8, uint8_t)
    HANDLE_TYPE(INT16, uint16_t)
    HANDLE_TYPE(INT32, uint32_t)
    HANDLE_TYPE(INT64, uint64_t)
    HANDLE_TYPE(UINT8, uint8_t)
    HANDLE_TYPE(UINT16, uint16_t)
    HANDLE_TYPE(UINT32, uint32_t)
    HANDLE_TYPE(UINT64, uint64_t)
    HANDLE_TYPE(FLOAT32, uint32_t)
    HANDLE_TYPE(FLOAT64, uint64_t)
    HANDLE_TYPE(ENUM, uint16_t)

#undef HANDLE_TYPE

    case schema::Type::Body::TEXT_TYPE:
    case schema::Type::Body::DATA_TYPE:
    case schema::Type::Body::LIST_TYPE:
    case schema::Type::Body::STRUCT_TYPE:
    case schema::Type::Body::OBJECT_TYPE:
    case schema::Type::Body::INTERFACE_TYPE:
      return !reader.isPointerFieldNull(field.getOffset() * POINTERS);
  }

359
  // Unknown type.  As far as we know, it isn't set.
360 361 362
  return false;
}
bool DynamicStruct::Builder::has(StructSchema::Member member) {
363
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424

  auto body = member.getProto().getBody();
  switch (body.which()) {
    case schema::StructNode::Member::Body::UNION_MEMBER: {
      auto u = body.getUnionMember();
      if (builder.getDataField<uint16_t>(u.getDiscriminantOffset() * ELEMENTS) != 0) {
        // Union has non-default member set.
        return true;
      }
      auto members = member.asUnion().getMembers();
      if (members.size() == 0) {
        // Union has no defined members.  This should probably be disallowed?
        return false;
      }

      // The union has the default member set, so now the question is whether that member is set
      // to its default value.  So, continue on with the function using that member.
      member = members[0];
      break;
    }

    case schema::StructNode::Member::Body::FIELD_MEMBER:
      // Continue to below.
      break;
  }

  auto field = member.getProto().getBody().getFieldMember();
  auto type = field.getType().getBody();

  switch (type.which()) {
    case schema::Type::Body::VOID_TYPE:
      return false;

#define HANDLE_TYPE(discrim, type) \
    case schema::Type::Body::discrim##_TYPE: \
      return builder.getDataField<type>(field.getOffset() * ELEMENTS) != 0;

    HANDLE_TYPE(BOOL, bool)
    HANDLE_TYPE(INT8, uint8_t)
    HANDLE_TYPE(INT16, uint16_t)
    HANDLE_TYPE(INT32, uint32_t)
    HANDLE_TYPE(INT64, uint64_t)
    HANDLE_TYPE(UINT8, uint8_t)
    HANDLE_TYPE(UINT16, uint16_t)
    HANDLE_TYPE(UINT32, uint32_t)
    HANDLE_TYPE(UINT64, uint64_t)
    HANDLE_TYPE(FLOAT32, uint32_t)
    HANDLE_TYPE(FLOAT64, uint64_t)
    HANDLE_TYPE(ENUM, uint16_t)

#undef HANDLE_TYPE

    case schema::Type::Body::TEXT_TYPE:
    case schema::Type::Body::DATA_TYPE:
    case schema::Type::Body::LIST_TYPE:
    case schema::Type::Body::STRUCT_TYPE:
    case schema::Type::Body::OBJECT_TYPE:
    case schema::Type::Body::INTERFACE_TYPE:
      return !builder.isPointerFieldNull(field.getOffset() * POINTERS);
  }

425
  // Unknown type.  As far as we know, it isn't set.
426 427 428
  return false;
}

429
void DynamicStruct::Builder::set(StructSchema::Member member, const DynamicValue::Reader& value) {
430
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
431 432 433
  return setImpl(builder, member, value);
}
DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Member member) {
434
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
435 436 437
  return initImpl(builder, member);
}
DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Member member, uint size) {
438
  KJ_REQUIRE(member.getContainingStruct() == schema,
439 440 441
          "`member` is not a member of this struct.");
  return initImpl(builder, member, size);
}
Kenton Varda's avatar
Kenton Varda committed
442 443 444

DynamicStruct::Builder DynamicStruct::Builder::getObject(
    StructSchema::Member member, StructSchema type) {
445
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
Kenton Varda's avatar
Kenton Varda committed
446 447
  switch (member.getProto().getBody().which()) {
    case schema::StructNode::Member::Body::UNION_MEMBER:
448
      KJ_FAIL_REQUIRE("Expected an Object.");
449
      break;
Kenton Varda's avatar
Kenton Varda committed
450 451 452

    case schema::StructNode::Member::Body::FIELD_MEMBER: {
      auto field = member.getProto().getBody().getFieldMember();
453
      KJ_REQUIRE(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
Kenton Varda's avatar
Kenton Varda committed
454 455 456 457 458
              "Expected an Object.");
      return getObjectImpl(builder, member, type);
    }
  }

459
  KJ_FAIL_ASSERT("switch() missing case.", (uint)member.getProto().getBody().which());
Kenton Varda's avatar
Kenton Varda committed
460 461 462 463
  return DynamicStruct::Builder();
}
DynamicList::Builder DynamicStruct::Builder::getObject(
    StructSchema::Member member, ListSchema type) {
464
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
Kenton Varda's avatar
Kenton Varda committed
465 466
  switch (member.getProto().getBody().which()) {
    case schema::StructNode::Member::Body::UNION_MEMBER:
467
      KJ_FAIL_REQUIRE("Expected an Object.");
468
      break;
Kenton Varda's avatar
Kenton Varda committed
469 470 471

    case schema::StructNode::Member::Body::FIELD_MEMBER: {
      auto field = member.getProto().getBody().getFieldMember();
472
      KJ_REQUIRE(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
Kenton Varda's avatar
Kenton Varda committed
473 474 475 476 477
              "Expected an Object.");
      return getObjectImpl(builder, member, type);
    }
  }

478
  KJ_FAIL_ASSERT("switch() missing case.", (uint)member.getProto().getBody().which());
Kenton Varda's avatar
Kenton Varda committed
479 480 481
  return DynamicList::Builder();
}
Text::Builder DynamicStruct::Builder::getObjectAsText(StructSchema::Member member) {
482
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
Kenton Varda's avatar
Kenton Varda committed
483 484
  switch (member.getProto().getBody().which()) {
    case schema::StructNode::Member::Body::UNION_MEMBER:
485
      KJ_FAIL_REQUIRE("Expected an Object.");
Kenton Varda's avatar
Kenton Varda committed
486 487 488 489
      return Text::Builder();

    case schema::StructNode::Member::Body::FIELD_MEMBER: {
      auto field = member.getProto().getBody().getFieldMember();
490
      KJ_REQUIRE(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
Kenton Varda's avatar
Kenton Varda committed
491
              "Expected an Object.");
492
      return getObjectAsTextImpl(builder, member);
Kenton Varda's avatar
Kenton Varda committed
493 494 495
    }
  }

496
  KJ_FAIL_ASSERT("switch() missing case.", (uint)member.getProto().getBody().which());
Kenton Varda's avatar
Kenton Varda committed
497 498 499
  return Text::Builder();
}
Data::Builder DynamicStruct::Builder::getObjectAsData(StructSchema::Member member) {
500
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
Kenton Varda's avatar
Kenton Varda committed
501 502
  switch (member.getProto().getBody().which()) {
    case schema::StructNode::Member::Body::UNION_MEMBER:
503
      KJ_FAIL_REQUIRE("Expected an Object.");
Kenton Varda's avatar
Kenton Varda committed
504 505 506 507
      return Data::Builder();

    case schema::StructNode::Member::Body::FIELD_MEMBER: {
      auto field = member.getProto().getBody().getFieldMember();
508
      KJ_REQUIRE(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
Kenton Varda's avatar
Kenton Varda committed
509 510 511 512 513
              "Expected an Object.");
      return getObjectAsDataImpl(builder, member);
    }
  }

514
  KJ_FAIL_ASSERT("switch() missing case.", (uint)member.getProto().getBody().which());
Kenton Varda's avatar
Kenton Varda committed
515 516 517
  return Data::Builder();
}

518 519
DynamicStruct::Builder DynamicStruct::Builder::initObject(
    StructSchema::Member member, StructSchema type) {
520
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
521 522
  switch (member.getProto().getBody().which()) {
    case schema::StructNode::Member::Body::UNION_MEMBER:
523
      KJ_FAIL_REQUIRE("Expected an Object.");
524
      return DynamicStruct::Builder();
Kenton Varda's avatar
Kenton Varda committed
525

526 527
    case schema::StructNode::Member::Body::FIELD_MEMBER: {
      auto field = member.getProto().getBody().getFieldMember();
528
      KJ_REQUIRE(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
Kenton Varda's avatar
Kenton Varda committed
529
              "Expected an Object.");
530 531
      return initFieldImpl(builder, member, type);
    }
Kenton Varda's avatar
Kenton Varda committed
532
  }
533

534
  KJ_FAIL_ASSERT("switch() missing case.", (uint)member.getProto().getBody().which());
535
  return DynamicStruct::Builder();
Kenton Varda's avatar
Kenton Varda committed
536
}
537 538
DynamicList::Builder DynamicStruct::Builder::initObject(
    StructSchema::Member member, ListSchema type, uint size) {
539
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
540 541
  switch (member.getProto().getBody().which()) {
    case schema::StructNode::Member::Body::UNION_MEMBER:
542
      KJ_FAIL_REQUIRE("Expected an Object.");
543 544 545 546
      return DynamicList::Builder();

    case schema::StructNode::Member::Body::FIELD_MEMBER: {
      auto field = member.getProto().getBody().getFieldMember();
547
      KJ_REQUIRE(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
Kenton Varda's avatar
Kenton Varda committed
548
              "Expected an Object.");
549 550
      return initFieldImpl(builder, member, type, size);
    }
Kenton Varda's avatar
Kenton Varda committed
551 552
  }

553
  KJ_FAIL_ASSERT("switch() missing case.", (uint)member.getProto().getBody().which());
554 555 556
  return DynamicList::Builder();
}
Text::Builder DynamicStruct::Builder::initObjectAsText(StructSchema::Member member, uint size) {
557
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
558
  switch (member.getProto().getBody().which()) {
559
    case schema::StructNode::Member::Body::UNION_MEMBER:
560
      KJ_FAIL_REQUIRE("Expected an Object.");
561
      return Text::Builder();
562 563

    case schema::StructNode::Member::Body::FIELD_MEMBER: {
564
      auto field = member.getProto().getBody().getFieldMember();
565
      KJ_REQUIRE(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
Kenton Varda's avatar
Kenton Varda committed
566
              "Expected an Object.");
567
      return initFieldAsTextImpl(builder, member, size);
568
    }
Kenton Varda's avatar
Kenton Varda committed
569
  }
570

571
  KJ_FAIL_ASSERT("switch() missing case.", (uint)member.getProto().getBody().which());
572
  return Text::Builder();
573
}
574
Data::Builder DynamicStruct::Builder::initObjectAsData(StructSchema::Member member, uint size) {
575
  KJ_REQUIRE(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
576
  switch (member.getProto().getBody().which()) {
577
    case schema::StructNode::Member::Body::UNION_MEMBER:
578
      KJ_FAIL_REQUIRE("Expected an Object.");
579
      return Data::Builder();
580 581

    case schema::StructNode::Member::Body::FIELD_MEMBER: {
582
      auto field = member.getProto().getBody().getFieldMember();
583
      KJ_REQUIRE(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
Kenton Varda's avatar
Kenton Varda committed
584
              "Expected an Object.");
585
      return initFieldAsDataImpl(builder, member, size);
586
    }
Kenton Varda's avatar
Kenton Varda committed
587
  }
588

589
  KJ_FAIL_ASSERT("switch() missing case.", (uint)member.getProto().getBody().which());
590
  return Data::Builder();
Kenton Varda's avatar
Kenton Varda committed
591 592
}

593
DynamicValue::Reader DynamicStruct::Reader::get(kj::StringPtr name) const {
Kenton Varda's avatar
Kenton Varda committed
594
  return getImpl(reader, schema.getMemberByName(name));
595
}
596
DynamicValue::Builder DynamicStruct::Builder::get(kj::StringPtr name) {
Kenton Varda's avatar
Kenton Varda committed
597
  return getImpl(builder, schema.getMemberByName(name));
598
}
599
bool DynamicStruct::Reader::has(kj::StringPtr name) const {
600 601
  return has(schema.getMemberByName(name));
}
602
bool DynamicStruct::Builder::has(kj::StringPtr name) {
603 604
  return has(schema.getMemberByName(name));
}
605
void DynamicStruct::Builder::set(kj::StringPtr name, const DynamicValue::Reader& value) {
Kenton Varda's avatar
Kenton Varda committed
606
  setImpl(builder, schema.getMemberByName(name), value);
Kenton Varda's avatar
Kenton Varda committed
607
}
608
void DynamicStruct::Builder::set(kj::StringPtr name,
609 610 611
                                 std::initializer_list<DynamicValue::Reader> value) {
  init(name, value.size()).as<DynamicList>().copyFrom(value);
}
612
DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name) {
Kenton Varda's avatar
Kenton Varda committed
613
  return initImpl(builder, schema.getMemberByName(name));
614
}
615
DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name, uint size) {
Kenton Varda's avatar
Kenton Varda committed
616 617 618
  return initImpl(builder, schema.getMemberByName(name), size);
}
DynamicStruct::Builder DynamicStruct::Builder::getObject(
619
    kj::StringPtr name, StructSchema type) {
Kenton Varda's avatar
Kenton Varda committed
620 621
  return getObject(schema.getMemberByName(name), type);
}
622
DynamicList::Builder DynamicStruct::Builder::getObject(kj::StringPtr name, ListSchema type) {
Kenton Varda's avatar
Kenton Varda committed
623 624
  return getObject(schema.getMemberByName(name), type);
}
625
Text::Builder DynamicStruct::Builder::getObjectAsText(kj::StringPtr name) {
Kenton Varda's avatar
Kenton Varda committed
626 627
  return getObjectAsText(schema.getMemberByName(name));
}
628
Data::Builder DynamicStruct::Builder::getObjectAsData(kj::StringPtr name) {
629
  return getObjectAsData(schema.getMemberByName(name));
630
}
631
DynamicStruct::Builder DynamicStruct::Builder::initObject(
632
    kj::StringPtr name, StructSchema type) {
Kenton Varda's avatar
Kenton Varda committed
633
  return initObject(schema.getMemberByName(name), type);
634
}
635
DynamicList::Builder DynamicStruct::Builder::initObject(
636
    kj::StringPtr name, ListSchema type, uint size) {
Kenton Varda's avatar
Kenton Varda committed
637
  return initObject(schema.getMemberByName(name), type, size);
Kenton Varda's avatar
Kenton Varda committed
638
}
639
Text::Builder DynamicStruct::Builder::initObjectAsText(kj::StringPtr name, uint size) {
Kenton Varda's avatar
Kenton Varda committed
640
  return initObjectAsText(schema.getMemberByName(name), size);
641
}
642
Data::Builder DynamicStruct::Builder::initObjectAsData(kj::StringPtr name, uint size) {
643
  return initObjectAsData(schema.getMemberByName(name), size);
644
}
Kenton Varda's avatar
Kenton Varda committed
645

646
DynamicValue::Reader DynamicStruct::Reader::getImpl(
647
    _::StructReader reader, StructSchema::Member member) {
648
  switch (member.getProto().getBody().which()) {
649
    case schema::StructNode::Member::Body::UNION_MEMBER:
650
      return DynamicUnion::Reader(member.asUnion(), reader);
Kenton Varda's avatar
Kenton Varda committed
651

652
    case schema::StructNode::Member::Body::FIELD_MEMBER: {
653
      auto field = member.getProto().getBody().getFieldMember();
654 655 656 657 658 659
      auto type = field.getType().getBody();
      auto dval = field.getDefaultValue().getBody();

      switch (type.which()) {
        case schema::Type::Body::VOID_TYPE:
          return DynamicValue::Reader(reader.getDataField<Void>(field.getOffset() * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
660 661

#define HANDLE_TYPE(discrim, titleCase, type) \
662 663 664
        case schema::Type::Body::discrim##_TYPE: \
          return DynamicValue::Reader(reader.getDataField<type>( \
              field.getOffset() * ELEMENTS, \
665
              bitCast<_::Mask<type>>(dval.get##titleCase##Value())));
666 667 668 669 670 671 672 673 674 675 676 677

        HANDLE_TYPE(BOOL, Bool, bool)
        HANDLE_TYPE(INT8, Int8, int8_t)
        HANDLE_TYPE(INT16, Int16, int16_t)
        HANDLE_TYPE(INT32, Int32, int32_t)
        HANDLE_TYPE(INT64, Int64, int64_t)
        HANDLE_TYPE(UINT8, Uint8, uint8_t)
        HANDLE_TYPE(UINT16, Uint16, uint16_t)
        HANDLE_TYPE(UINT32, Uint32, uint32_t)
        HANDLE_TYPE(UINT64, Uint64, uint64_t)
        HANDLE_TYPE(FLOAT32, Float32, float)
        HANDLE_TYPE(FLOAT64, Float64, double)
Kenton Varda's avatar
Kenton Varda committed
678 679 680

#undef HANDLE_TYPE

681 682 683 684
        case schema::Type::Body::ENUM_TYPE: {
          uint16_t typedDval;
          typedDval = dval.getEnumValue();
          return DynamicValue::Reader(DynamicEnum(
685
              member.getContainingStruct().getDependency(type.getEnumType()).asEnum(),
686 687 688 689 690 691
              reader.getDataField<uint16_t>(field.getOffset() * ELEMENTS, typedDval)));
        }

        case schema::Type::Body::TEXT_TYPE: {
          Text::Reader typedDval = dval.getTextValue();
          return DynamicValue::Reader(
692
              reader.getBlobField<Text>(field.getOffset() * POINTERS,
693
                                        typedDval.begin(), typedDval.size() * BYTES));
694 695 696 697 698
        }

        case schema::Type::Body::DATA_TYPE: {
          Data::Reader typedDval = dval.getDataValue();
          return DynamicValue::Reader(
699
              reader.getBlobField<Data>(field.getOffset() * POINTERS,
700
                                        typedDval.begin(), typedDval.size() * BYTES));
701 702 703 704 705
        }

        case schema::Type::Body::LIST_TYPE: {
          auto elementType = type.getListType();
          return DynamicValue::Reader(DynamicList::Reader(
706
              ListSchema::of(elementType, member.getContainingStruct()),
707
              reader.getListField(field.getOffset() * POINTERS,
708
                                  elementSizeFor(elementType.getBody().which()),
709
                                  dval.getListValue<_::UncheckedMessage>())));
710 711 712 713
        }

        case schema::Type::Body::STRUCT_TYPE: {
          return DynamicValue::Reader(DynamicStruct::Reader(
714
              member.getContainingStruct().getDependency(type.getStructType()).asStruct(),
715
              reader.getStructField(field.getOffset() * POINTERS,
716
                                    dval.getStructValue<_::UncheckedMessage>())));
717 718 719
        }

        case schema::Type::Body::OBJECT_TYPE: {
Kenton Varda's avatar
Kenton Varda committed
720
          return DynamicValue::Reader(DynamicObject(
721
              reader.getObjectField(field.getOffset() * POINTERS,
722
                                    dval.getObjectValue<_::UncheckedMessage>())));
723 724 725
        }

        case schema::Type::Body::INTERFACE_TYPE:
726
          KJ_FAIL_ASSERT("Interfaces not yet implemented.");
727 728
          break;
      }
Kenton Varda's avatar
Kenton Varda committed
729

730
      return nullptr;
Kenton Varda's avatar
Kenton Varda committed
731 732 733
    }
  }

734
  KJ_FAIL_ASSERT("switch() missing case.", (uint)member.getProto().getBody().which());
735
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
736 737
}

738
DynamicValue::Builder DynamicStruct::Builder::getImpl(
739
    _::StructBuilder builder, StructSchema::Member member) {
740
  switch (member.getProto().getBody().which()) {
741
    case schema::StructNode::Member::Body::UNION_MEMBER:
742
      return DynamicUnion::Builder(member.asUnion(), builder);
Kenton Varda's avatar
Kenton Varda committed
743

744
    case schema::StructNode::Member::Body::FIELD_MEMBER: {
745
      auto field = member.getProto().getBody().getFieldMember();
746 747 748 749 750 751
      auto type = field.getType().getBody();
      auto dval = field.getDefaultValue().getBody();

      switch (type.which()) {
        case schema::Type::Body::VOID_TYPE:
          return DynamicValue::Builder(builder.getDataField<Void>(field.getOffset() * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
752 753

#define HANDLE_TYPE(discrim, titleCase, type) \
754 755 756
        case schema::Type::Body::discrim##_TYPE: \
          return DynamicValue::Builder(builder.getDataField<type>( \
              field.getOffset() * ELEMENTS, \
757
              bitCast<_::Mask<type>>(dval.get##titleCase##Value())));
758 759 760 761 762 763 764 765 766 767 768 769

        HANDLE_TYPE(BOOL, Bool, bool)
        HANDLE_TYPE(INT8, Int8, int8_t)
        HANDLE_TYPE(INT16, Int16, int16_t)
        HANDLE_TYPE(INT32, Int32, int32_t)
        HANDLE_TYPE(INT64, Int64, int64_t)
        HANDLE_TYPE(UINT8, Uint8, uint8_t)
        HANDLE_TYPE(UINT16, Uint16, uint16_t)
        HANDLE_TYPE(UINT32, Uint32, uint32_t)
        HANDLE_TYPE(UINT64, Uint64, uint64_t)
        HANDLE_TYPE(FLOAT32, Float32, float)
        HANDLE_TYPE(FLOAT64, Float64, double)
Kenton Varda's avatar
Kenton Varda committed
770 771 772

#undef HANDLE_TYPE

773 774 775 776
        case schema::Type::Body::ENUM_TYPE: {
          uint16_t typedDval;
          typedDval = dval.getEnumValue();
          return DynamicValue::Builder(DynamicEnum(
777
              member.getContainingStruct().getDependency(type.getEnumType()).asEnum(),
778 779 780 781 782 783
              builder.getDataField<uint16_t>(field.getOffset() * ELEMENTS, typedDval)));
        }

        case schema::Type::Body::TEXT_TYPE: {
          Text::Reader typedDval = dval.getTextValue();
          return DynamicValue::Builder(
784
              builder.getBlobField<Text>(field.getOffset() * POINTERS,
785
                                         typedDval.begin(), typedDval.size() * BYTES));
786 787 788 789 790
        }

        case schema::Type::Body::DATA_TYPE: {
          Data::Reader typedDval = dval.getDataValue();
          return DynamicValue::Builder(
791
              builder.getBlobField<Data>(field.getOffset() * POINTERS,
792
                                         typedDval.begin(), typedDval.size() * BYTES));
793 794
        }

795 796 797 798 799 800
        case schema::Type::Body::LIST_TYPE: {
          ListSchema listType = ListSchema::of(type.getListType(), member.getContainingStruct());
          if (listType.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
            return DynamicValue::Builder(DynamicList::Builder(listType,
                builder.getStructListField(field.getOffset() * POINTERS,
                                           structSizeFromSchema(listType.getStructElementType()),
801
                                           dval.getListValue<_::UncheckedMessage>())));
802 803 804 805
          } else {
            return DynamicValue::Builder(DynamicList::Builder(listType,
                builder.getListField(field.getOffset() * POINTERS,
                                     elementSizeFor(listType.whichElementType()),
806
                                     dval.getListValue<_::UncheckedMessage>())));
807 808
          }
        }
809 810

        case schema::Type::Body::STRUCT_TYPE: {
811 812
          auto structSchema =
              member.getContainingStruct().getDependency(type.getStructType()).asStruct();
813
          return DynamicValue::Builder(DynamicStruct::Builder(
814
              structSchema,
815
              builder.getStructField(
816
                  field.getOffset() * POINTERS,
817
                  structSizeFromSchema(structSchema),
818
                  dval.getStructValue<_::UncheckedMessage>())));
819 820 821
        }

        case schema::Type::Body::OBJECT_TYPE: {
Kenton Varda's avatar
Kenton Varda committed
822 823
          return DynamicValue::Builder(DynamicObject(
              builder.asReader().getObjectField(
824
                  field.getOffset() * POINTERS,
825
                  dval.getObjectValue<_::UncheckedMessage>())));
826 827 828
        }

        case schema::Type::Body::INTERFACE_TYPE:
829
          KJ_FAIL_ASSERT("Interfaces not yet implemented.");
830 831
          break;
      }
Kenton Varda's avatar
Kenton Varda committed
832

833
      return nullptr;
Kenton Varda's avatar
Kenton Varda committed
834 835 836
    }
  }

837
  KJ_FAIL_ASSERT("switch() missing case.", (uint)member.getProto().getBody().which());
838
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
839
}
Kenton Varda's avatar
Kenton Varda committed
840
DynamicStruct::Builder DynamicStruct::Builder::getObjectImpl(
841
    _::StructBuilder builder, StructSchema::Member field, StructSchema type) {
Kenton Varda's avatar
Kenton Varda committed
842 843
  return DynamicStruct::Builder(type,
      builder.getStructField(
844
          field.getProto().getBody().getFieldMember().getOffset() * POINTERS,
Kenton Varda's avatar
Kenton Varda committed
845 846 847
          structSizeFromSchema(type), nullptr));
}
DynamicList::Builder DynamicStruct::Builder::getObjectImpl(
848
    _::StructBuilder builder, StructSchema::Member field, ListSchema type) {
849 850 851 852 853 854 855 856 857 858 859 860 861
  if (type.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
    return DynamicList::Builder(type,
        builder.getStructListField(
            field.getProto().getBody().getFieldMember().getOffset() * POINTERS,
            structSizeFromSchema(type.getStructElementType()),
            nullptr));
  } else {
    return DynamicList::Builder(type,
        builder.getListField(
            field.getProto().getBody().getFieldMember().getOffset() * POINTERS,
            elementSizeFor(type.whichElementType()),
            nullptr));
  }
Kenton Varda's avatar
Kenton Varda committed
862 863
}
Text::Builder DynamicStruct::Builder::getObjectAsTextImpl(
864
    _::StructBuilder builder, StructSchema::Member field) {
Kenton Varda's avatar
Kenton Varda committed
865
  return builder.getBlobField<Text>(
866
      field.getProto().getBody().getFieldMember().getOffset() * POINTERS, nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
867 868
}
Data::Builder DynamicStruct::Builder::getObjectAsDataImpl(
869
    _::StructBuilder builder, StructSchema::Member field) {
Kenton Varda's avatar
Kenton Varda committed
870
  return builder.getBlobField<Data>(
871
      field.getProto().getBody().getFieldMember().getOffset() * POINTERS, nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
872
}
Kenton Varda's avatar
Kenton Varda committed
873

874
void DynamicStruct::Builder::setImpl(
875
    _::StructBuilder builder, StructSchema::Member member,
876
    const DynamicValue::Reader& value) {
877
  switch (member.getProto().getBody().which()) {
878 879
    case schema::StructNode::Member::Body::UNION_MEMBER: {
      auto src = value.as<DynamicUnion>();
880 881
      KJ_IF_MAYBE(which, src.which()) {
        getImpl(builder, member).as<DynamicUnion>().set(member, src.get());
882
        return;
883
      } else {
884
        KJ_FAIL_REQUIRE(
885 886 887 888 889
            "Trying to copy a union value, but the union's discriminant is not recognized.  It "
            "was probably constructed using a newer version of the schema.") {
          // Just don't copy anything.
          return;
        }
890 891
      }
    }
Kenton Varda's avatar
Kenton Varda committed
892

893
    case schema::StructNode::Member::Body::FIELD_MEMBER: {
894
      auto field = member.getProto().getBody().getFieldMember();
895 896
      auto type = field.getType().getBody();
      auto dval = field.getDefaultValue().getBody();
Kenton Varda's avatar
Kenton Varda committed
897

898 899 900 901
      switch (type.which()) {
        case schema::Type::Body::VOID_TYPE:
          builder.setDataField<Void>(field.getOffset() * ELEMENTS, value.as<Void>());
          return;
Kenton Varda's avatar
Kenton Varda committed
902

903 904 905 906
#define HANDLE_TYPE(discrim, titleCase, type) \
        case schema::Type::Body::discrim##_TYPE: \
          builder.setDataField<type>( \
              field.getOffset() * ELEMENTS, value.as<type>(), \
907
              bitCast<_::Mask<type> >(dval.get##titleCase##Value())); \
908 909 910 911 912 913 914 915 916 917 918 919 920
          return;

        HANDLE_TYPE(BOOL, Bool, bool)
        HANDLE_TYPE(INT8, Int8, int8_t)
        HANDLE_TYPE(INT16, Int16, int16_t)
        HANDLE_TYPE(INT32, Int32, int32_t)
        HANDLE_TYPE(INT64, Int64, int64_t)
        HANDLE_TYPE(UINT8, Uint8, uint8_t)
        HANDLE_TYPE(UINT16, Uint16, uint16_t)
        HANDLE_TYPE(UINT32, Uint32, uint32_t)
        HANDLE_TYPE(UINT64, Uint64, uint64_t)
        HANDLE_TYPE(FLOAT32, Float32, float)
        HANDLE_TYPE(FLOAT64, Float64, double)
Kenton Varda's avatar
Kenton Varda committed
921 922 923

#undef HANDLE_TYPE

924 925 926 927 928 929 930 931
        case schema::Type::Body::ENUM_TYPE: {
          uint16_t rawValue;
          auto enumSchema = member.getContainingStruct().getDependency(type.getEnumType()).asEnum();
          if (value.getType() == DynamicValue::TEXT) {
            // Convert from text.
            rawValue = enumSchema.getEnumerantByName(value.as<Text>()).getOrdinal();
          } else {
            DynamicEnum enumValue = value.as<DynamicEnum>();
932 933
            KJ_REQUIRE(enumValue.getSchema() == enumSchema,
                       "Type mismatch when using DynamicList::Builder::set().") {
934 935 936 937 938 939
              return;
            }
            rawValue = enumValue.getRaw();
          }
          builder.setDataField<uint16_t>(field.getOffset() * ELEMENTS, rawValue,
                                         dval.getEnumValue());
940
          return;
941
        }
942 943

        case schema::Type::Body::TEXT_TYPE:
944
          builder.setBlobField<Text>(field.getOffset() * POINTERS, value.as<Text>());
945 946 947
          return;

        case schema::Type::Body::DATA_TYPE:
948
          builder.setBlobField<Data>(field.getOffset() * POINTERS, value.as<Data>());
949 950 951
          return;

        case schema::Type::Body::LIST_TYPE: {
952
          builder.setListField(field.getOffset() * POINTERS, value.as<DynamicList>().reader);
953 954 955 956
          return;
        }

        case schema::Type::Body::STRUCT_TYPE: {
957
          builder.setStructField(field.getOffset() * POINTERS, value.as<DynamicStruct>().reader);
958 959 960 961
          return;
        }

        case schema::Type::Body::OBJECT_TYPE: {
962
          builder.setObjectField(field.getOffset() * POINTERS, value.as<DynamicObject>().reader);
963 964 965 966
          return;
        }

        case schema::Type::Body::INTERFACE_TYPE:
967
          KJ_FAIL_ASSERT("Interfaces not yet implemented.");
968 969
          return;
      }
Kenton Varda's avatar
Kenton Varda committed
970

971 972 973
      KJ_FAIL_REQUIRE("can't set field of unknown type", (uint)type.which()) {
        return;
      }
Kenton Varda's avatar
Kenton Varda committed
974
    }
975
  }
Kenton Varda's avatar
Kenton Varda committed
976

977
  KJ_FAIL_ASSERT("switch() missing case.", (uint)member.getProto().getBody().which());
978
}
Kenton Varda's avatar
Kenton Varda committed
979

980
DynamicValue::Builder DynamicStruct::Builder::initImpl(
981
    _::StructBuilder builder, StructSchema::Member member, uint size) {
982
  switch (member.getProto().getBody().which()) {
983
    case schema::StructNode::Member::Body::UNION_MEMBER:
984
      KJ_FAIL_REQUIRE(
985
          "Can't init() a union.  get() it first and then init() one of its members.");
986
      break;
Kenton Varda's avatar
Kenton Varda committed
987

988
    case schema::StructNode::Member::Body::FIELD_MEMBER: {
989 990 991 992 993 994 995 996 997 998
      auto type = member.getProto().getBody().getFieldMember().getType().getBody();
      switch (type.which()) {
        case schema::Type::Body::LIST_TYPE:
          return initFieldImpl(builder, member, ListSchema::of(
              type.getListType(), member.getContainingStruct()), size);
        case schema::Type::Body::TEXT_TYPE:
          return initFieldAsTextImpl(builder, member, size);
        case schema::Type::Body::DATA_TYPE:
          return initFieldAsDataImpl(builder, member, size);
        default:
999
          KJ_FAIL_REQUIRE(
Kenton Varda's avatar
Kenton Varda committed
1000
              "init() with size is only valid for list, text, or data fields.", (uint)type.which());
1001 1002 1003
          break;
      }
      break;
1004
    }
Kenton Varda's avatar
Kenton Varda committed
1005 1006
  }

1007 1008
  // Failed.
  return getImpl(builder, member);
Kenton Varda's avatar
Kenton Varda committed
1009 1010
}

1011
DynamicValue::Builder DynamicStruct::Builder::initImpl(
1012
    _::StructBuilder builder, StructSchema::Member member) {
1013
  switch (member.getProto().getBody().which()) {
1014
    case schema::StructNode::Member::Body::UNION_MEMBER:
1015
      KJ_FAIL_REQUIRE(
1016
          "Can't init() a union.  get() it first and then init() one of its members.");
1017
      break;
1018 1019

    case schema::StructNode::Member::Body::FIELD_MEMBER: {
1020
      auto type = member.getProto().getBody().getFieldMember().getType().getBody();
1021
      KJ_REQUIRE(type.which() == schema::Type::Body::STRUCT_TYPE,
1022
              "init() without a size is only valid for struct fields.");
1023 1024
      return initFieldImpl(builder, member,
          member.getContainingStruct().getDependency(type.getStructType()).asStruct());
Kenton Varda's avatar
Kenton Varda committed
1025 1026 1027
    }
  }

1028 1029 1030 1031
  // Failed.
  return getImpl(builder, member);
}
DynamicStruct::Builder DynamicStruct::Builder::initFieldImpl(
1032
    _::StructBuilder builder, StructSchema::Member field, StructSchema type) {
1033 1034
  return DynamicStruct::Builder(
      type, builder.initStructField(
1035
          field.getProto().getBody().getFieldMember().getOffset() * POINTERS,
1036 1037 1038
          structSizeFromSchema(type)));
}
DynamicList::Builder DynamicStruct::Builder::initFieldImpl(
1039
    _::StructBuilder builder, StructSchema::Member field,
1040 1041 1042 1043
    ListSchema type, uint size) {
  if (type.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
    return DynamicList::Builder(
        type, builder.initStructListField(
1044
            field.getProto().getBody().getFieldMember().getOffset() * POINTERS, size * ELEMENTS,
1045 1046 1047 1048
            structSizeFromSchema(type.getStructElementType())));
  } else {
    return DynamicList::Builder(
        type, builder.initListField(
1049
            field.getProto().getBody().getFieldMember().getOffset() * POINTERS,
1050 1051
            elementSizeFor(type.whichElementType()),
            size * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1052
  }
1053 1054
}
Text::Builder DynamicStruct::Builder::initFieldAsTextImpl(
1055
    _::StructBuilder builder, StructSchema::Member field, uint size) {
1056
  return builder.initBlobField<Text>(
1057
      field.getProto().getBody().getFieldMember().getOffset() * POINTERS, size * BYTES);
1058 1059
}
Data::Builder DynamicStruct::Builder::initFieldAsDataImpl(
1060
    _::StructBuilder builder, StructSchema::Member field, uint size) {
1061
  return builder.initBlobField<Data>(
1062
      field.getProto().getBody().getFieldMember().getOffset() * POINTERS, size * BYTES);
Kenton Varda's avatar
Kenton Varda committed
1063 1064 1065 1066
}

// =======================================================================================

1067
DynamicValue::Reader DynamicList::Reader::operator[](uint index) const {
1068
  KJ_REQUIRE(index < size(), "List index out-of-bounds.");
Kenton Varda's avatar
Kenton Varda committed
1069

1070
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1071
#define HANDLE_TYPE(name, discrim, typeName) \
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
    case schema::Type::Body::discrim##_TYPE: \
      return DynamicValue::Reader(reader.getDataElement<typeName>(index * ELEMENTS));

    HANDLE_TYPE(void, VOID, Void)
    HANDLE_TYPE(bool, BOOL, bool)
    HANDLE_TYPE(int8, INT8, int8_t)
    HANDLE_TYPE(int16, INT16, int16_t)
    HANDLE_TYPE(int32, INT32, int32_t)
    HANDLE_TYPE(int64, INT64, int64_t)
    HANDLE_TYPE(uint8, UINT8, uint8_t)
    HANDLE_TYPE(uint16, UINT16, uint16_t)
    HANDLE_TYPE(uint32, UINT32, uint32_t)
    HANDLE_TYPE(uint64, UINT64, uint64_t)
    HANDLE_TYPE(float32, FLOAT32, float)
    HANDLE_TYPE(float64, FLOAT64, double)
Kenton Varda's avatar
Kenton Varda committed
1087 1088
#undef HANDLE_TYPE

1089 1090 1091 1092
    case schema::Type::Body::TEXT_TYPE:
      return DynamicValue::Reader(reader.getBlobElement<Text>(index * ELEMENTS));
    case schema::Type::Body::DATA_TYPE:
      return DynamicValue::Reader(reader.getBlobElement<Data>(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1093

1094 1095 1096 1097 1098 1099
    case schema::Type::Body::LIST_TYPE: {
      auto elementType = schema.getListElementType();
      return DynamicValue::Reader(DynamicList::Reader(
          elementType, reader.getListElement(
              index * ELEMENTS, elementSizeFor(elementType.whichElementType()))));
    }
Kenton Varda's avatar
Kenton Varda committed
1100

1101 1102 1103
    case schema::Type::Body::STRUCT_TYPE:
      return DynamicValue::Reader(DynamicStruct::Reader(
          schema.getStructElementType(), reader.getStructElement(index * ELEMENTS)));
Kenton Varda's avatar
Kenton Varda committed
1104

1105 1106 1107
    case schema::Type::Body::ENUM_TYPE:
      return DynamicValue::Reader(DynamicEnum(
          schema.getEnumElementType(), reader.getDataElement<uint16_t>(index * ELEMENTS)));
Kenton Varda's avatar
Kenton Varda committed
1108

1109
    case schema::Type::Body::OBJECT_TYPE:
Kenton Varda's avatar
Kenton Varda committed
1110
      return DynamicValue::Reader(DynamicObject(
1111
          reader.getObjectElement(index * ELEMENTS)));
Kenton Varda's avatar
Kenton Varda committed
1112

1113
    case schema::Type::Body::INTERFACE_TYPE:
1114 1115 1116
      KJ_FAIL_ASSERT("Interfaces not implemented.") {
        return nullptr;
      }
Kenton Varda's avatar
Kenton Varda committed
1117
  }
1118

1119
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1120 1121
}

1122
DynamicValue::Builder DynamicList::Builder::operator[](uint index) {
1123
  KJ_REQUIRE(index < size(), "List index out-of-bounds.");
Kenton Varda's avatar
Kenton Varda committed
1124

1125
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1126
#define HANDLE_TYPE(name, discrim, typeName) \
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
    case schema::Type::Body::discrim##_TYPE: \
      return DynamicValue::Builder(builder.getDataElement<typeName>(index * ELEMENTS));

    HANDLE_TYPE(void, VOID, Void)
    HANDLE_TYPE(bool, BOOL, bool)
    HANDLE_TYPE(int8, INT8, int8_t)
    HANDLE_TYPE(int16, INT16, int16_t)
    HANDLE_TYPE(int32, INT32, int32_t)
    HANDLE_TYPE(int64, INT64, int64_t)
    HANDLE_TYPE(uint8, UINT8, uint8_t)
    HANDLE_TYPE(uint16, UINT16, uint16_t)
    HANDLE_TYPE(uint32, UINT32, uint32_t)
    HANDLE_TYPE(uint64, UINT64, uint64_t)
    HANDLE_TYPE(float32, FLOAT32, float)
    HANDLE_TYPE(float64, FLOAT64, double)
Kenton Varda's avatar
Kenton Varda committed
1142 1143
#undef HANDLE_TYPE

1144 1145 1146 1147
    case schema::Type::Body::TEXT_TYPE:
      return DynamicValue::Builder(builder.getBlobElement<Text>(index * ELEMENTS));
    case schema::Type::Body::DATA_TYPE:
      return DynamicValue::Builder(builder.getBlobElement<Data>(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1148

1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
    case schema::Type::Body::LIST_TYPE: {
      ListSchema elementType = schema.getListElementType();
      if (elementType.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
        return DynamicValue::Builder(DynamicList::Builder(elementType,
            builder.getStructListElement(
                index * ELEMENTS,
                structSizeFromSchema(elementType.getStructElementType()))));
      } else {
        return DynamicValue::Builder(DynamicList::Builder(elementType,
            builder.getListElement(
                index * ELEMENTS,
                elementSizeFor(elementType.whichElementType()))));
      }
    }
Kenton Varda's avatar
Kenton Varda committed
1163

1164 1165 1166
    case schema::Type::Body::STRUCT_TYPE:
      return DynamicValue::Builder(DynamicStruct::Builder(
          schema.getStructElementType(), builder.getStructElement(index * ELEMENTS)));
Kenton Varda's avatar
Kenton Varda committed
1167

1168 1169 1170
    case schema::Type::Body::ENUM_TYPE:
      return DynamicValue::Builder(DynamicEnum(
          schema.getEnumElementType(), builder.getDataElement<uint16_t>(index * ELEMENTS)));
Kenton Varda's avatar
Kenton Varda committed
1171

1172
    case schema::Type::Body::OBJECT_TYPE:
1173
      KJ_FAIL_ASSERT("List(Object) not supported.");
1174
      return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1175

1176
    case schema::Type::Body::INTERFACE_TYPE:
1177 1178 1179
      KJ_FAIL_ASSERT("Interfaces not implemented.") {
        return nullptr;
      }
Kenton Varda's avatar
Kenton Varda committed
1180
  }
1181

1182
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1183 1184
}

1185
void DynamicList::Builder::set(uint index, const DynamicValue::Reader& value) {
1186
  KJ_REQUIRE(index < size(), "List index out-of-bounds.") {
1187 1188
    return;
  }
Kenton Varda's avatar
Kenton Varda committed
1189

1190
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1191
#define HANDLE_TYPE(name, discrim, typeName) \
1192 1193
    case schema::Type::Body::discrim##_TYPE: \
      builder.setDataElement<typeName>(index * ELEMENTS, value.as<typeName>()); \
1194
      return;
Kenton Varda's avatar
Kenton Varda committed
1195

1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
    HANDLE_TYPE(void, VOID, Void)
    HANDLE_TYPE(bool, BOOL, bool)
    HANDLE_TYPE(int8, INT8, int8_t)
    HANDLE_TYPE(int16, INT16, int16_t)
    HANDLE_TYPE(int32, INT32, int32_t)
    HANDLE_TYPE(int64, INT64, int64_t)
    HANDLE_TYPE(uint8, UINT8, uint8_t)
    HANDLE_TYPE(uint16, UINT16, uint16_t)
    HANDLE_TYPE(uint32, UINT32, uint32_t)
    HANDLE_TYPE(uint64, UINT64, uint64_t)
    HANDLE_TYPE(float32, FLOAT32, float)
    HANDLE_TYPE(float64, FLOAT64, double)
Kenton Varda's avatar
Kenton Varda committed
1208 1209
#undef HANDLE_TYPE

1210 1211
    case schema::Type::Body::TEXT_TYPE:
      builder.setBlobElement<Text>(index * ELEMENTS, value.as<Text>());
1212
      return;
1213 1214
    case schema::Type::Body::DATA_TYPE:
      builder.setBlobElement<Data>(index * ELEMENTS, value.as<Data>());
1215
      return;
Kenton Varda's avatar
Kenton Varda committed
1216

1217
    case schema::Type::Body::LIST_TYPE: {
1218
      builder.setListElement(index * ELEMENTS, value.as<DynamicList>().reader);
1219
      return;
1220
    }
Kenton Varda's avatar
Kenton Varda committed
1221

1222
    case schema::Type::Body::STRUCT_TYPE:
1223 1224 1225
      // Not supported for the same reason List<struct> doesn't support it -- the space for the
      // element is already allocated, and if it's smaller than the input value the copy would
      // have to be lossy.
1226 1227 1228
      KJ_FAIL_ASSERT("DynamicList of structs does not support set().") {
        return;
      }
Kenton Varda's avatar
Kenton Varda committed
1229

1230
    case schema::Type::Body::ENUM_TYPE: {
1231 1232 1233 1234 1235 1236
      uint16_t rawValue;
      if (value.getType() == DynamicValue::TEXT) {
        // Convert from text.
        rawValue = schema.getEnumElementType().getEnumerantByName(value.as<Text>()).getOrdinal();
      } else {
        DynamicEnum enumValue = value.as<DynamicEnum>();
1237 1238
        KJ_REQUIRE(schema.getEnumElementType() == enumValue.getSchema(),
                   "Type mismatch when using DynamicList::Builder::set().") {
1239 1240 1241
          return;
        }
        rawValue = enumValue.getRaw();
1242
      }
1243
      builder.setDataElement<uint16_t>(index * ELEMENTS, rawValue);
1244
      return;
1245
    }
Kenton Varda's avatar
Kenton Varda committed
1246

1247
    case schema::Type::Body::OBJECT_TYPE:
1248 1249 1250
      KJ_FAIL_ASSERT("List(Object) not supported.") {
        return;
      }
Kenton Varda's avatar
Kenton Varda committed
1251

1252
    case schema::Type::Body::INTERFACE_TYPE:
1253 1254 1255
      KJ_FAIL_ASSERT("Interfaces not implemented.") {
        return;
      }
Kenton Varda's avatar
Kenton Varda committed
1256
  }
1257

1258 1259 1260
  KJ_FAIL_REQUIRE("can't set element of unknown type", (uint)schema.whichElementType()) {
    return;
  }
Kenton Varda's avatar
Kenton Varda committed
1261 1262 1263
}

DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) {
1264
  KJ_REQUIRE(index < this->size(), "List index out-of-bounds.");
Kenton Varda's avatar
Kenton Varda committed
1265

1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281
  switch (schema.whichElementType()) {
    case schema::Type::Body::VOID_TYPE:
    case schema::Type::Body::BOOL_TYPE:
    case schema::Type::Body::INT8_TYPE:
    case schema::Type::Body::INT16_TYPE:
    case schema::Type::Body::INT32_TYPE:
    case schema::Type::Body::INT64_TYPE:
    case schema::Type::Body::UINT8_TYPE:
    case schema::Type::Body::UINT16_TYPE:
    case schema::Type::Body::UINT32_TYPE:
    case schema::Type::Body::UINT64_TYPE:
    case schema::Type::Body::FLOAT32_TYPE:
    case schema::Type::Body::FLOAT64_TYPE:
    case schema::Type::Body::ENUM_TYPE:
    case schema::Type::Body::STRUCT_TYPE:
    case schema::Type::Body::INTERFACE_TYPE:
1282
      KJ_FAIL_REQUIRE("Expected a list or blob.");
1283
      return nullptr;
1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303

    case schema::Type::Body::TEXT_TYPE:
      return DynamicValue::Builder(builder.initBlobElement<Text>(index * ELEMENTS, size * BYTES));

    case schema::Type::Body::DATA_TYPE:
      return DynamicValue::Builder(builder.initBlobElement<Data>(index * ELEMENTS, size * BYTES));

    case schema::Type::Body::LIST_TYPE: {
      auto elementType = schema.getListElementType();

      if (elementType.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
        return DynamicValue::Builder(DynamicList::Builder(
            elementType, builder.initStructListElement(
                index * ELEMENTS, size * ELEMENTS,
                structSizeFromSchema(elementType.getStructElementType()))));
      } else {
        return DynamicValue::Builder(DynamicList::Builder(
            elementType, builder.initListElement(
                index * ELEMENTS, elementSizeFor(elementType.whichElementType()),
                size * ELEMENTS)));
Kenton Varda's avatar
Kenton Varda committed
1304 1305 1306
      }
    }

1307
    case schema::Type::Body::OBJECT_TYPE: {
1308
      KJ_FAIL_ASSERT("List(Object) not supported.");
1309
      return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1310 1311
    }
  }
1312

1313
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1314 1315
}

1316
void DynamicList::Builder::copyFrom(std::initializer_list<DynamicValue::Reader> value) {
1317
  KJ_REQUIRE(value.size() == size(), "DynamicList::copyFrom() argument had different size.");
1318 1319 1320 1321 1322 1323
  uint i = 0;
  for (auto element: value) {
    set(i++, element);
  }
}

1324
DynamicList::Reader DynamicList::Builder::asReader() const {
1325
  return DynamicList::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
1326 1327
}

Kenton Varda's avatar
Kenton Varda committed
1328 1329
// =======================================================================================

1330
DynamicValue::Reader DynamicValue::Builder::asReader() const {
Kenton Varda's avatar
Kenton Varda committed
1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
  switch (type) {
    case UNKNOWN: return Reader();
    case VOID: return Reader(voidValue);
    case BOOL: return Reader(boolValue);
    case INT: return Reader(intValue);
    case UINT: return Reader(uintValue);
    case FLOAT: return Reader(floatValue);
    case TEXT: return Reader(textValue.asReader());
    case DATA: return Reader(dataValue.asReader());
    case LIST: return Reader(listValue.asReader());
    case ENUM: return Reader(enumValue);
    case STRUCT: return Reader(structValue.asReader());
    case UNION: return Reader(unionValue.asReader());
1344
    case INTERFACE: KJ_FAIL_ASSERT("Interfaces not implemented."); return Reader();
Kenton Varda's avatar
Kenton Varda committed
1345 1346
    case OBJECT: return Reader(objectValue);
  }
1347
  KJ_FAIL_ASSERT("Missing switch case.");
Kenton Varda's avatar
Kenton Varda committed
1348 1349 1350
  return Reader();
}

1351 1352 1353 1354
namespace {

template <typename T>
T signedToUnsigned(long long value) {
1355
  KJ_REQUIRE(value >= 0 && T(value) == value, "Value out-of-range for requested type.", value) {
1356
    // Use it anyway.
1357
    break;
1358 1359 1360 1361 1362 1363
  }
  return value;
}

template <>
uint64_t signedToUnsigned<uint64_t>(long long value) {
1364
  KJ_REQUIRE(value >= 0, "Value out-of-range for requested type.", value) {
1365
    // Use it anyway.
1366
    break;
1367 1368 1369 1370 1371 1372
  }
  return value;
}

template <typename T>
T unsignedToSigned(unsigned long long value) {
1373 1374
  KJ_REQUIRE(T(value) >= 0 && (unsigned long long)T(value) == value,
             "Value out-of-range for requested type.", value) {
1375
    // Use it anyway.
1376
    break;
1377 1378 1379 1380 1381 1382
  }
  return value;
}

template <>
int64_t unsignedToSigned<int64_t>(unsigned long long value) {
1383
  KJ_REQUIRE(int64_t(value) >= 0, "Value out-of-range for requested type.", value) {
1384
    // Use it anyway.
1385
    break;
1386 1387 1388 1389 1390 1391
  }
  return value;
}

template <typename T, typename U>
T checkRoundTrip(U value) {
1392
  KJ_REQUIRE(T(value) == value, "Value out-of-range for requested type.", value) {
1393
    // Use it anyway.
1394
    break;
1395 1396 1397 1398 1399 1400 1401
  }
  return value;
}

}  // namespace

#define HANDLE_NUMERIC_TYPE(typeName, ifInt, ifUint, ifFloat) \
1402
typeName DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
1403 1404 1405 1406 1407 1408 1409 1410
  switch (reader.type) { \
    case INT: \
      return ifInt<typeName>(reader.intValue); \
    case UINT: \
      return ifUint<typeName>(reader.uintValue); \
    case FLOAT: \
      return ifFloat<typeName>(reader.floatValue); \
    default: \
Kenton Varda's avatar
Kenton Varda committed
1411
      KJ_FAIL_REQUIRE("Value type mismatch.") { \
1412
        return 0; \
1413
      } \
1414 1415
  } \
} \
1416
typeName DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
1417 1418 1419 1420 1421 1422 1423 1424
  switch (builder.type) { \
    case INT: \
      return ifInt<typeName>(builder.intValue); \
    case UINT: \
      return ifUint<typeName>(builder.uintValue); \
    case FLOAT: \
      return ifFloat<typeName>(builder.floatValue); \
    default: \
Kenton Varda's avatar
Kenton Varda committed
1425
      KJ_FAIL_REQUIRE("Value type mismatch.") { \
1426
        return 0; \
1427
      } \
1428 1429 1430 1431 1432 1433
  } \
}

HANDLE_NUMERIC_TYPE(int8_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
HANDLE_NUMERIC_TYPE(int16_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
HANDLE_NUMERIC_TYPE(int32_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
1434
HANDLE_NUMERIC_TYPE(int64_t, kj::implicitCast, unsignedToSigned, checkRoundTrip)
1435 1436 1437
HANDLE_NUMERIC_TYPE(uint8_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
HANDLE_NUMERIC_TYPE(uint16_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
HANDLE_NUMERIC_TYPE(uint32_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
1438 1439 1440
HANDLE_NUMERIC_TYPE(uint64_t, signedToUnsigned, kj::implicitCast, checkRoundTrip)
HANDLE_NUMERIC_TYPE(float, kj::implicitCast, kj::implicitCast, kj::implicitCast)
HANDLE_NUMERIC_TYPE(double, kj::implicitCast, kj::implicitCast, kj::implicitCast)
1441 1442 1443

#undef HANDLE_NUMERIC_TYPE

Kenton Varda's avatar
Kenton Varda committed
1444
#define HANDLE_TYPE(name, discrim, typeName) \
1445
ReaderFor<typeName> DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
Kenton Varda's avatar
Kenton Varda committed
1446
  KJ_REQUIRE(reader.type == discrim, "Value type mismatch.") { \
1447 1448
    return ReaderFor<typeName>(); \
  } \
Kenton Varda's avatar
Kenton Varda committed
1449 1450
  return reader.name##Value; \
} \
1451
BuilderFor<typeName> DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
Kenton Varda's avatar
Kenton Varda committed
1452
  KJ_REQUIRE(builder.type == discrim, "Value type mismatch.") { \
1453 1454
    return BuilderFor<typeName>(); \
  } \
Kenton Varda's avatar
Kenton Varda committed
1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465
  return builder.name##Value; \
}

//HANDLE_TYPE(void, VOID, Void)
HANDLE_TYPE(bool, BOOL, bool)

HANDLE_TYPE(text, TEXT, Text)
HANDLE_TYPE(list, LIST, DynamicList)
HANDLE_TYPE(struct, STRUCT, DynamicStruct)
HANDLE_TYPE(enum, ENUM, DynamicEnum)
HANDLE_TYPE(object, OBJECT, DynamicObject)
1466
HANDLE_TYPE(union, UNION, DynamicUnion)
Kenton Varda's avatar
Kenton Varda committed
1467 1468 1469

#undef HANDLE_TYPE

1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492
Data::Reader DynamicValue::Reader::AsImpl<Data>::apply(const Reader& reader) {
  if (reader.type == TEXT) {
    // Coerce text to data.
    return Data::Reader(reinterpret_cast<const byte*>(reader.textValue.begin()),
                        reader.textValue.size());
  }
  KJ_REQUIRE(reader.type == DATA, "Value type mismatch.") {
    return Data::Reader();
  }
  return reader.dataValue;
}
Data::Builder DynamicValue::Builder::AsImpl<Data>::apply(Builder& builder) {
  if (builder.type == TEXT) {
    // Coerce text to data.
    return Data::Builder(reinterpret_cast<byte*>(builder.textValue.begin()),
                         builder.textValue.size());
  }
  KJ_REQUIRE(builder.type == DATA, "Value type mismatch.") {
    return BuilderFor<Data>();
  }
  return builder.dataValue;
}

Kenton Varda's avatar
Kenton Varda committed
1493
// As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
1494
Void DynamicValue::Reader::AsImpl<Void>::apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1495
  KJ_REQUIRE(reader.type == VOID, "Value type mismatch.") {
Kenton Varda's avatar
Kenton Varda committed
1496 1497 1498 1499
    return Void();
  }
  return reader.voidValue;
}
1500
Void DynamicValue::Builder::AsImpl<Void>::apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1501
  KJ_REQUIRE(builder.type == VOID, "Value type mismatch.") {
Kenton Varda's avatar
Kenton Varda committed
1502 1503 1504 1505 1506
    return Void();
  }
  return builder.voidValue;
}

Kenton Varda's avatar
Kenton Varda committed
1507 1508 1509
// =======================================================================================

template <>
1510 1511
DynamicStruct::Reader MessageReader::getRoot<DynamicStruct>(StructSchema schema) {
  return DynamicStruct::Reader(schema, getRootInternal());
Kenton Varda's avatar
Kenton Varda committed
1512 1513 1514
}

template <>
1515 1516
DynamicStruct::Builder MessageBuilder::initRoot<DynamicStruct>(StructSchema schema) {
  return DynamicStruct::Builder(schema, initRoot(structSizeFromSchema(schema)));
Kenton Varda's avatar
Kenton Varda committed
1517 1518 1519
}

template <>
1520 1521
DynamicStruct::Builder MessageBuilder::getRoot<DynamicStruct>(StructSchema schema) {
  return DynamicStruct::Builder(schema, getRoot(structSizeFromSchema(schema)));
Kenton Varda's avatar
Kenton Varda committed
1522 1523
}

1524
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
1525

1526
DynamicStruct::Reader PointerHelpers<DynamicStruct, Kind::UNKNOWN>::getDynamic(
1527
    StructReader reader, WirePointerCount index, StructSchema schema) {
1528
  return DynamicStruct::Reader(schema, reader.getStructField(index, nullptr));
Kenton Varda's avatar
Kenton Varda committed
1529
}
1530
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::UNKNOWN>::getDynamic(
1531
    StructBuilder builder, WirePointerCount index, StructSchema schema) {
1532 1533
  return DynamicStruct::Builder(schema, builder.getStructField(
      index, structSizeFromSchema(schema), nullptr));
Kenton Varda's avatar
Kenton Varda committed
1534 1535
}
void PointerHelpers<DynamicStruct, Kind::UNKNOWN>::set(
1536
    StructBuilder builder, WirePointerCount index, const DynamicStruct::Reader& value) {
1537
  builder.setStructField(index, value.reader);
Kenton Varda's avatar
Kenton Varda committed
1538 1539
}
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::UNKNOWN>::init(
1540
    StructBuilder builder, WirePointerCount index, StructSchema schema) {
1541 1542
  return DynamicStruct::Builder(schema,
      builder.initStructField(index, structSizeFromSchema(schema)));
Kenton Varda's avatar
Kenton Varda committed
1543 1544
}

1545
DynamicList::Reader PointerHelpers<DynamicList, Kind::UNKNOWN>::getDynamic(
1546
    StructReader reader, WirePointerCount index, ListSchema schema) {
1547 1548
  return DynamicList::Reader(schema,
      reader.getListField(index, elementSizeFor(schema.whichElementType()), nullptr));
Kenton Varda's avatar
Kenton Varda committed
1549
}
1550
DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::getDynamic(
1551
    StructBuilder builder, WirePointerCount index, ListSchema schema) {
1552 1553 1554 1555 1556 1557 1558 1559 1560
  if (schema.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
    return DynamicList::Builder(schema,
        builder.getStructListField(index,
            structSizeFromSchema(schema.getStructElementType()),
            nullptr));
  } else {
    return DynamicList::Builder(schema,
        builder.getListField(index, elementSizeFor(schema.whichElementType()), nullptr));
  }
Kenton Varda's avatar
Kenton Varda committed
1561 1562
}
void PointerHelpers<DynamicList, Kind::UNKNOWN>::set(
1563
    StructBuilder builder, WirePointerCount index, const DynamicList::Reader& value) {
1564
  builder.setListField(index, value.reader);
Kenton Varda's avatar
Kenton Varda committed
1565 1566
}
DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::init(
1567
    StructBuilder builder, WirePointerCount index, ListSchema schema, uint size) {
1568 1569
  if (schema.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
    return DynamicList::Builder(schema,
Kenton Varda's avatar
Kenton Varda committed
1570
        builder.initStructListField(index, size * ELEMENTS,
1571
            structSizeFromSchema(schema.getStructElementType())));
Kenton Varda's avatar
Kenton Varda committed
1572
  } else {
1573 1574
    return DynamicList::Builder(schema,
        builder.initListField(index, elementSizeFor(schema.whichElementType()), size * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1575 1576 1577
  }
}

1578
}  // namespace _ (private)
Kenton Varda's avatar
Kenton Varda committed
1579

1580 1581
// -------------------------------------------------------------------

1582
Orphan<DynamicStruct> Orphanage::newOrphan(StructSchema schema) const {
1583 1584 1585 1586
  return Orphan<DynamicStruct>(
      schema, _::OrphanBuilder::initStruct(arena, structSizeFromSchema(schema)));
}

1587
Orphan<DynamicList> Orphanage::newOrphan(ListSchema schema, uint size) const {
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600
  if (schema.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
    return Orphan<DynamicList>(schema, _::OrphanBuilder::initStructList(
        arena, size * ELEMENTS, structSizeFromSchema(schema.getStructElementType())));
  } else {
    return Orphan<DynamicList>(schema, _::OrphanBuilder::initList(
        arena, size * ELEMENTS, elementSizeFor(schema.whichElementType())));
  }
}

DynamicStruct::Builder Orphan<DynamicStruct>::get() {
  return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema)));
}

1601 1602 1603 1604
DynamicStruct::Reader Orphan<DynamicStruct>::getReader() const {
  return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
}

1605 1606 1607 1608 1609 1610 1611 1612 1613 1614
DynamicList::Builder Orphan<DynamicList>::get() {
  if (schema.whichElementType() == schema::Type::Body::STRUCT_TYPE) {
    return DynamicList::Builder(
        schema, builder.asStructList(structSizeFromSchema(schema.getStructElementType())));
  } else {
    return DynamicList::Builder(
        schema, builder.asList(elementSizeFor(schema.whichElementType())));
  }
}

1615 1616 1617 1618 1619
DynamicList::Reader Orphan<DynamicList>::getReader() const {
  return DynamicList::Reader(
      schema, builder.asListReader(elementSizeFor(schema.whichElementType())));
}

1620
}  // namespace capnp