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

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

25
namespace capnp {
Kenton Varda's avatar
Kenton Varda committed
26 27 28

namespace {

29 30 31 32
bool hasDiscriminantValue(const schema::Field::Reader& reader) {
  return reader.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT;
}

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

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
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
template <>
inline float bitCast<float, uint32_t>(uint32_t value) KJ_UNUSED;
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) KJ_UNUSED;
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
57 58 59 60 61 62 63 64 65 66 67 68 69
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;
}

70
ElementSize elementSizeFor(schema::Type::Which elementType) {
Kenton Varda's avatar
Kenton Varda committed
71
  switch (elementType) {
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
    case schema::Type::VOID: return ElementSize::VOID;
    case schema::Type::BOOL: return ElementSize::BIT;
    case schema::Type::INT8: return ElementSize::BYTE;
    case schema::Type::INT16: return ElementSize::TWO_BYTES;
    case schema::Type::INT32: return ElementSize::FOUR_BYTES;
    case schema::Type::INT64: return ElementSize::EIGHT_BYTES;
    case schema::Type::UINT8: return ElementSize::BYTE;
    case schema::Type::UINT16: return ElementSize::TWO_BYTES;
    case schema::Type::UINT32: return ElementSize::FOUR_BYTES;
    case schema::Type::UINT64: return ElementSize::EIGHT_BYTES;
    case schema::Type::FLOAT32: return ElementSize::FOUR_BYTES;
    case schema::Type::FLOAT64: return ElementSize::EIGHT_BYTES;

    case schema::Type::TEXT: return ElementSize::POINTER;
    case schema::Type::DATA: return ElementSize::POINTER;
    case schema::Type::LIST: return ElementSize::POINTER;
    case schema::Type::ENUM: return ElementSize::TWO_BYTES;
    case schema::Type::STRUCT: return ElementSize::INLINE_COMPOSITE;
    case schema::Type::INTERFACE: return ElementSize::POINTER;
91
    case schema::Type::ANY_POINTER: KJ_FAIL_ASSERT("List(AnyPointer) not supported."); break;
Kenton Varda's avatar
Kenton Varda committed
92
  }
93 94

  // Unknown type.  Treat it as zero-size.
95
  return ElementSize::VOID;
Kenton Varda's avatar
Kenton Varda committed
96 97
}

98
inline _::StructSize structSizeFromSchema(StructSchema schema) {
Kenton Varda's avatar
Kenton Varda committed
99
  auto node = schema.getProto().getStruct();
100
  return _::StructSize(
101
      node.getDataWordCount() * WORDS,
102
      node.getPointerCount() * POINTERS);
Kenton Varda's avatar
Kenton Varda committed
103 104
}

Kenton Varda's avatar
Kenton Varda committed
105 106 107 108
}  // namespace

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

109
kj::Maybe<EnumSchema::Enumerant> DynamicEnum::getEnumerant() const {
110
  auto enumerants = schema.getEnumerants();
Kenton Varda's avatar
Kenton Varda committed
111 112 113 114 115 116 117
  if (value < enumerants.size()) {
    return enumerants[value];
  } else {
    return nullptr;
  }
}

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

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

Kenton Varda's avatar
Kenton Varda committed
129 130
bool DynamicStruct::Reader::isSetInUnion(StructSchema::Field field) const {
  auto proto = field.getProto();
131
  if (hasDiscriminantValue(proto)) {
Kenton Varda's avatar
Kenton Varda committed
132 133 134
    uint16_t discrim = reader.getDataField<uint16_t>(
        schema.getProto().getStruct().getDiscriminantOffset() * ELEMENTS);
    return discrim == proto.getDiscriminantValue();
135
  } else {
Kenton Varda's avatar
Kenton Varda committed
136
    return true;
137
  }
Kenton Varda's avatar
Kenton Varda committed
138 139
}

Kenton Varda's avatar
Kenton Varda committed
140 141 142 143
void DynamicStruct::Reader::verifySetInUnion(StructSchema::Field field) const {
  KJ_REQUIRE(isSetInUnion(field),
      "Tried to get() a union member which is not currently initialized.",
      field.getProto().getName(), schema.getProto().getDisplayName());
Kenton Varda's avatar
Kenton Varda committed
144 145
}

Kenton Varda's avatar
Kenton Varda committed
146 147
bool DynamicStruct::Builder::isSetInUnion(StructSchema::Field field) {
  auto proto = field.getProto();
148
  if (hasDiscriminantValue(proto)) {
Kenton Varda's avatar
Kenton Varda committed
149 150 151
    uint16_t discrim = builder.getDataField<uint16_t>(
        schema.getProto().getStruct().getDiscriminantOffset() * ELEMENTS);
    return discrim == proto.getDiscriminantValue();
152
  } else {
Kenton Varda's avatar
Kenton Varda committed
153
    return true;
154
  }
Kenton Varda's avatar
Kenton Varda committed
155 156
}

Kenton Varda's avatar
Kenton Varda committed
157 158 159 160
void DynamicStruct::Builder::verifySetInUnion(StructSchema::Field field) {
  KJ_REQUIRE(isSetInUnion(field),
      "Tried to get() a union member which is not currently initialized.",
      field.getProto().getName(), schema.getProto().getDisplayName());
161 162
}

Kenton Varda's avatar
Kenton Varda committed
163
void DynamicStruct::Builder::setInUnion(StructSchema::Field field) {
164
  // If a union member, set the discriminant to match.
Kenton Varda's avatar
Kenton Varda committed
165
  auto proto = field.getProto();
166
  if (hasDiscriminantValue(proto)) {
167
    builder.setDataField<uint16_t>(
Kenton Varda's avatar
Kenton Varda committed
168 169
        schema.getProto().getStruct().getDiscriminantOffset() * ELEMENTS,
        proto.getDiscriminantValue());
Kenton Varda's avatar
Kenton Varda committed
170
  }
171
}
Kenton Varda's avatar
Kenton Varda committed
172

Kenton Varda's avatar
Kenton Varda committed
173 174 175
DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const {
  KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
  verifySetInUnion(field);
Kenton Varda's avatar
Kenton Varda committed
176

177
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
178 179
  auto proto = field.getProto();
  switch (proto.which()) {
180 181
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
182 183 184 185 186

      // Note that the default value might be "anyPointer" even if the type is some poniter type
      // *other than* anyPointer. This happens with generics -- the field is actually a generic
      // parameter that has been bound, but the default value was of course compiled without any
      // binding available.
187
      auto dval = slot.getDefaultValue();
188 189

      switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
190
        case schema::Type::VOID:
191
          return reader.getDataField<Void>(slot.getOffset() * ELEMENTS);
Kenton Varda's avatar
Kenton Varda committed
192 193

#define HANDLE_TYPE(discrim, titleCase, type) \
Kenton Varda's avatar
Kenton Varda committed
194
        case schema::Type::discrim: \
195
          return reader.getDataField<type>( \
196
              slot.getOffset() * ELEMENTS, \
197
              bitCast<_::Mask<type>>(dval.get##titleCase()));
198 199 200 201 202 203 204 205 206 207 208 209

        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
210 211 212

#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
213
        case schema::Type::ENUM: {
214 215
          uint16_t typedDval = dval.getEnum();
          return DynamicEnum(type.asEnum(),
216
              reader.getDataField<uint16_t>(slot.getOffset() * ELEMENTS, typedDval));
217 218
        }

Kenton Varda's avatar
Kenton Varda committed
219
        case schema::Type::TEXT: {
220
          Text::Reader typedDval = dval.isAnyPointer() ? Text::Reader() : dval.getText();
221 222
          return reader.getPointerField(slot.getOffset() * POINTERS)
                       .getBlob<Text>(typedDval.begin(), typedDval.size() * BYTES);
223 224
        }

Kenton Varda's avatar
Kenton Varda committed
225
        case schema::Type::DATA: {
226
          Data::Reader typedDval = dval.isAnyPointer() ? Data::Reader() : dval.getData();
227 228
          return reader.getPointerField(slot.getOffset() * POINTERS)
                       .getBlob<Data>(typedDval.begin(), typedDval.size() * BYTES);
229 230
        }

Kenton Varda's avatar
Kenton Varda committed
231
        case schema::Type::LIST: {
232 233
          auto elementType = type.asList().getElementType();
          return DynamicList::Reader(type.asList(),
234
              reader.getPointerField(slot.getOffset() * POINTERS)
235 236
                    .getList(elementSizeFor(elementType.which()), dval.isAnyPointer() ? nullptr :
                        dval.getList().getAs<_::UncheckedMessage>()));
237 238
        }

239
        case schema::Type::STRUCT:
240
          return DynamicStruct::Reader(type.asStruct(),
241
              reader.getPointerField(slot.getOffset() * POINTERS)
242 243
                    .getStruct(dval.isAnyPointer() ? nullptr :
                        dval.getStruct().getAs<_::UncheckedMessage>()));
244

245 246
        case schema::Type::ANY_POINTER:
          return AnyPointer::Reader(reader.getPointerField(slot.getOffset() * POINTERS));
247

Kenton Varda's avatar
Kenton Varda committed
248
        case schema::Type::INTERFACE:
249
          return DynamicCapability::Client(type.asInterface(),
250
              reader.getPointerField(slot.getOffset() * POINTERS).getCapability());
251
      }
Kenton Varda's avatar
Kenton Varda committed
252

Kenton Varda's avatar
Kenton Varda committed
253
      KJ_UNREACHABLE;
Kenton Varda's avatar
Kenton Varda committed
254
    }
Kenton Varda's avatar
Kenton Varda committed
255

Kenton Varda's avatar
Kenton Varda committed
256
    case schema::Field::GROUP:
257
      return DynamicStruct::Reader(type.asStruct(), reader);
Kenton Varda's avatar
Kenton Varda committed
258 259
  }

Kenton Varda's avatar
Kenton Varda committed
260
  KJ_UNREACHABLE;
Kenton Varda's avatar
Kenton Varda committed
261 262
}

Kenton Varda's avatar
Kenton Varda committed
263 264 265
DynamicValue::Builder DynamicStruct::Builder::get(StructSchema::Field field) {
  KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
  verifySetInUnion(field);
Kenton Varda's avatar
Kenton Varda committed
266

Kenton Varda's avatar
Kenton Varda committed
267
  auto proto = field.getProto();
268
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
269
  switch (proto.which()) {
270 271
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
272 273 274 275 276

      // Note that the default value might be "anyPointer" even if the type is some poniter type
      // *other than* anyPointer. This happens with generics -- the field is actually a generic
      // parameter that has been bound, but the default value was of course compiled without any
      // binding available.
277
      auto dval = slot.getDefaultValue();
278 279

      switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
280
        case schema::Type::VOID:
281
          return builder.getDataField<Void>(slot.getOffset() * ELEMENTS);
Kenton Varda's avatar
Kenton Varda committed
282 283

#define HANDLE_TYPE(discrim, titleCase, type) \
Kenton Varda's avatar
Kenton Varda committed
284
        case schema::Type::discrim: \
Kenton Varda's avatar
Kenton Varda committed
285
          return builder.getDataField<type>( \
286
              slot.getOffset() * ELEMENTS, \
Kenton Varda's avatar
Kenton Varda committed
287
              bitCast<_::Mask<type>>(dval.get##titleCase()));
288 289 290 291 292 293 294 295 296 297 298 299

        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
300 301 302

#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
303
        case schema::Type::ENUM: {
304 305
          uint16_t typedDval = dval.getEnum();
          return DynamicEnum(type.asEnum(),
306
              builder.getDataField<uint16_t>(slot.getOffset() * ELEMENTS, typedDval));
307 308
        }

Kenton Varda's avatar
Kenton Varda committed
309
        case schema::Type::TEXT: {
310
          Text::Reader typedDval = dval.isAnyPointer() ? Text::Reader() : dval.getText();
311 312
          return builder.getPointerField(slot.getOffset() * POINTERS)
                        .getBlob<Text>(typedDval.begin(), typedDval.size() * BYTES);
313 314
        }

Kenton Varda's avatar
Kenton Varda committed
315
        case schema::Type::DATA: {
316
          Data::Reader typedDval = dval.isAnyPointer() ? Data::Reader() : dval.getData();
317 318
          return builder.getPointerField(slot.getOffset() * POINTERS)
                        .getBlob<Data>(typedDval.begin(), typedDval.size() * BYTES);
319 320
        }

Kenton Varda's avatar
Kenton Varda committed
321
        case schema::Type::LIST: {
322
          ListSchema listType = type.asList();
Kenton Varda's avatar
Kenton Varda committed
323
          if (listType.whichElementType() == schema::Type::STRUCT) {
Kenton Varda's avatar
Kenton Varda committed
324
            return DynamicList::Builder(listType,
325 326
                builder.getPointerField(slot.getOffset() * POINTERS)
                       .getStructList(structSizeFromSchema(listType.getStructElementType()),
327 328
                                      dval.isAnyPointer() ? nullptr :
                                          dval.getList().getAs<_::UncheckedMessage>()));
329
          } else {
Kenton Varda's avatar
Kenton Varda committed
330
            return DynamicList::Builder(listType,
331 332
                builder.getPointerField(slot.getOffset() * POINTERS)
                       .getList(elementSizeFor(listType.whichElementType()),
333 334
                                dval.isAnyPointer() ? nullptr :
                                    dval.getList().getAs<_::UncheckedMessage>()));
335 336
          }
        }
337

Kenton Varda's avatar
Kenton Varda committed
338
        case schema::Type::STRUCT: {
339
          auto structSchema = type.asStruct();
Kenton Varda's avatar
Kenton Varda committed
340
          return DynamicStruct::Builder(structSchema,
341 342
              builder.getPointerField(slot.getOffset() * POINTERS)
                     .getStruct(structSizeFromSchema(structSchema),
343 344
                                dval.isAnyPointer() ? nullptr :
                                    dval.getStruct().getAs<_::UncheckedMessage>()));
345 346
        }

347 348
        case schema::Type::ANY_POINTER:
          return AnyPointer::Builder(builder.getPointerField(slot.getOffset() * POINTERS));
349

Kenton Varda's avatar
Kenton Varda committed
350
        case schema::Type::INTERFACE:
351
          return DynamicCapability::Client(type.asInterface(),
352
              builder.getPointerField(slot.getOffset() * POINTERS).getCapability());
353
      }
Kenton Varda's avatar
Kenton Varda committed
354

Kenton Varda's avatar
Kenton Varda committed
355
      KJ_UNREACHABLE;
Kenton Varda's avatar
Kenton Varda committed
356
    }
Kenton Varda's avatar
Kenton Varda committed
357

Kenton Varda's avatar
Kenton Varda committed
358
    case schema::Field::GROUP:
359
      return DynamicStruct::Builder(type.asStruct(), builder);
Kenton Varda's avatar
Kenton Varda committed
360 361
  }

Kenton Varda's avatar
Kenton Varda committed
362
  KJ_UNREACHABLE;
Kenton Varda's avatar
Kenton Varda committed
363
}
Kenton Varda's avatar
Kenton Varda committed
364

365
DynamicValue::Pipeline DynamicStruct::Pipeline::get(StructSchema::Field field) {
366 367 368
  KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");

  auto proto = field.getProto();
369
  KJ_REQUIRE(!hasDiscriminantValue(proto), "Can't pipeline on union members.");
370

371 372
  auto type = field.getType();

373 374 375 376 377 378
  switch (proto.which()) {
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();

      switch (type.which()) {
        case schema::Type::STRUCT:
379
          return DynamicStruct::Pipeline(type.asStruct(),
380 381 382
              typeless.getPointerField(slot.getOffset()));

        case schema::Type::INTERFACE:
383
          return DynamicCapability::Client(type.asInterface(),
384 385 386 387 388 389 390 391 392 393
              typeless.getPointerField(slot.getOffset()).asCap());

        default:
          KJ_FAIL_REQUIRE("Can only pipeline on struct and interface fields.");
      }

      KJ_UNREACHABLE;
    }

    case schema::Field::GROUP:
394
      return DynamicStruct::Pipeline(type.asStruct(), typeless.noop());
395 396 397 398 399
  }

  KJ_UNREACHABLE;
}

Kenton Varda's avatar
Kenton Varda committed
400 401 402 403
bool DynamicStruct::Reader::has(StructSchema::Field field) const {
  KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");

  auto proto = field.getProto();
404
  if (hasDiscriminantValue(proto)) {
Kenton Varda's avatar
Kenton Varda committed
405 406 407 408 409 410
    uint16_t discrim = reader.getDataField<uint16_t>(
        schema.getProto().getStruct().getDiscriminantOffset() * ELEMENTS);
    if (discrim != proto.getDiscriminantValue()) {
      // Field is not active in the union.
      return false;
    }
411
  }
Kenton Varda's avatar
Kenton Varda committed
412 413

  switch (proto.which()) {
414
    case schema::Field::SLOT:
Kenton Varda's avatar
Kenton Varda committed
415 416 417
      // Continue to below.
      break;

418 419
    case schema::Field::GROUP:
      return true;
Kenton Varda's avatar
Kenton Varda committed
420 421
  }

422
  auto slot = proto.getSlot();
423
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
424 425

  switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
426
    case schema::Type::VOID:
427 428 429 430 431 432 433 434 435 436 437 438 439 440
    case schema::Type::BOOL:
    case schema::Type::INT8:
    case schema::Type::INT16:
    case schema::Type::INT32:
    case schema::Type::INT64:
    case schema::Type::UINT8:
    case schema::Type::UINT16:
    case schema::Type::UINT32:
    case schema::Type::UINT64:
    case schema::Type::FLOAT32:
    case schema::Type::FLOAT64:
    case schema::Type::ENUM:
      // Primitive types are always present.
      return true;
Kenton Varda's avatar
Kenton Varda committed
441

Kenton Varda's avatar
Kenton Varda committed
442 443 444 445
    case schema::Type::TEXT:
    case schema::Type::DATA:
    case schema::Type::LIST:
    case schema::Type::STRUCT:
446
    case schema::Type::ANY_POINTER:
Kenton Varda's avatar
Kenton Varda committed
447
    case schema::Type::INTERFACE:
448
      return !reader.getPointerField(slot.getOffset() * POINTERS).isNull();
Kenton Varda's avatar
Kenton Varda committed
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
  }

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

kj::Maybe<StructSchema::Field> DynamicStruct::Reader::which() const {
  auto structProto = schema.getProto().getStruct();
  if (structProto.getDiscriminantCount() == 0) {
    return nullptr;
  }

  uint16_t discrim = reader.getDataField<uint16_t>(structProto.getDiscriminantOffset() * ELEMENTS);
  return schema.getFieldByDiscriminant(discrim);
}

kj::Maybe<StructSchema::Field> DynamicStruct::Builder::which() {
  auto structProto = schema.getProto().getStruct();
  if (structProto.getDiscriminantCount() == 0) {
    return nullptr;
  }

  uint16_t discrim = builder.getDataField<uint16_t>(structProto.getDiscriminantOffset() * ELEMENTS);
  return schema.getFieldByDiscriminant(discrim);
}

void DynamicStruct::Builder::set(StructSchema::Field field, const DynamicValue::Reader& value) {
  KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
  setInUnion(field);

  auto proto = field.getProto();
480
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
481
  switch (proto.which()) {
482 483 484
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
      auto dval = slot.getDefaultValue();
Kenton Varda's avatar
Kenton Varda committed
485

486
      switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
487
        case schema::Type::VOID:
488
          builder.setDataField<Void>(slot.getOffset() * ELEMENTS, value.as<Void>());
489
          return;
Kenton Varda's avatar
Kenton Varda committed
490

491
#define HANDLE_TYPE(discrim, titleCase, type) \
Kenton Varda's avatar
Kenton Varda committed
492
        case schema::Type::discrim: \
493
          builder.setDataField<type>( \
494
              slot.getOffset() * ELEMENTS, value.as<type>(), \
Kenton Varda's avatar
Kenton Varda committed
495
              bitCast<_::Mask<type> >(dval.get##titleCase())); \
496 497 498 499 500 501 502 503 504 505 506 507 508
          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
509 510 511

#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
512
        case schema::Type::ENUM: {
513
          uint16_t rawValue;
514
          auto enumSchema = type.asEnum();
515 516 517
          if (value.getType() == DynamicValue::TEXT) {
            // Convert from text.
            rawValue = enumSchema.getEnumerantByName(value.as<Text>()).getOrdinal();
518 519
          } else if (value.getType() == DynamicValue::INT ||
                     value.getType() == DynamicValue::UINT) {
520
            rawValue = value.as<uint16_t>();
Kenton Varda's avatar
Kenton Varda committed
521
          } else {
522
            DynamicEnum enumValue = value.as<DynamicEnum>();
523
            KJ_REQUIRE(enumValue.getSchema() == enumSchema, "Value type mismatch.") {
524 525 526 527
              return;
            }
            rawValue = enumValue.getRaw();
          }
528
          builder.setDataField<uint16_t>(slot.getOffset() * ELEMENTS, rawValue,
Kenton Varda's avatar
Kenton Varda committed
529
                                         dval.getEnum());
530
          return;
531
        }
532

Kenton Varda's avatar
Kenton Varda committed
533
        case schema::Type::TEXT:
534
          builder.getPointerField(slot.getOffset() * POINTERS).setBlob<Text>(value.as<Text>());
535 536
          return;

Kenton Varda's avatar
Kenton Varda committed
537
        case schema::Type::DATA:
538
          builder.getPointerField(slot.getOffset() * POINTERS).setBlob<Data>(value.as<Data>());
539 540
          return;

541
        case schema::Type::LIST: {
542
          ListSchema listType = type.asList();
543 544 545 546
          auto listValue = value.as<DynamicList>();
          KJ_REQUIRE(listValue.getSchema() == listType, "Value type mismatch.") {
            return;
          }
547
          builder.getPointerField(slot.getOffset() * POINTERS).setList(listValue.reader);
548
          return;
549
        }
550

551
        case schema::Type::STRUCT: {
552
          auto structType = type.asStruct();
553 554 555 556
          auto structValue = value.as<DynamicStruct>();
          KJ_REQUIRE(structValue.getSchema() == structType, "Value type mismatch.") {
            return;
          }
557
          builder.getPointerField(slot.getOffset() * POINTERS).setStruct(structValue.reader);
558
          return;
559
        }
560

561 562 563
        case schema::Type::ANY_POINTER:
          AnyPointer::Builder(builder.getPointerField(slot.getOffset() * POINTERS))
                 .set(value.as<AnyPointer>());
564 565
          return;

Kenton Varda's avatar
Kenton Varda committed
566
        case schema::Type::INTERFACE:
567
          auto interfaceType = type.asInterface();
568 569 570 571 572 573
          auto capability = value.as<DynamicCapability>();
          KJ_REQUIRE(capability.getSchema().extends(interfaceType), "Value type mismatch.") {
            return;
          }
          builder.getPointerField(slot.getOffset() * POINTERS).setCapability(
              kj::mv(capability.hook));
574 575
          return;
      }
Kenton Varda's avatar
Kenton Varda committed
576

Kenton Varda's avatar
Kenton Varda committed
577 578 579
      KJ_UNREACHABLE;
    }

Kenton Varda's avatar
Kenton Varda committed
580
    case schema::Field::GROUP: {
Kenton Varda's avatar
Kenton Varda committed
581 582 583 584 585 586 587 588 589 590 591
      auto src = value.as<DynamicStruct>();
      auto dst = init(field).as<DynamicStruct>();

      KJ_IF_MAYBE(unionField, src.which()) {
        dst.set(*unionField, src.get(*unionField));
      }

      for (auto field: src.schema.getNonUnionFields()) {
        if (src.has(field)) {
          dst.set(field, src.get(field));
        }
592
      }
Kenton Varda's avatar
Kenton Varda committed
593
    }
594
  }
Kenton Varda's avatar
Kenton Varda committed
595

Kenton Varda's avatar
Kenton Varda committed
596
  KJ_UNREACHABLE;
597
}
Kenton Varda's avatar
Kenton Varda committed
598

Kenton Varda's avatar
Kenton Varda committed
599 600 601 602 603
DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Field field) {
  KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
  setInUnion(field);

  auto proto = field.getProto();
604
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
605 606

  switch (proto.which()) {
607 608
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
609 610
      switch (type.which()) {
        case schema::Type::STRUCT: {
611
          auto subSchema = type.asStruct();
612 613 614 615
          return DynamicStruct::Builder(subSchema,
              builder.getPointerField(slot.getOffset() * POINTERS)
                     .initStruct(structSizeFromSchema(subSchema)));
        }
616
        case schema::Type::ANY_POINTER: {
617 618
          auto pointer = builder.getPointerField(slot.getOffset() * POINTERS);
          pointer.clear();
619
          return AnyPointer::Builder(pointer);
620 621 622 623
        }
        default:
          KJ_FAIL_REQUIRE("init() without a size is only valid for struct and object fields.");
      }
Kenton Varda's avatar
Kenton Varda committed
624 625
    }

Kenton Varda's avatar
Kenton Varda committed
626
    case schema::Field::GROUP: {
Kenton Varda's avatar
Kenton Varda committed
627
      clear(field);
628
      return DynamicStruct::Builder(type.asStruct(), builder);
Kenton Varda's avatar
Kenton Varda committed
629 630 631 632 633
    }
  }

  KJ_UNREACHABLE;
}
Kenton Varda's avatar
Kenton Varda committed
634

Kenton Varda's avatar
Kenton Varda committed
635 636 637 638 639
DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Field field, uint size) {
  KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
  setInUnion(field);

  auto proto = field.getProto();
640
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
641 642

  switch (proto.which()) {
643 644
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
645
      switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
646
        case schema::Type::LIST: {
647
          auto listType = type.asList();
Kenton Varda's avatar
Kenton Varda committed
648
          if (listType.whichElementType() == schema::Type::STRUCT) {
Kenton Varda's avatar
Kenton Varda committed
649
            return DynamicList::Builder(listType,
650 651 652
                builder.getPointerField(slot.getOffset() * POINTERS)
                       .initStructList(size * ELEMENTS,
                                       structSizeFromSchema(listType.getStructElementType())));
Kenton Varda's avatar
Kenton Varda committed
653 654
          } else {
            return DynamicList::Builder(listType,
655 656
                builder.getPointerField(slot.getOffset() * POINTERS)
                       .initList(elementSizeFor(listType.whichElementType()), size * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
657 658
          }
        }
Kenton Varda's avatar
Kenton Varda committed
659
        case schema::Type::TEXT:
660 661
          return builder.getPointerField(slot.getOffset() * POINTERS)
                        .initBlob<Text>(size * BYTES);
Kenton Varda's avatar
Kenton Varda committed
662
        case schema::Type::DATA:
663 664
          return builder.getPointerField(slot.getOffset() * POINTERS)
                        .initBlob<Data>(size * BYTES);
665
        default:
666
          KJ_FAIL_REQUIRE(
667 668
              "init() with size is only valid for list, text, or data fields.",
              (uint)type.which());
669 670
          break;
      }
671
    }
Kenton Varda's avatar
Kenton Varda committed
672

Kenton Varda's avatar
Kenton Varda committed
673
    case schema::Field::GROUP:
Kenton Varda's avatar
Kenton Varda committed
674
      KJ_FAIL_REQUIRE("init() with size is only valid for list, text, or data fields.");
Kenton Varda's avatar
Kenton Varda committed
675 676
  }

Kenton Varda's avatar
Kenton Varda committed
677
  KJ_UNREACHABLE;
Kenton Varda's avatar
Kenton Varda committed
678 679
}

680 681 682 683 684 685
void DynamicStruct::Builder::adopt(StructSchema::Field field, Orphan<DynamicValue>&& orphan) {
  KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
  setInUnion(field);

  auto proto = field.getProto();
  switch (proto.which()) {
686 687
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
688
      auto type = field.getType();
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707

      switch (type.which()) {
        case schema::Type::VOID:
        case schema::Type::BOOL:
        case schema::Type::INT8:
        case schema::Type::INT16:
        case schema::Type::INT32:
        case schema::Type::INT64:
        case schema::Type::UINT8:
        case schema::Type::UINT16:
        case schema::Type::UINT32:
        case schema::Type::UINT64:
        case schema::Type::FLOAT32:
        case schema::Type::FLOAT64:
        case schema::Type::ENUM:
          set(field, orphan.getReader());
          return;

        case schema::Type::TEXT:
708
          KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch.");
709 710 711
          break;

        case schema::Type::DATA:
712
          KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
713 714 715
          break;

        case schema::Type::LIST: {
716
          ListSchema listType = type.asList();
717
          KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == listType,
718 719 720
                     "Value type mismatch.") {
            return;
          }
721 722 723 724
          break;
        }

        case schema::Type::STRUCT: {
725
          auto structType = type.asStruct();
726
          KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == structType,
727 728 729
                     "Value type mismatch.") {
            return;
          }
730 731 732
          break;
        }

733
        case schema::Type::ANY_POINTER:
734 735
          KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT ||
                     orphan.getType() == DynamicValue::LIST ||
736 737
                     orphan.getType() == DynamicValue::TEXT ||
                     orphan.getType() == DynamicValue::DATA ||
738
                     orphan.getType() == DynamicValue::ANY_POINTER,
739 740 741
                     "Value type mismatch.") {
            return;
          }
742 743 744
          break;

        case schema::Type::INTERFACE:
745
          auto interfaceType = type.asInterface();
746 747 748 749 750
          KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY &&
                     orphan.interfaceSchema.extends(interfaceType),
                     "Value type mismatch.") {
            return;
          }
751 752 753
          break;
      }

754
      builder.getPointerField(slot.getOffset() * POINTERS).adopt(kj::mv(orphan.builder));
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
      return;
    }

    case schema::Field::GROUP:
      // Have to transfer fields.
      auto src = orphan.get().as<DynamicStruct>();
      auto dst = init(field).as<DynamicStruct>();

      KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == dst.getSchema(),
                 "Value type mismatch.");

      KJ_IF_MAYBE(unionField, src.which()) {
        dst.adopt(*unionField, src.disown(*unionField));
      }

      for (auto field: src.schema.getNonUnionFields()) {
        if (src.has(field)) {
          dst.adopt(field, src.disown(field));
        }
      }

      return;
  }

  KJ_UNREACHABLE;
}

Orphan<DynamicValue> DynamicStruct::Builder::disown(StructSchema::Field field) {
  // We end up calling get(field) below, so we don't need to validate `field` here.

  auto proto = field.getProto();
  switch (proto.which()) {
787 788
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
789

790
      switch (field.getType().which()) {
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
        case schema::Type::VOID:
        case schema::Type::BOOL:
        case schema::Type::INT8:
        case schema::Type::INT16:
        case schema::Type::INT32:
        case schema::Type::INT64:
        case schema::Type::UINT8:
        case schema::Type::UINT16:
        case schema::Type::UINT32:
        case schema::Type::UINT64:
        case schema::Type::FLOAT32:
        case schema::Type::FLOAT64:
        case schema::Type::ENUM: {
          auto result = Orphan<DynamicValue>(get(field), _::OrphanBuilder());
          clear(field);
          return kj::mv(result);
        }

        case schema::Type::TEXT:
        case schema::Type::DATA:
        case schema::Type::LIST:
        case schema::Type::STRUCT:
813
        case schema::Type::ANY_POINTER:
814 815
        case schema::Type::INTERFACE: {
          auto value = get(field);
816 817
          return Orphan<DynamicValue>(
              value, builder.getPointerField(slot.getOffset() * POINTERS).disown());
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
        }
      }
      KJ_UNREACHABLE;
    }

    case schema::Field::GROUP: {
      // We have to allocate new space for the group, unfortunately.
      auto src = get(field).as<DynamicStruct>();

      Orphan<DynamicStruct> result =
          Orphanage::getForMessageContaining(*this).newOrphan(src.getSchema());
      auto dst = result.get();

      KJ_IF_MAYBE(unionField, src.which()) {
        dst.adopt(*unionField, src.disown(*unionField));
      }

      // We need to explicitly reset the union to its default field.
      KJ_IF_MAYBE(unionField, src.schema.getFieldByDiscriminant(0)) {
        src.clear(*unionField);
      }

      for (auto field: src.schema.getNonUnionFields()) {
        if (src.has(field)) {
          dst.adopt(field, src.disown(field));
        }
      }

      return kj::mv(result);
    }
  }

  KJ_UNREACHABLE;
}
Kenton Varda's avatar
Kenton Varda committed
852 853 854 855 856 857

void DynamicStruct::Builder::clear(StructSchema::Field field) {
  KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
  setInUnion(field);

  auto proto = field.getProto();
858
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
859
  switch (proto.which()) {
860 861
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
Kenton Varda's avatar
Kenton Varda committed
862 863

      switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
864
        case schema::Type::VOID:
865
          builder.setDataField<Void>(slot.getOffset() * ELEMENTS, VOID);
Kenton Varda's avatar
Kenton Varda committed
866 867 868
          return;

#define HANDLE_TYPE(discrim, type) \
Kenton Varda's avatar
Kenton Varda committed
869
        case schema::Type::discrim: \
870
          builder.setDataField<type>(slot.getOffset() * ELEMENTS, 0); \
Kenton Varda's avatar
Kenton Varda committed
871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
          return;

        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

Kenton Varda's avatar
Kenton Varda committed
888 889 890 891
        case schema::Type::TEXT:
        case schema::Type::DATA:
        case schema::Type::LIST:
        case schema::Type::STRUCT:
892
        case schema::Type::ANY_POINTER:
Kenton Varda's avatar
Kenton Varda committed
893
        case schema::Type::INTERFACE:
894
          builder.getPointerField(slot.getOffset() * POINTERS).clear();
Kenton Varda's avatar
Kenton Varda committed
895 896 897 898 899 900
          return;
      }

      KJ_UNREACHABLE;
    }

Kenton Varda's avatar
Kenton Varda committed
901
    case schema::Field::GROUP: {
902
      DynamicStruct::Builder group(type.asStruct(), builder);
903 904 905

      // We clear the union field with discriminant 0 rather than the one that is set because
      // we want the union to end up with its default field active.
Kenton Varda's avatar
Kenton Varda committed
906 907 908
      KJ_IF_MAYBE(unionField, group.schema.getFieldByDiscriminant(0)) {
        group.clear(*unionField);
      }
909

Kenton Varda's avatar
Kenton Varda committed
910 911 912
      for (auto subField: group.schema.getNonUnionFields()) {
        group.clear(subField);
      }
913
      return;
Kenton Varda's avatar
Kenton Varda committed
914 915
    }
  }
916

Kenton Varda's avatar
Kenton Varda committed
917 918 919 920 921 922 923 924 925
  KJ_UNREACHABLE;
}

DynamicValue::Reader DynamicStruct::Reader::get(kj::StringPtr name) const {
  return get(schema.getFieldByName(name));
}
DynamicValue::Builder DynamicStruct::Builder::get(kj::StringPtr name) {
  return get(schema.getFieldByName(name));
}
926
DynamicValue::Pipeline DynamicStruct::Pipeline::get(kj::StringPtr name) {
927 928
  return get(schema.getFieldByName(name));
}
Kenton Varda's avatar
Kenton Varda committed
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951
bool DynamicStruct::Reader::has(kj::StringPtr name) const {
  return has(schema.getFieldByName(name));
}
bool DynamicStruct::Builder::has(kj::StringPtr name) {
  return has(schema.getFieldByName(name));
}
void DynamicStruct::Builder::set(kj::StringPtr name, const DynamicValue::Reader& value) {
  set(schema.getFieldByName(name), value);
}
void DynamicStruct::Builder::set(kj::StringPtr name,
                                 std::initializer_list<DynamicValue::Reader> value) {
  auto list = init(name, value.size()).as<DynamicList>();
  uint i = 0;
  for (auto element: value) {
    list.set(i++, element);
  }
}
DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name) {
  return init(schema.getFieldByName(name));
}
DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name, uint size) {
  return init(schema.getFieldByName(name), size);
}
952 953 954 955 956 957
void DynamicStruct::Builder::adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan) {
  adopt(schema.getFieldByName(name), kj::mv(orphan));
}
Orphan<DynamicValue> DynamicStruct::Builder::disown(kj::StringPtr name) {
  return disown(schema.getFieldByName(name));
}
Kenton Varda's avatar
Kenton Varda committed
958
void DynamicStruct::Builder::clear(kj::StringPtr name) {
959
  clear(schema.getFieldByName(name));
Kenton Varda's avatar
Kenton Varda committed
960
}
Kenton Varda's avatar
Kenton Varda committed
961 962 963

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

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

967
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
968
#define HANDLE_TYPE(name, discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
969
    case schema::Type::discrim: \
970
      return reader.getDataElement<typeName>(index * ELEMENTS);
971 972 973 974 975 976 977 978 979 980 981 982 983

    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
984 985
#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
986
    case schema::Type::TEXT:
987
      return reader.getPointerElement(index * ELEMENTS).getBlob<Text>(nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
988
    case schema::Type::DATA:
989
      return reader.getPointerElement(index * ELEMENTS).getBlob<Data>(nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
990

Kenton Varda's avatar
Kenton Varda committed
991
    case schema::Type::LIST: {
992
      auto elementType = schema.getListElementType();
993 994 995
      return DynamicList::Reader(elementType,
          reader.getPointerElement(index * ELEMENTS)
                .getList(elementSizeFor(elementType.whichElementType()), nullptr));
996
    }
Kenton Varda's avatar
Kenton Varda committed
997

Kenton Varda's avatar
Kenton Varda committed
998
    case schema::Type::STRUCT:
999 1000
      return DynamicStruct::Reader(schema.getStructElementType(),
                                   reader.getStructElement(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1001

Kenton Varda's avatar
Kenton Varda committed
1002
    case schema::Type::ENUM:
1003 1004
      return DynamicEnum(schema.getEnumElementType(),
                         reader.getDataElement<uint16_t>(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1005

1006 1007
    case schema::Type::ANY_POINTER:
      return AnyPointer::Reader(reader.getPointerElement(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1008

Kenton Varda's avatar
Kenton Varda committed
1009
    case schema::Type::INTERFACE:
1010 1011
      return DynamicCapability::Client(schema.getInterfaceElementType(),
                                       reader.getPointerElement(index * ELEMENTS).getCapability());
Kenton Varda's avatar
Kenton Varda committed
1012
  }
1013

1014
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1015 1016
}

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

1020
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1021
#define HANDLE_TYPE(name, discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1022
    case schema::Type::discrim: \
1023
      return builder.getDataElement<typeName>(index * ELEMENTS);
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036

    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
1037 1038
#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
1039
    case schema::Type::TEXT:
1040
      return builder.getPointerElement(index * ELEMENTS).getBlob<Text>(nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
1041
    case schema::Type::DATA:
1042
      return builder.getPointerElement(index * ELEMENTS).getBlob<Data>(nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
1043

Kenton Varda's avatar
Kenton Varda committed
1044
    case schema::Type::LIST: {
1045
      ListSchema elementType = schema.getListElementType();
Kenton Varda's avatar
Kenton Varda committed
1046
      if (elementType.whichElementType() == schema::Type::STRUCT) {
1047
        return DynamicList::Builder(elementType,
1048 1049 1050
            builder.getPointerElement(index * ELEMENTS)
                   .getStructList(structSizeFromSchema(elementType.getStructElementType()),
                                  nullptr));
1051
      } else {
1052
        return DynamicList::Builder(elementType,
1053 1054
            builder.getPointerElement(index * ELEMENTS)
                   .getList(elementSizeFor(elementType.whichElementType()), nullptr));
1055 1056
      }
    }
Kenton Varda's avatar
Kenton Varda committed
1057

Kenton Varda's avatar
Kenton Varda committed
1058
    case schema::Type::STRUCT:
1059 1060
      return DynamicStruct::Builder(schema.getStructElementType(),
                                    builder.getStructElement(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1061

Kenton Varda's avatar
Kenton Varda committed
1062
    case schema::Type::ENUM:
1063 1064
      return DynamicEnum(schema.getEnumElementType(),
                         builder.getDataElement<uint16_t>(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1065

1066 1067
    case schema::Type::ANY_POINTER:
      KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
1068
      return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1069

Kenton Varda's avatar
Kenton Varda committed
1070
    case schema::Type::INTERFACE:
1071 1072
      return DynamicCapability::Client(schema.getInterfaceElementType(),
                                       builder.getPointerElement(index * ELEMENTS).getCapability());
Kenton Varda's avatar
Kenton Varda committed
1073
  }
1074

1075
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1076 1077
}

1078
void DynamicList::Builder::set(uint index, const DynamicValue::Reader& value) {
1079
  KJ_REQUIRE(index < size(), "List index out-of-bounds.") {
1080 1081
    return;
  }
Kenton Varda's avatar
Kenton Varda committed
1082

1083
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1084
#define HANDLE_TYPE(name, discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1085
    case schema::Type::discrim: \
1086
      builder.setDataElement<typeName>(index * ELEMENTS, value.as<typeName>()); \
1087
      return;
Kenton Varda's avatar
Kenton Varda committed
1088

1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
    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
1101 1102
#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
1103
    case schema::Type::TEXT:
1104
      builder.getPointerElement(index * ELEMENTS).setBlob<Text>(value.as<Text>());
1105
      return;
Kenton Varda's avatar
Kenton Varda committed
1106
    case schema::Type::DATA:
1107
      builder.getPointerElement(index * ELEMENTS).setBlob<Data>(value.as<Data>());
1108
      return;
Kenton Varda's avatar
Kenton Varda committed
1109

Kenton Varda's avatar
Kenton Varda committed
1110
    case schema::Type::LIST: {
1111 1112 1113 1114
      auto listValue = value.as<DynamicList>();
      KJ_REQUIRE(listValue.getSchema() == schema.getListElementType(), "Value type mismatch.") {
        return;
      }
1115
      builder.getPointerElement(index * ELEMENTS).setList(listValue.reader);
1116
      return;
1117
    }
Kenton Varda's avatar
Kenton Varda committed
1118

1119
    case schema::Type::STRUCT: {
1120 1121 1122 1123 1124
      auto structValue = value.as<DynamicStruct>();
      KJ_REQUIRE(structValue.getSchema() == schema.getStructElementType(), "Value type mismatch.") {
        return;
      }
      builder.getStructElement(index * ELEMENTS).copyContentFrom(structValue.reader);
1125 1126
      return;
    }
Kenton Varda's avatar
Kenton Varda committed
1127

Kenton Varda's avatar
Kenton Varda committed
1128
    case schema::Type::ENUM: {
1129 1130 1131 1132 1133 1134
      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>();
1135 1136
        KJ_REQUIRE(schema.getEnumElementType() == enumValue.getSchema(),
                   "Type mismatch when using DynamicList::Builder::set().") {
1137 1138 1139
          return;
        }
        rawValue = enumValue.getRaw();
1140
      }
1141
      builder.setDataElement<uint16_t>(index * ELEMENTS, rawValue);
1142
      return;
1143
    }
Kenton Varda's avatar
Kenton Varda committed
1144

1145 1146
    case schema::Type::ANY_POINTER:
      KJ_FAIL_ASSERT("List(AnyPointer) not supported.") {
1147 1148
        return;
      }
Kenton Varda's avatar
Kenton Varda committed
1149

1150 1151 1152 1153
    case schema::Type::INTERFACE: {
      auto capValue = value.as<DynamicCapability>();
      KJ_REQUIRE(capValue.getSchema().extends(schema.getInterfaceElementType()),
                 "Value type mismatch.") {
1154 1155
        return;
      }
1156 1157 1158
      builder.getPointerElement(index * ELEMENTS).setCapability(kj::mv(capValue.hook));
      return;
    }
Kenton Varda's avatar
Kenton Varda committed
1159
  }
1160

1161 1162 1163
  KJ_FAIL_REQUIRE("can't set element of unknown type", (uint)schema.whichElementType()) {
    return;
  }
Kenton Varda's avatar
Kenton Varda committed
1164 1165 1166
}

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

1169
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184
    case schema::Type::VOID:
    case schema::Type::BOOL:
    case schema::Type::INT8:
    case schema::Type::INT16:
    case schema::Type::INT32:
    case schema::Type::INT64:
    case schema::Type::UINT8:
    case schema::Type::UINT16:
    case schema::Type::UINT32:
    case schema::Type::UINT64:
    case schema::Type::FLOAT32:
    case schema::Type::FLOAT64:
    case schema::Type::ENUM:
    case schema::Type::STRUCT:
    case schema::Type::INTERFACE:
1185
      KJ_FAIL_REQUIRE("Expected a list or blob.");
1186
      return nullptr;
1187

Kenton Varda's avatar
Kenton Varda committed
1188
    case schema::Type::TEXT:
1189
      return builder.getPointerElement(index * ELEMENTS).initBlob<Text>(size * BYTES);
1190

Kenton Varda's avatar
Kenton Varda committed
1191
    case schema::Type::DATA:
1192
      return builder.getPointerElement(index * ELEMENTS).initBlob<Data>(size * BYTES);
1193

Kenton Varda's avatar
Kenton Varda committed
1194
    case schema::Type::LIST: {
1195 1196
      auto elementType = schema.getListElementType();

Kenton Varda's avatar
Kenton Varda committed
1197
      if (elementType.whichElementType() == schema::Type::STRUCT) {
1198 1199 1200 1201
        return DynamicList::Builder(elementType,
            builder.getPointerElement(index * ELEMENTS)
                   .initStructList(size * ELEMENTS,
                                   structSizeFromSchema(elementType.getStructElementType())));
1202
      } else {
1203 1204 1205
        return DynamicList::Builder(elementType,
            builder.getPointerElement(index * ELEMENTS)
                   .initList(elementSizeFor(elementType.whichElementType()), size * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1206 1207 1208
      }
    }

1209 1210
    case schema::Type::ANY_POINTER: {
      KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
1211
      return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1212 1213
    }
  }
1214

1215
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1216 1217
}

1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
void DynamicList::Builder::adopt(uint index, Orphan<DynamicValue>&& orphan) {
  switch (schema.whichElementType()) {
    case schema::Type::VOID:
    case schema::Type::BOOL:
    case schema::Type::INT8:
    case schema::Type::INT16:
    case schema::Type::INT32:
    case schema::Type::INT64:
    case schema::Type::UINT8:
    case schema::Type::UINT16:
    case schema::Type::UINT32:
    case schema::Type::UINT64:
    case schema::Type::FLOAT32:
    case schema::Type::FLOAT64:
    case schema::Type::ENUM:
      set(index, orphan.getReader());
      return;

    case schema::Type::TEXT:
      KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch.");
1238
      builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(orphan.builder));
1239 1240 1241 1242
      return;

    case schema::Type::DATA:
      KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
1243
      builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(orphan.builder));
1244 1245 1246 1247 1248 1249
      return;

    case schema::Type::LIST: {
      ListSchema elementType = schema.getListElementType();
      KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == elementType,
                 "Value type mismatch.");
1250
      builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(orphan.builder));
1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
      return;
    }

    case schema::Type::STRUCT: {
      auto elementType = schema.getStructElementType();
      KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == elementType,
                 "Value type mismatch.");
      builder.getStructElement(index * ELEMENTS).transferContentFrom(
          orphan.builder.asStruct(structSizeFromSchema(elementType)));
      return;
    }

1263 1264
    case schema::Type::ANY_POINTER:
      KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
1265

1266 1267 1268 1269 1270 1271 1272 1273
    case schema::Type::INTERFACE: {
      auto elementType = schema.getInterfaceElementType();
      KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY &&
                 orphan.interfaceSchema.extends(elementType),
                 "Value type mismatch.");
      builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(orphan.builder));
      return;
    }
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295
  }

  KJ_UNREACHABLE;
}

Orphan<DynamicValue> DynamicList::Builder::disown(uint index) {
  switch (schema.whichElementType()) {
    case schema::Type::VOID:
    case schema::Type::BOOL:
    case schema::Type::INT8:
    case schema::Type::INT16:
    case schema::Type::INT32:
    case schema::Type::INT64:
    case schema::Type::UINT8:
    case schema::Type::UINT16:
    case schema::Type::UINT32:
    case schema::Type::UINT64:
    case schema::Type::FLOAT32:
    case schema::Type::FLOAT64:
    case schema::Type::ENUM: {
      auto result = Orphan<DynamicValue>(operator[](index), _::OrphanBuilder());
      switch (elementSizeFor(schema.whichElementType())) {
1296 1297 1298 1299 1300 1301 1302 1303 1304
        case ElementSize::VOID: break;
        case ElementSize::BIT: builder.setDataElement<bool>(index * ELEMENTS, false); break;
        case ElementSize::BYTE: builder.setDataElement<uint8_t>(index * ELEMENTS, 0); break;
        case ElementSize::TWO_BYTES: builder.setDataElement<uint16_t>(index * ELEMENTS, 0); break;
        case ElementSize::FOUR_BYTES: builder.setDataElement<uint32_t>(index * ELEMENTS, 0); break;
        case ElementSize::EIGHT_BYTES: builder.setDataElement<uint64_t>(index * ELEMENTS, 0);break;

        case ElementSize::POINTER:
        case ElementSize::INLINE_COMPOSITE:
1305 1306 1307 1308 1309 1310 1311 1312
          KJ_UNREACHABLE;
      }
      return kj::mv(result);
    }

    case schema::Type::TEXT:
    case schema::Type::DATA:
    case schema::Type::LIST:
1313
    case schema::Type::ANY_POINTER:
1314 1315
    case schema::Type::INTERFACE: {
      auto value = operator[](index);
1316
      return Orphan<DynamicValue>(value, builder.getPointerElement(index * ELEMENTS).disown());
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331
    }

    case schema::Type::STRUCT: {
      // We have to make a copy.
      Orphan<DynamicStruct> result =
          Orphanage::getForMessageContaining(*this).newOrphan(schema.getStructElementType());
      auto element = builder.getStructElement(index * ELEMENTS);
      result.get().builder.transferContentFrom(element);
      element.clearAll();
      return kj::mv(result);
    }
  }
  KJ_UNREACHABLE;
}

1332
void DynamicList::Builder::copyFrom(std::initializer_list<DynamicValue::Reader> value) {
1333
  KJ_REQUIRE(value.size() == size(), "DynamicList::copyFrom() argument had different size.");
1334 1335 1336 1337 1338 1339
  uint i = 0;
  for (auto element: value) {
    set(i++, element);
  }
}

1340
DynamicList::Reader DynamicList::Builder::asReader() const {
1341
  return DynamicList::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
1342 1343
}

Kenton Varda's avatar
Kenton Varda committed
1344 1345
// =======================================================================================

Kenton Varda's avatar
Kenton Varda committed
1346
DynamicValue::Reader::Reader(ConstSchema constant): type(VOID) {
1347
  auto type = constant.getType();
1348
  auto value = constant.getProto().getConst().getValue();
1349
  switch (type.which()) {
1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
    case schema::Type::VOID: *this = capnp::VOID; break;
    case schema::Type::BOOL: *this = value.getBool(); break;
    case schema::Type::INT8: *this = value.getInt8(); break;
    case schema::Type::INT16: *this = value.getInt16(); break;
    case schema::Type::INT32: *this = value.getInt32(); break;
    case schema::Type::INT64: *this = value.getInt64(); break;
    case schema::Type::UINT8: *this = value.getUint8(); break;
    case schema::Type::UINT16: *this = value.getUint16(); break;
    case schema::Type::UINT32: *this = value.getUint32(); break;
    case schema::Type::UINT64: *this = value.getUint64(); break;
    case schema::Type::FLOAT32: *this = value.getFloat32(); break;
    case schema::Type::FLOAT64: *this = value.getFloat64(); break;
    case schema::Type::TEXT: *this = value.getText(); break;
    case schema::Type::DATA: *this = value.getData(); break;

    case schema::Type::ENUM:
1366
      *this = DynamicEnum(type.asEnum(), value.getEnum());
1367 1368 1369
      break;

    case schema::Type::STRUCT:
1370
      *this = value.getStruct().getAs<DynamicStruct>(type.asStruct());
1371 1372 1373
      break;

    case schema::Type::LIST:
1374
      *this = value.getList().getAs<DynamicList>(type.asList());
1375 1376
      break;

1377 1378
    case schema::Type::ANY_POINTER:
      *this = value.getAnyPointer();
1379 1380 1381 1382 1383 1384 1385
      break;

    case schema::Type::INTERFACE:
      KJ_FAIL_ASSERT("Constants can't have interface type.");
  }
}

1386
DynamicValue::Reader::Reader(const Reader& other) {
Kenton Varda's avatar
Kenton Varda committed
1387
  switch (other.type) {
1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398
    case UNKNOWN:
    case VOID:
    case BOOL:
    case INT:
    case UINT:
    case FLOAT:
    case TEXT:
    case DATA:
    case LIST:
    case ENUM:
    case STRUCT:
1399
    case ANY_POINTER:
1400 1401 1402 1403 1404 1405
      static_assert(kj::canMemcpy<Text::Reader>() &&
                    kj::canMemcpy<Data::Reader>() &&
                    kj::canMemcpy<DynamicList::Reader>() &&
                    kj::canMemcpy<DynamicEnum>() &&
                    kj::canMemcpy<DynamicStruct::Reader>() &&
                    kj::canMemcpy<AnyPointer::Reader>(),
1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
                    "Assumptions here don't hold.");
      break;

    case CAPABILITY:
      type = CAPABILITY;
      kj::ctor(capabilityValue, other.capabilityValue);
      return;
  }

  memcpy(this, &other, sizeof(*this));
}
Kenton Varda's avatar
Kenton Varda committed
1417 1418
DynamicValue::Reader::Reader(Reader&& other) noexcept {
  switch (other.type) {
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429
    case UNKNOWN:
    case VOID:
    case BOOL:
    case INT:
    case UINT:
    case FLOAT:
    case TEXT:
    case DATA:
    case LIST:
    case ENUM:
    case STRUCT:
1430
    case ANY_POINTER:
1431 1432 1433 1434 1435 1436
      static_assert(kj::canMemcpy<Text::Reader>() &&
                    kj::canMemcpy<Data::Reader>() &&
                    kj::canMemcpy<DynamicList::Reader>() &&
                    kj::canMemcpy<DynamicEnum>() &&
                    kj::canMemcpy<DynamicStruct::Reader>() &&
                    kj::canMemcpy<AnyPointer::Reader>(),
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447
                    "Assumptions here don't hold.");
      break;

    case CAPABILITY:
      type = CAPABILITY;
      kj::ctor(capabilityValue, kj::mv(other.capabilityValue));
      return;
  }

  memcpy(this, &other, sizeof(*this));
}
Kenton Varda's avatar
Kenton Varda committed
1448
DynamicValue::Reader::~Reader() noexcept(false) {
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469
  if (type == CAPABILITY) {
    kj::dtor(capabilityValue);
  }
}

DynamicValue::Reader& DynamicValue::Reader::operator=(const Reader& other) {
  if (type == CAPABILITY) {
    kj::dtor(capabilityValue);
  }
  kj::ctor(*this, other);
  return *this;
}
DynamicValue::Reader& DynamicValue::Reader::operator=(Reader&& other) {
  if (type == CAPABILITY) {
    kj::dtor(capabilityValue);
  }
  kj::ctor(*this, kj::mv(other));
  return *this;
}

DynamicValue::Builder::Builder(Builder& other) {
Kenton Varda's avatar
Kenton Varda committed
1470
  switch (other.type) {
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
    case UNKNOWN:
    case VOID:
    case BOOL:
    case INT:
    case UINT:
    case FLOAT:
    case TEXT:
    case DATA:
    case LIST:
    case ENUM:
    case STRUCT:
1482
    case ANY_POINTER:
1483
      // Unfortunately canMemcpy() doesn't work on these types due to the use of
1484 1485 1486 1487 1488 1489 1490
      // DisallowConstCopy, but __has_trivial_destructor should detect if any of these types
      // become non-trivial.
      static_assert(__has_trivial_destructor(Text::Builder) &&
                    __has_trivial_destructor(Data::Builder) &&
                    __has_trivial_destructor(DynamicList::Builder) &&
                    __has_trivial_destructor(DynamicEnum) &&
                    __has_trivial_destructor(DynamicStruct::Builder) &&
1491
                    __has_trivial_destructor(AnyPointer::Builder),
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502
                    "Assumptions here don't hold.");
      break;

    case CAPABILITY:
      type = CAPABILITY;
      kj::ctor(capabilityValue, other.capabilityValue);
      return;
  }

  memcpy(this, &other, sizeof(*this));
}
Kenton Varda's avatar
Kenton Varda committed
1503 1504
DynamicValue::Builder::Builder(Builder&& other) noexcept {
  switch (other.type) {
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515
    case UNKNOWN:
    case VOID:
    case BOOL:
    case INT:
    case UINT:
    case FLOAT:
    case TEXT:
    case DATA:
    case LIST:
    case ENUM:
    case STRUCT:
1516
    case ANY_POINTER:
1517 1518 1519 1520 1521 1522 1523 1524
      // Unfortunately __has_trivial_copy doesn't work on these types due to the use of
      // DisallowConstCopy, but __has_trivial_destructor should detect if any of these types
      // become non-trivial.
      static_assert(__has_trivial_destructor(Text::Builder) &&
                    __has_trivial_destructor(Data::Builder) &&
                    __has_trivial_destructor(DynamicList::Builder) &&
                    __has_trivial_destructor(DynamicEnum) &&
                    __has_trivial_destructor(DynamicStruct::Builder) &&
1525
                    __has_trivial_destructor(AnyPointer::Builder),
1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
                    "Assumptions here don't hold.");
      break;

    case CAPABILITY:
      type = CAPABILITY;
      kj::ctor(capabilityValue, kj::mv(other.capabilityValue));
      return;
  }

  memcpy(this, &other, sizeof(*this));
}
Kenton Varda's avatar
Kenton Varda committed
1537
DynamicValue::Builder::~Builder() noexcept(false) {
1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
  if (type == CAPABILITY) {
    kj::dtor(capabilityValue);
  }
}

DynamicValue::Builder& DynamicValue::Builder::operator=(Builder& other) {
  if (type == CAPABILITY) {
    kj::dtor(capabilityValue);
  }
  kj::ctor(*this, other);
  return *this;
}
DynamicValue::Builder& DynamicValue::Builder::operator=(Builder&& other) {
  if (type == CAPABILITY) {
    kj::dtor(capabilityValue);
  }
  kj::ctor(*this, kj::mv(other));
  return *this;
}

1558
DynamicValue::Reader DynamicValue::Builder::asReader() const {
Kenton Varda's avatar
Kenton Varda committed
1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570
  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());
1571
    case CAPABILITY: return Reader(capabilityValue);
1572
    case ANY_POINTER: return Reader(anyPointerValue.asReader());
Kenton Varda's avatar
Kenton Varda committed
1573
  }
1574
  KJ_FAIL_ASSERT("Missing switch case.");
Kenton Varda's avatar
Kenton Varda committed
1575 1576 1577
  return Reader();
}

1578
DynamicValue::Pipeline::Pipeline(Pipeline&& other) noexcept: type(other.type) {
1579 1580 1581 1582 1583
  switch (type) {
    case UNKNOWN: break;
    case STRUCT: kj::ctor(structValue, kj::mv(other.structValue)); break;
    case CAPABILITY: kj::ctor(capabilityValue, kj::mv(other.capabilityValue)); break;
    default:
1584 1585
      KJ_LOG(ERROR, "Unexpected pipeline type.", (uint)type);
      type = UNKNOWN;
1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604
      break;
  }
}
DynamicValue::Pipeline& DynamicValue::Pipeline::operator=(Pipeline&& other) {
  kj::dtor(*this);
  kj::ctor(*this, kj::mv(other));
  return *this;
}
DynamicValue::Pipeline::~Pipeline() noexcept(false) {
  switch (type) {
    case UNKNOWN: break;
    case STRUCT: kj::dtor(structValue); break;
    case CAPABILITY: kj::dtor(capabilityValue); break;
    default:
      KJ_FAIL_ASSERT("Unexpected pipeline type.", (uint)type) { type = UNKNOWN; break; }
      break;
  }
}

1605 1606 1607 1608
namespace {

template <typename T>
T signedToUnsigned(long long value) {
1609
  KJ_REQUIRE(value >= 0 && T(value) == value, "Value out-of-range for requested type.", value) {
1610
    // Use it anyway.
1611
    break;
1612 1613 1614 1615 1616 1617
  }
  return value;
}

template <>
uint64_t signedToUnsigned<uint64_t>(long long value) {
1618
  KJ_REQUIRE(value >= 0, "Value out-of-range for requested type.", value) {
1619
    // Use it anyway.
1620
    break;
1621 1622 1623 1624 1625 1626
  }
  return value;
}

template <typename T>
T unsignedToSigned(unsigned long long value) {
1627 1628
  KJ_REQUIRE(T(value) >= 0 && (unsigned long long)T(value) == value,
             "Value out-of-range for requested type.", value) {
1629
    // Use it anyway.
1630
    break;
1631 1632 1633 1634 1635 1636
  }
  return value;
}

template <>
int64_t unsignedToSigned<int64_t>(unsigned long long value) {
1637
  KJ_REQUIRE(int64_t(value) >= 0, "Value out-of-range for requested type.", value) {
1638
    // Use it anyway.
1639
    break;
1640 1641 1642 1643 1644 1645
  }
  return value;
}

template <typename T, typename U>
T checkRoundTrip(U value) {
1646
  KJ_REQUIRE(T(value) == value, "Value out-of-range for requested type.", value) {
1647
    // Use it anyway.
1648
    break;
1649 1650 1651 1652 1653 1654 1655
  }
  return value;
}

}  // namespace

#define HANDLE_NUMERIC_TYPE(typeName, ifInt, ifUint, ifFloat) \
1656
typeName DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
1657 1658 1659 1660 1661 1662 1663 1664
  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
1665
      KJ_FAIL_REQUIRE("Value type mismatch.") { \
1666
        return 0; \
1667
      } \
1668 1669
  } \
} \
1670
typeName DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
1671 1672 1673 1674 1675 1676 1677 1678
  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
1679
      KJ_FAIL_REQUIRE("Value type mismatch.") { \
1680
        return 0; \
1681
      } \
1682 1683 1684 1685 1686 1687
  } \
}

HANDLE_NUMERIC_TYPE(int8_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
HANDLE_NUMERIC_TYPE(int16_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
HANDLE_NUMERIC_TYPE(int32_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
1688
HANDLE_NUMERIC_TYPE(int64_t, kj::implicitCast, unsignedToSigned, checkRoundTrip)
1689 1690 1691
HANDLE_NUMERIC_TYPE(uint8_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
HANDLE_NUMERIC_TYPE(uint16_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
HANDLE_NUMERIC_TYPE(uint32_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
1692 1693 1694
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)
1695 1696 1697

#undef HANDLE_NUMERIC_TYPE

Kenton Varda's avatar
Kenton Varda committed
1698
#define HANDLE_TYPE(name, discrim, typeName) \
1699
ReaderFor<typeName> DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
Kenton Varda's avatar
Kenton Varda committed
1700
  KJ_REQUIRE(reader.type == discrim, "Value type mismatch.") { \
1701 1702
    return ReaderFor<typeName>(); \
  } \
Kenton Varda's avatar
Kenton Varda committed
1703 1704
  return reader.name##Value; \
} \
1705
BuilderFor<typeName> DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
1706
  KJ_REQUIRE(builder.type == discrim, "Value type mismatch."); \
Kenton Varda's avatar
Kenton Varda committed
1707 1708 1709 1710 1711 1712 1713 1714 1715 1716
  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)
1717
HANDLE_TYPE(anyPointer, ANY_POINTER, AnyPointer)
Kenton Varda's avatar
Kenton Varda committed
1718 1719 1720

#undef HANDLE_TYPE

1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748
PipelineFor<DynamicStruct> DynamicValue::Pipeline::AsImpl<DynamicStruct>::apply(
    Pipeline& pipeline) {
  KJ_REQUIRE(pipeline.type == STRUCT, "Pipeline type mismatch.");
  return kj::mv(pipeline.structValue);
}

ReaderFor<DynamicCapability> DynamicValue::Reader::AsImpl<DynamicCapability>::apply(
    const Reader& reader) {
  KJ_REQUIRE(reader.type == CAPABILITY, "Value type mismatch.") {
    return DynamicCapability::Client();
  }
  return reader.capabilityValue;
}
BuilderFor<DynamicCapability> DynamicValue::Builder::AsImpl<DynamicCapability>::apply(
    Builder& builder) {
  KJ_REQUIRE(builder.type == CAPABILITY, "Value type mismatch.") {
    return DynamicCapability::Client();
  }
  return builder.capabilityValue;
}
PipelineFor<DynamicCapability> DynamicValue::Pipeline::AsImpl<DynamicCapability>::apply(
    Pipeline& pipeline) {
  KJ_REQUIRE(pipeline.type == CAPABILITY, "Pipeline type mismatch.") {
    return DynamicCapability::Client();
  }
  return kj::mv(pipeline.capabilityValue);
}

1749 1750 1751
Data::Reader DynamicValue::Reader::AsImpl<Data>::apply(const Reader& reader) {
  if (reader.type == TEXT) {
    // Coerce text to data.
1752
    return reader.textValue.asBytes();
1753 1754 1755 1756 1757 1758 1759 1760 1761
  }
  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.
1762
    return builder.textValue.asBytes();
1763 1764 1765 1766 1767 1768 1769
  }
  KJ_REQUIRE(builder.type == DATA, "Value type mismatch.") {
    return BuilderFor<Data>();
  }
  return builder.dataValue;
}

Kenton Varda's avatar
Kenton Varda committed
1770
// As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
1771
Void DynamicValue::Reader::AsImpl<Void>::apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1772
  KJ_REQUIRE(reader.type == VOID, "Value type mismatch.") {
Kenton Varda's avatar
Kenton Varda committed
1773 1774 1775 1776
    return Void();
  }
  return reader.voidValue;
}
1777
Void DynamicValue::Builder::AsImpl<Void>::apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1778
  KJ_REQUIRE(builder.type == VOID, "Value type mismatch.") {
Kenton Varda's avatar
Kenton Varda committed
1779 1780 1781 1782 1783
    return Void();
  }
  return builder.voidValue;
}

Kenton Varda's avatar
Kenton Varda committed
1784 1785
// =======================================================================================

1786
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
1787

1788
DynamicStruct::Reader PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
1789
    PointerReader reader, StructSchema schema) {
1790 1791
  KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1792
  return DynamicStruct::Reader(schema, reader.getStruct(nullptr));
Kenton Varda's avatar
Kenton Varda committed
1793
}
1794
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
1795
    PointerBuilder builder, StructSchema schema) {
1796 1797
  KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1798
  return DynamicStruct::Builder(schema, builder.getStruct(
1799
      structSizeFromSchema(schema), nullptr));
Kenton Varda's avatar
Kenton Varda committed
1800
}
1801
void PointerHelpers<DynamicStruct, Kind::OTHER>::set(
1802
    PointerBuilder builder, const DynamicStruct::Reader& value) {
1803 1804
  KJ_REQUIRE(!value.schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1805
  builder.setStruct(value.reader);
Kenton Varda's avatar
Kenton Varda committed
1806
}
1807
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::init(
1808
    PointerBuilder builder, StructSchema schema) {
1809 1810
  KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1811
  return DynamicStruct::Builder(schema,
1812
      builder.initStruct(structSizeFromSchema(schema)));
Kenton Varda's avatar
Kenton Varda committed
1813 1814
}

1815
DynamicList::Reader PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
1816
    PointerReader reader, ListSchema schema) {
1817
  return DynamicList::Reader(schema,
1818
      reader.getList(elementSizeFor(schema.whichElementType()), nullptr));
Kenton Varda's avatar
Kenton Varda committed
1819
}
1820
DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
1821
    PointerBuilder builder, ListSchema schema) {
Kenton Varda's avatar
Kenton Varda committed
1822
  if (schema.whichElementType() == schema::Type::STRUCT) {
1823
    return DynamicList::Builder(schema,
1824
        builder.getStructList(
1825 1826 1827 1828
            structSizeFromSchema(schema.getStructElementType()),
            nullptr));
  } else {
    return DynamicList::Builder(schema,
1829
        builder.getList(elementSizeFor(schema.whichElementType()), nullptr));
1830
  }
Kenton Varda's avatar
Kenton Varda committed
1831
}
1832
void PointerHelpers<DynamicList, Kind::OTHER>::set(
1833 1834
    PointerBuilder builder, const DynamicList::Reader& value) {
  builder.setList(value.reader);
Kenton Varda's avatar
Kenton Varda committed
1835
}
1836
DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::init(
1837
    PointerBuilder builder, ListSchema schema, uint size) {
Kenton Varda's avatar
Kenton Varda committed
1838
  if (schema.whichElementType() == schema::Type::STRUCT) {
1839
    return DynamicList::Builder(schema,
1840
        builder.initStructList(size * ELEMENTS,
1841
            structSizeFromSchema(schema.getStructElementType())));
Kenton Varda's avatar
Kenton Varda committed
1842
  } else {
1843
    return DynamicList::Builder(schema,
1844
        builder.initList(elementSizeFor(schema.whichElementType()), size * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1845 1846 1847
  }
}

1848
DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
1849 1850 1851
    PointerReader reader, InterfaceSchema schema) {
  return DynamicCapability::Client(schema, reader.getCapability());
}
1852
DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
1853 1854 1855
    PointerBuilder builder, InterfaceSchema schema) {
  return DynamicCapability::Client(schema, builder.getCapability());
}
1856
void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
1857
    PointerBuilder builder, DynamicCapability::Client& value) {
1858 1859
  builder.setCapability(value.hook->addRef());
}
1860
void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
1861 1862 1863 1864
    PointerBuilder builder, DynamicCapability::Client&& value) {
  builder.setCapability(kj::mv(value.hook));
}

1865
}  // namespace _ (private)
Kenton Varda's avatar
Kenton Varda committed
1866

1867
template <>
1868
void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan) {
1869 1870 1871 1872 1873 1874 1875 1876
  switch (orphan.getType()) {
    case DynamicValue::UNKNOWN:
    case DynamicValue::VOID:
    case DynamicValue::BOOL:
    case DynamicValue::INT:
    case DynamicValue::UINT:
    case DynamicValue::FLOAT:
    case DynamicValue::ENUM:
1877
      KJ_FAIL_REQUIRE("AnyPointer cannot adopt primitive (non-object) value.");
1878 1879 1880 1881 1882

    case DynamicValue::STRUCT:
    case DynamicValue::LIST:
    case DynamicValue::TEXT:
    case DynamicValue::DATA:
1883
    case DynamicValue::CAPABILITY:
1884
    case DynamicValue::ANY_POINTER:
1885 1886 1887 1888 1889
      builder.adopt(kj::mv(orphan.builder));
      break;
  }
}

1890
template <>
1891
DynamicStruct::Builder Orphan<AnyPointer>::getAs<DynamicStruct>(StructSchema schema) {
1892 1893 1894
  return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema)));
}
template <>
1895
DynamicStruct::Reader Orphan<AnyPointer>::getAsReader<DynamicStruct>(StructSchema schema) const {
1896 1897 1898
  return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
}
template <>
1899
Orphan<DynamicStruct> Orphan<AnyPointer>::releaseAs<DynamicStruct>(StructSchema schema) {
1900 1901 1902 1903
  return Orphan<DynamicStruct>(schema, kj::mv(builder));
}

template <>
1904
DynamicList::Builder Orphan<AnyPointer>::getAs<DynamicList>(ListSchema schema) {
1905 1906 1907 1908 1909 1910 1911 1912
  if (schema.whichElementType() == schema::Type::STRUCT) {
    return DynamicList::Builder(schema, builder.asStructList(
        structSizeFromSchema(schema.getStructElementType())));
  } else {
    return DynamicList::Builder(schema, builder.asList(elementSizeFor(schema.whichElementType())));
  }
}
template <>
1913
DynamicList::Reader Orphan<AnyPointer>::getAsReader<DynamicList>(ListSchema schema) const {
1914 1915 1916 1917
  return DynamicList::Reader(schema, builder.asListReader(
      elementSizeFor(schema.whichElementType())));
}
template <>
1918
Orphan<DynamicList> Orphan<AnyPointer>::releaseAs<DynamicList>(ListSchema schema) {
1919 1920 1921
  return Orphan<DynamicList>(schema, kj::mv(builder));
}

1922
template <>
1923
DynamicCapability::Client Orphan<AnyPointer>::getAs<DynamicCapability>(InterfaceSchema schema) {
1924 1925 1926
  return DynamicCapability::Client(schema, builder.asCapability());
}
template <>
1927
DynamicCapability::Client Orphan<AnyPointer>::getAsReader<DynamicCapability>(
1928 1929 1930 1931
    InterfaceSchema schema) const {
  return DynamicCapability::Client(schema, builder.asCapability());
}
template <>
1932
Orphan<DynamicCapability> Orphan<AnyPointer>::releaseAs<DynamicCapability>(
1933 1934 1935 1936
    InterfaceSchema schema) {
  return Orphan<DynamicCapability>(schema, kj::mv(builder));
}

1937 1938
// -------------------------------------------------------------------

1939
Orphan<DynamicStruct> Orphanage::newOrphan(StructSchema schema) const {
1940 1941 1942 1943
  return Orphan<DynamicStruct>(
      schema, _::OrphanBuilder::initStruct(arena, structSizeFromSchema(schema)));
}

1944
Orphan<DynamicList> Orphanage::newOrphan(ListSchema schema, uint size) const {
Kenton Varda's avatar
Kenton Varda committed
1945
  if (schema.whichElementType() == schema::Type::STRUCT) {
1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957
    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)));
}

1958 1959 1960 1961
DynamicStruct::Reader Orphan<DynamicStruct>::getReader() const {
  return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
}

1962
DynamicList::Builder Orphan<DynamicList>::get() {
Kenton Varda's avatar
Kenton Varda committed
1963
  if (schema.whichElementType() == schema::Type::STRUCT) {
1964 1965 1966 1967 1968 1969 1970 1971
    return DynamicList::Builder(
        schema, builder.asStructList(structSizeFromSchema(schema.getStructElementType())));
  } else {
    return DynamicList::Builder(
        schema, builder.asList(elementSizeFor(schema.whichElementType())));
  }
}

1972 1973 1974 1975 1976
DynamicList::Reader Orphan<DynamicList>::getReader() const {
  return DynamicList::Reader(
      schema, builder.asListReader(elementSizeFor(schema.whichElementType())));
}

1977 1978 1979 1980 1981 1982 1983 1984
DynamicCapability::Client Orphan<DynamicCapability>::get() {
  return DynamicCapability::Client(schema, builder.asCapability());
}

DynamicCapability::Client Orphan<DynamicCapability>::getReader() const {
  return DynamicCapability::Client(schema, builder.asCapability());
}

1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999
Orphan<DynamicValue>::Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder)
    : type(value.getType()), builder(kj::mv(builder)) {
  switch (type) {
    case DynamicValue::UNKNOWN: break;
    case DynamicValue::VOID: voidValue = value.voidValue; break;
    case DynamicValue::BOOL: boolValue = value.boolValue; break;
    case DynamicValue::INT: intValue = value.intValue; break;
    case DynamicValue::UINT: uintValue = value.uintValue; break;
    case DynamicValue::FLOAT: floatValue = value.floatValue; break;
    case DynamicValue::ENUM: enumValue = value.enumValue; break;

    case DynamicValue::TEXT: break;
    case DynamicValue::DATA: break;
    case DynamicValue::LIST: listSchema = value.listValue.getSchema(); break;
    case DynamicValue::STRUCT: structSchema = value.structValue.getSchema(); break;
2000
    case DynamicValue::CAPABILITY: interfaceSchema = value.capabilityValue.getSchema(); break;
2001
    case DynamicValue::ANY_POINTER: break;
2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027
  }
}

DynamicValue::Builder Orphan<DynamicValue>::get() {
  switch (type) {
    case DynamicValue::UNKNOWN: return nullptr;
    case DynamicValue::VOID: return voidValue;
    case DynamicValue::BOOL: return boolValue;
    case DynamicValue::INT: return intValue;
    case DynamicValue::UINT: return uintValue;
    case DynamicValue::FLOAT: return floatValue;
    case DynamicValue::ENUM: return enumValue;

    case DynamicValue::TEXT: return builder.asText();
    case DynamicValue::DATA: return builder.asData();
    case DynamicValue::LIST:
      if (listSchema.whichElementType() == schema::Type::STRUCT) {
        return DynamicList::Builder(listSchema,
            builder.asStructList(structSizeFromSchema(listSchema.getStructElementType())));
      } else {
        return DynamicList::Builder(listSchema,
            builder.asList(elementSizeFor(listSchema.whichElementType())));
      }
    case DynamicValue::STRUCT:
      return DynamicStruct::Builder(structSchema,
          builder.asStruct(structSizeFromSchema(structSchema)));
2028 2029
    case DynamicValue::CAPABILITY:
      return DynamicCapability::Client(interfaceSchema, builder.asCapability());
2030 2031 2032
    case DynamicValue::ANY_POINTER:
      KJ_FAIL_REQUIRE("Can't get() an AnyPointer orphan; there is no underlying pointer to "
                      "wrap in an AnyPointer::Builder.");
2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053
  }
  KJ_UNREACHABLE;
}
DynamicValue::Reader Orphan<DynamicValue>::getReader() const {
  switch (type) {
    case DynamicValue::UNKNOWN: return nullptr;
    case DynamicValue::VOID: return voidValue;
    case DynamicValue::BOOL: return boolValue;
    case DynamicValue::INT: return intValue;
    case DynamicValue::UINT: return uintValue;
    case DynamicValue::FLOAT: return floatValue;
    case DynamicValue::ENUM: return enumValue;

    case DynamicValue::TEXT: return builder.asTextReader();
    case DynamicValue::DATA: return builder.asDataReader();
    case DynamicValue::LIST:
      return DynamicList::Reader(listSchema,
          builder.asListReader(elementSizeFor(listSchema.whichElementType())));
    case DynamicValue::STRUCT:
      return DynamicStruct::Reader(structSchema,
          builder.asStructReader(structSizeFromSchema(structSchema)));
2054 2055
    case DynamicValue::CAPABILITY:
      return DynamicCapability::Client(interfaceSchema, builder.asCapability());
2056 2057 2058
    case DynamicValue::ANY_POINTER:
      KJ_FAIL_ASSERT("Can't get() an AnyPointer orphan; there is no underlying pointer to "
                     "wrap in an AnyPointer::Builder.");
2059 2060 2061 2062
  }
  KJ_UNREACHABLE;
}

2063
template <>
2064 2065
Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>() {
  KJ_REQUIRE(type == DynamicValue::ANY_POINTER, "Value type mismatch.");
2066
  type = DynamicValue::UNKNOWN;
2067
  return Orphan<AnyPointer>(kj::mv(builder));
2068
}
2069 2070 2071
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>() {
  KJ_REQUIRE(type == DynamicValue::STRUCT, "Value type mismatch.");
2072
  type = DynamicValue::UNKNOWN;
2073 2074 2075 2076 2077
  return Orphan<DynamicStruct>(structSchema, kj::mv(builder));
}
template <>
Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>() {
  KJ_REQUIRE(type == DynamicValue::LIST, "Value type mismatch.");
2078
  type = DynamicValue::UNKNOWN;
2079 2080 2081
  return Orphan<DynamicList>(listSchema, kj::mv(builder));
}

2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
    const DynamicValue::Reader& copyFrom) const {
  switch (copyFrom.getType()) {
    case DynamicValue::UNKNOWN: return nullptr;
    case DynamicValue::VOID: return copyFrom.voidValue;
    case DynamicValue::BOOL: return copyFrom.boolValue;
    case DynamicValue::INT: return copyFrom.intValue;
    case DynamicValue::UINT: return copyFrom.uintValue;
    case DynamicValue::FLOAT: return copyFrom.floatValue;
    case DynamicValue::ENUM: return copyFrom.enumValue;

    case DynamicValue::TEXT: return newOrphanCopy(copyFrom.textValue);
    case DynamicValue::DATA: return newOrphanCopy(copyFrom.dataValue);
    case DynamicValue::LIST: return newOrphanCopy(copyFrom.listValue);
    case DynamicValue::STRUCT: return newOrphanCopy(copyFrom.structValue);
2098
    case DynamicValue::CAPABILITY: return newOrphanCopy(copyFrom.capabilityValue);
2099
    case DynamicValue::ANY_POINTER: return newOrphanCopy(copyFrom.anyPointerValue);
2100 2101 2102 2103
  }
  KJ_UNREACHABLE;
}

2104
}  // namespace capnp