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

#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 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
        case schema::Type::ANY_POINTER: {
          auto target = AnyPointer::Builder(builder.getPointerField(slot.getOffset() * POINTERS));

          switch (value.getType()) {
            case DynamicValue::Type::TEXT:
              target.setAs<Text>(value.as<Text>());
              return;
            case DynamicValue::Type::DATA:
              target.setAs<Data>(value.as<Data>());
              return;
            case DynamicValue::Type::LIST:
              target.setAs<DynamicList>(value.as<DynamicList>());
              return;
            case DynamicValue::Type::STRUCT:
              target.setAs<DynamicStruct>(value.as<DynamicStruct>());
              return;
            case DynamicValue::Type::CAPABILITY:
              target.setAs<DynamicCapability>(value.as<DynamicCapability>());
              return;
            case DynamicValue::Type::ANY_POINTER:
              target.set(value.as<AnyPointer>());
              return;

            case DynamicValue::Type::UNKNOWN:
            case DynamicValue::Type::VOID:
            case DynamicValue::Type::BOOL:
            case DynamicValue::Type::INT:
            case DynamicValue::Type::UINT:
            case DynamicValue::Type::FLOAT:
            case DynamicValue::Type::ENUM:
              KJ_FAIL_ASSERT("Value type mismatch; expected AnyPointer");
          }

          KJ_UNREACHABLE;
        }
596

597
        case schema::Type::INTERFACE: {
598
          auto interfaceType = type.asInterface();
599 600 601 602 603 604
          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));
605
          return;
606
        }
607
      }
Kenton Varda's avatar
Kenton Varda committed
608

Kenton Varda's avatar
Kenton Varda committed
609 610 611
      KJ_UNREACHABLE;
    }

Kenton Varda's avatar
Kenton Varda committed
612
    case schema::Field::GROUP: {
Kenton Varda's avatar
Kenton Varda committed
613 614 615 616 617 618 619 620 621 622 623
      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));
        }
624
      }
Kenton Varda's avatar
Kenton Varda committed
625
    }
626
  }
Kenton Varda's avatar
Kenton Varda committed
627

Kenton Varda's avatar
Kenton Varda committed
628
  KJ_UNREACHABLE;
629
}
Kenton Varda's avatar
Kenton Varda committed
630

Kenton Varda's avatar
Kenton Varda committed
631 632 633 634 635
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();
636
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
637 638

  switch (proto.which()) {
639 640
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
641 642
      switch (type.which()) {
        case schema::Type::STRUCT: {
643
          auto subSchema = type.asStruct();
644 645 646 647
          return DynamicStruct::Builder(subSchema,
              builder.getPointerField(slot.getOffset() * POINTERS)
                     .initStruct(structSizeFromSchema(subSchema)));
        }
648
        case schema::Type::ANY_POINTER: {
649 650
          auto pointer = builder.getPointerField(slot.getOffset() * POINTERS);
          pointer.clear();
651
          return AnyPointer::Builder(pointer);
652 653 654 655
        }
        default:
          KJ_FAIL_REQUIRE("init() without a size is only valid for struct and object fields.");
      }
Kenton Varda's avatar
Kenton Varda committed
656 657
    }

Kenton Varda's avatar
Kenton Varda committed
658
    case schema::Field::GROUP: {
Kenton Varda's avatar
Kenton Varda committed
659
      clear(field);
660
      return DynamicStruct::Builder(type.asStruct(), builder);
Kenton Varda's avatar
Kenton Varda committed
661 662 663 664 665
    }
  }

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

Kenton Varda's avatar
Kenton Varda committed
667 668 669 670 671
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();
672
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
673 674

  switch (proto.which()) {
675 676
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
677
      switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
678
        case schema::Type::LIST: {
679
          auto listType = type.asList();
Kenton Varda's avatar
Kenton Varda committed
680
          if (listType.whichElementType() == schema::Type::STRUCT) {
Kenton Varda's avatar
Kenton Varda committed
681
            return DynamicList::Builder(listType,
682 683 684
                builder.getPointerField(slot.getOffset() * POINTERS)
                       .initStructList(size * ELEMENTS,
                                       structSizeFromSchema(listType.getStructElementType())));
Kenton Varda's avatar
Kenton Varda committed
685 686
          } else {
            return DynamicList::Builder(listType,
687 688
                builder.getPointerField(slot.getOffset() * POINTERS)
                       .initList(elementSizeFor(listType.whichElementType()), size * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
689 690
          }
        }
Kenton Varda's avatar
Kenton Varda committed
691
        case schema::Type::TEXT:
692 693
          return builder.getPointerField(slot.getOffset() * POINTERS)
                        .initBlob<Text>(size * BYTES);
Kenton Varda's avatar
Kenton Varda committed
694
        case schema::Type::DATA:
695 696
          return builder.getPointerField(slot.getOffset() * POINTERS)
                        .initBlob<Data>(size * BYTES);
697
        default:
698
          KJ_FAIL_REQUIRE(
699 700
              "init() with size is only valid for list, text, or data fields.",
              (uint)type.which());
701 702
          break;
      }
703
    }
Kenton Varda's avatar
Kenton Varda committed
704

Kenton Varda's avatar
Kenton Varda committed
705
    case schema::Field::GROUP:
Kenton Varda's avatar
Kenton Varda committed
706
      KJ_FAIL_REQUIRE("init() with size is only valid for list, text, or data fields.");
Kenton Varda's avatar
Kenton Varda committed
707 708
  }

Kenton Varda's avatar
Kenton Varda committed
709
  KJ_UNREACHABLE;
Kenton Varda's avatar
Kenton Varda committed
710 711
}

712 713 714 715 716 717
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()) {
718 719
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
720
      auto type = field.getType();
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739

      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:
740
          KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch.");
741 742 743
          break;

        case schema::Type::DATA:
744
          KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
745 746 747
          break;

        case schema::Type::LIST: {
748
          ListSchema listType = type.asList();
749
          KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == listType,
750 751 752
                     "Value type mismatch.") {
            return;
          }
753 754 755 756
          break;
        }

        case schema::Type::STRUCT: {
757
          auto structType = type.asStruct();
758
          KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == structType,
759 760 761
                     "Value type mismatch.") {
            return;
          }
762 763 764
          break;
        }

765
        case schema::Type::ANY_POINTER:
766 767
          KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT ||
                     orphan.getType() == DynamicValue::LIST ||
768 769
                     orphan.getType() == DynamicValue::TEXT ||
                     orphan.getType() == DynamicValue::DATA ||
770
                     orphan.getType() == DynamicValue::CAPABILITY ||
771
                     orphan.getType() == DynamicValue::ANY_POINTER,
772 773 774
                     "Value type mismatch.") {
            return;
          }
775 776
          break;

777
        case schema::Type::INTERFACE: {
778
          auto interfaceType = type.asInterface();
779 780 781 782 783
          KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY &&
                     orphan.interfaceSchema.extends(interfaceType),
                     "Value type mismatch.") {
            return;
          }
784
          break;
785
        }
786 787
      }

788
      builder.getPointerField(slot.getOffset() * POINTERS).adopt(kj::mv(orphan.builder));
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
      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()) {
821 822
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
823

824
      switch (field.getType().which()) {
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
        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:
847
        case schema::Type::ANY_POINTER:
848 849
        case schema::Type::INTERFACE: {
          auto value = get(field);
850 851
          return Orphan<DynamicValue>(
              value, builder.getPointerField(slot.getOffset() * POINTERS).disown());
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
        }
      }
      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
886 887 888 889 890 891

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();
892
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
893
  switch (proto.which()) {
894 895
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
Kenton Varda's avatar
Kenton Varda committed
896 897

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

#define HANDLE_TYPE(discrim, type) \
Kenton Varda's avatar
Kenton Varda committed
903
        case schema::Type::discrim: \
904
          builder.setDataField<type>(slot.getOffset() * ELEMENTS, 0); \
Kenton Varda's avatar
Kenton Varda committed
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
          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
922 923 924 925
        case schema::Type::TEXT:
        case schema::Type::DATA:
        case schema::Type::LIST:
        case schema::Type::STRUCT:
926
        case schema::Type::ANY_POINTER:
Kenton Varda's avatar
Kenton Varda committed
927
        case schema::Type::INTERFACE:
928
          builder.getPointerField(slot.getOffset() * POINTERS).clear();
Kenton Varda's avatar
Kenton Varda committed
929 930 931 932 933 934
          return;
      }

      KJ_UNREACHABLE;
    }

Kenton Varda's avatar
Kenton Varda committed
935
    case schema::Field::GROUP: {
936
      DynamicStruct::Builder group(type.asStruct(), builder);
937 938 939

      // 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
940 941 942
      KJ_IF_MAYBE(unionField, group.schema.getFieldByDiscriminant(0)) {
        group.clear(*unionField);
      }
943

Kenton Varda's avatar
Kenton Varda committed
944 945 946
      for (auto subField: group.schema.getNonUnionFields()) {
        group.clear(subField);
      }
947
      return;
Kenton Varda's avatar
Kenton Varda committed
948 949
    }
  }
950

Kenton Varda's avatar
Kenton Varda committed
951 952 953 954 955 956 957 958 959
  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));
}
960
DynamicValue::Pipeline DynamicStruct::Pipeline::get(kj::StringPtr name) {
961 962
  return get(schema.getFieldByName(name));
}
Kenton Varda's avatar
Kenton Varda committed
963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
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);
}
986 987 988 989 990 991
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
992
void DynamicStruct::Builder::clear(kj::StringPtr name) {
993
  clear(schema.getFieldByName(name));
Kenton Varda's avatar
Kenton Varda committed
994
}
Kenton Varda's avatar
Kenton Varda committed
995 996 997

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

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

1001
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1002
#define HANDLE_TYPE(name, discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1003
    case schema::Type::discrim: \
1004
      return reader.getDataElement<typeName>(index * ELEMENTS);
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017

    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
1018 1019
#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
1020
    case schema::Type::TEXT:
1021
      return reader.getPointerElement(index * ELEMENTS).getBlob<Text>(nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
1022
    case schema::Type::DATA:
1023
      return reader.getPointerElement(index * ELEMENTS).getBlob<Data>(nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
1024

Kenton Varda's avatar
Kenton Varda committed
1025
    case schema::Type::LIST: {
1026
      auto elementType = schema.getListElementType();
1027 1028 1029
      return DynamicList::Reader(elementType,
          reader.getPointerElement(index * ELEMENTS)
                .getList(elementSizeFor(elementType.whichElementType()), nullptr));
1030
    }
Kenton Varda's avatar
Kenton Varda committed
1031

Kenton Varda's avatar
Kenton Varda committed
1032
    case schema::Type::STRUCT:
1033 1034
      return DynamicStruct::Reader(schema.getStructElementType(),
                                   reader.getStructElement(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1035

Kenton Varda's avatar
Kenton Varda committed
1036
    case schema::Type::ENUM:
1037 1038
      return DynamicEnum(schema.getEnumElementType(),
                         reader.getDataElement<uint16_t>(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1039

1040 1041
    case schema::Type::ANY_POINTER:
      return AnyPointer::Reader(reader.getPointerElement(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1042

Kenton Varda's avatar
Kenton Varda committed
1043
    case schema::Type::INTERFACE:
1044 1045
      return DynamicCapability::Client(schema.getInterfaceElementType(),
                                       reader.getPointerElement(index * ELEMENTS).getCapability());
Kenton Varda's avatar
Kenton Varda committed
1046
  }
1047

1048
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1049 1050
}

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

1054
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1055
#define HANDLE_TYPE(name, discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1056
    case schema::Type::discrim: \
1057
      return builder.getDataElement<typeName>(index * ELEMENTS);
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070

    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
1071 1072
#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
1073
    case schema::Type::TEXT:
1074
      return builder.getPointerElement(index * ELEMENTS).getBlob<Text>(nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
1075
    case schema::Type::DATA:
1076
      return builder.getPointerElement(index * ELEMENTS).getBlob<Data>(nullptr, 0 * BYTES);
Kenton Varda's avatar
Kenton Varda committed
1077

Kenton Varda's avatar
Kenton Varda committed
1078
    case schema::Type::LIST: {
1079
      ListSchema elementType = schema.getListElementType();
Kenton Varda's avatar
Kenton Varda committed
1080
      if (elementType.whichElementType() == schema::Type::STRUCT) {
1081
        return DynamicList::Builder(elementType,
1082 1083 1084
            builder.getPointerElement(index * ELEMENTS)
                   .getStructList(structSizeFromSchema(elementType.getStructElementType()),
                                  nullptr));
1085
      } else {
1086
        return DynamicList::Builder(elementType,
1087 1088
            builder.getPointerElement(index * ELEMENTS)
                   .getList(elementSizeFor(elementType.whichElementType()), nullptr));
1089 1090
      }
    }
Kenton Varda's avatar
Kenton Varda committed
1091

Kenton Varda's avatar
Kenton Varda committed
1092
    case schema::Type::STRUCT:
1093 1094
      return DynamicStruct::Builder(schema.getStructElementType(),
                                    builder.getStructElement(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1095

Kenton Varda's avatar
Kenton Varda committed
1096
    case schema::Type::ENUM:
1097 1098
      return DynamicEnum(schema.getEnumElementType(),
                         builder.getDataElement<uint16_t>(index * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1099

1100 1101
    case schema::Type::ANY_POINTER:
      KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
1102
      return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1103

Kenton Varda's avatar
Kenton Varda committed
1104
    case schema::Type::INTERFACE:
1105 1106
      return DynamicCapability::Client(schema.getInterfaceElementType(),
                                       builder.getPointerElement(index * ELEMENTS).getCapability());
Kenton Varda's avatar
Kenton Varda committed
1107
  }
1108

1109
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1110 1111
}

1112
void DynamicList::Builder::set(uint index, const DynamicValue::Reader& value) {
1113
  KJ_REQUIRE(index < size(), "List index out-of-bounds.") {
1114 1115
    return;
  }
Kenton Varda's avatar
Kenton Varda committed
1116

1117
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1118
#define HANDLE_TYPE(name, discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1119
    case schema::Type::discrim: \
1120
      builder.setDataElement<typeName>(index * ELEMENTS, value.as<typeName>()); \
1121
      return;
Kenton Varda's avatar
Kenton Varda committed
1122

1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
    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
1135 1136
#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
1137
    case schema::Type::TEXT:
1138
      builder.getPointerElement(index * ELEMENTS).setBlob<Text>(value.as<Text>());
1139
      return;
Kenton Varda's avatar
Kenton Varda committed
1140
    case schema::Type::DATA:
1141
      builder.getPointerElement(index * ELEMENTS).setBlob<Data>(value.as<Data>());
1142
      return;
Kenton Varda's avatar
Kenton Varda committed
1143

Kenton Varda's avatar
Kenton Varda committed
1144
    case schema::Type::LIST: {
1145 1146 1147 1148
      auto listValue = value.as<DynamicList>();
      KJ_REQUIRE(listValue.getSchema() == schema.getListElementType(), "Value type mismatch.") {
        return;
      }
1149
      builder.getPointerElement(index * ELEMENTS).setList(listValue.reader);
1150
      return;
1151
    }
Kenton Varda's avatar
Kenton Varda committed
1152

1153
    case schema::Type::STRUCT: {
1154 1155 1156 1157 1158
      auto structValue = value.as<DynamicStruct>();
      KJ_REQUIRE(structValue.getSchema() == schema.getStructElementType(), "Value type mismatch.") {
        return;
      }
      builder.getStructElement(index * ELEMENTS).copyContentFrom(structValue.reader);
1159 1160
      return;
    }
Kenton Varda's avatar
Kenton Varda committed
1161

Kenton Varda's avatar
Kenton Varda committed
1162
    case schema::Type::ENUM: {
1163 1164 1165 1166 1167 1168
      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>();
1169 1170
        KJ_REQUIRE(schema.getEnumElementType() == enumValue.getSchema(),
                   "Type mismatch when using DynamicList::Builder::set().") {
1171 1172 1173
          return;
        }
        rawValue = enumValue.getRaw();
1174
      }
1175
      builder.setDataElement<uint16_t>(index * ELEMENTS, rawValue);
1176
      return;
1177
    }
Kenton Varda's avatar
Kenton Varda committed
1178

1179 1180
    case schema::Type::ANY_POINTER:
      KJ_FAIL_ASSERT("List(AnyPointer) not supported.") {
1181 1182
        return;
      }
Kenton Varda's avatar
Kenton Varda committed
1183

1184 1185 1186 1187
    case schema::Type::INTERFACE: {
      auto capValue = value.as<DynamicCapability>();
      KJ_REQUIRE(capValue.getSchema().extends(schema.getInterfaceElementType()),
                 "Value type mismatch.") {
1188 1189
        return;
      }
1190 1191 1192
      builder.getPointerElement(index * ELEMENTS).setCapability(kj::mv(capValue.hook));
      return;
    }
Kenton Varda's avatar
Kenton Varda committed
1193
  }
1194

1195 1196 1197
  KJ_FAIL_REQUIRE("can't set element of unknown type", (uint)schema.whichElementType()) {
    return;
  }
Kenton Varda's avatar
Kenton Varda committed
1198 1199 1200
}

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

1203
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
    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:
1219
      KJ_FAIL_REQUIRE("Expected a list or blob.");
1220
      return nullptr;
1221

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

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

Kenton Varda's avatar
Kenton Varda committed
1228
    case schema::Type::LIST: {
1229 1230
      auto elementType = schema.getListElementType();

Kenton Varda's avatar
Kenton Varda committed
1231
      if (elementType.whichElementType() == schema::Type::STRUCT) {
1232 1233 1234 1235
        return DynamicList::Builder(elementType,
            builder.getPointerElement(index * ELEMENTS)
                   .initStructList(size * ELEMENTS,
                                   structSizeFromSchema(elementType.getStructElementType())));
1236
      } else {
1237 1238 1239
        return DynamicList::Builder(elementType,
            builder.getPointerElement(index * ELEMENTS)
                   .initList(elementSizeFor(elementType.whichElementType()), size * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1240 1241 1242
      }
    }

1243 1244
    case schema::Type::ANY_POINTER: {
      KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
1245
      return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1246 1247
    }
  }
1248

1249
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1250 1251
}

1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
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.");
1272
      builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(orphan.builder));
1273 1274 1275 1276
      return;

    case schema::Type::DATA:
      KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
1277
      builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(orphan.builder));
1278 1279 1280 1281 1282 1283
      return;

    case schema::Type::LIST: {
      ListSchema elementType = schema.getListElementType();
      KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == elementType,
                 "Value type mismatch.");
1284
      builder.getPointerElement(index * ELEMENTS).adopt(kj::mv(orphan.builder));
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
      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;
    }

1297 1298
    case schema::Type::ANY_POINTER:
      KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
1299

1300 1301 1302 1303 1304 1305 1306 1307
    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;
    }
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
  }

  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())) {
1330 1331 1332 1333 1334 1335 1336 1337 1338
        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:
1339 1340 1341 1342 1343 1344 1345 1346
          KJ_UNREACHABLE;
      }
      return kj::mv(result);
    }

    case schema::Type::TEXT:
    case schema::Type::DATA:
    case schema::Type::LIST:
1347
    case schema::Type::ANY_POINTER:
1348 1349
    case schema::Type::INTERFACE: {
      auto value = operator[](index);
1350
      return Orphan<DynamicValue>(value, builder.getPointerElement(index * ELEMENTS).disown());
1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
    }

    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;
}

1366
void DynamicList::Builder::copyFrom(std::initializer_list<DynamicValue::Reader> value) {
1367
  KJ_REQUIRE(value.size() == size(), "DynamicList::copyFrom() argument had different size.");
1368 1369 1370 1371 1372 1373
  uint i = 0;
  for (auto element: value) {
    set(i++, element);
  }
}

1374
DynamicList::Reader DynamicList::Builder::asReader() const {
1375
  return DynamicList::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
1376 1377
}

Kenton Varda's avatar
Kenton Varda committed
1378 1379
// =======================================================================================

Kenton Varda's avatar
Kenton Varda committed
1380
DynamicValue::Reader::Reader(ConstSchema constant): type(VOID) {
1381
  auto type = constant.getType();
1382
  auto value = constant.getProto().getConst().getValue();
1383
  switch (type.which()) {
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399
    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:
1400
      *this = DynamicEnum(type.asEnum(), value.getEnum());
1401 1402 1403
      break;

    case schema::Type::STRUCT:
1404
      *this = value.getStruct().getAs<DynamicStruct>(type.asStruct());
1405 1406 1407
      break;

    case schema::Type::LIST:
1408
      *this = value.getList().getAs<DynamicList>(type.asList());
1409 1410
      break;

1411 1412
    case schema::Type::ANY_POINTER:
      *this = value.getAnyPointer();
1413 1414 1415 1416 1417 1418 1419
      break;

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

1420
DynamicValue::Reader::Reader(const Reader& other) {
Kenton Varda's avatar
Kenton Varda committed
1421
  switch (other.type) {
1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432
    case UNKNOWN:
    case VOID:
    case BOOL:
    case INT:
    case UINT:
    case FLOAT:
    case TEXT:
    case DATA:
    case LIST:
    case ENUM:
    case STRUCT:
1433
    case ANY_POINTER:
1434 1435 1436 1437 1438 1439
      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>(),
1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
                    "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
1451 1452
DynamicValue::Reader::Reader(Reader&& other) noexcept {
  switch (other.type) {
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
    case UNKNOWN:
    case VOID:
    case BOOL:
    case INT:
    case UINT:
    case FLOAT:
    case TEXT:
    case DATA:
    case LIST:
    case ENUM:
    case STRUCT:
1464
    case ANY_POINTER:
1465 1466 1467 1468 1469 1470
      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>(),
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
                    "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
1482
DynamicValue::Reader::~Reader() noexcept(false) {
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503
  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
1504
  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
      // Unfortunately canMemcpy() doesn't work on these types due to the use of
1518 1519 1520 1521 1522 1523 1524
      // 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, other.capabilityValue);
      return;
  }

  memcpy(this, &other, sizeof(*this));
}
Kenton Varda's avatar
Kenton Varda committed
1537 1538
DynamicValue::Builder::Builder(Builder&& other) noexcept {
  switch (other.type) {
1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
    case UNKNOWN:
    case VOID:
    case BOOL:
    case INT:
    case UINT:
    case FLOAT:
    case TEXT:
    case DATA:
    case LIST:
    case ENUM:
    case STRUCT:
1550
    case ANY_POINTER:
1551 1552 1553 1554 1555 1556 1557 1558
      // 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) &&
1559
                    __has_trivial_destructor(AnyPointer::Builder),
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570
                    "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
1571
DynamicValue::Builder::~Builder() noexcept(false) {
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591
  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;
}

1592
DynamicValue::Reader DynamicValue::Builder::asReader() const {
Kenton Varda's avatar
Kenton Varda committed
1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604
  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());
1605
    case CAPABILITY: return Reader(capabilityValue);
1606
    case ANY_POINTER: return Reader(anyPointerValue.asReader());
Kenton Varda's avatar
Kenton Varda committed
1607
  }
1608
  KJ_FAIL_ASSERT("Missing switch case.");
Kenton Varda's avatar
Kenton Varda committed
1609 1610 1611
  return Reader();
}

1612
DynamicValue::Pipeline::Pipeline(Pipeline&& other) noexcept: type(other.type) {
1613 1614 1615 1616 1617
  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:
1618 1619
      KJ_LOG(ERROR, "Unexpected pipeline type.", (uint)type);
      type = UNKNOWN;
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638
      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;
  }
}

1639 1640 1641 1642
namespace {

template <typename T>
T signedToUnsigned(long long value) {
1643
  KJ_REQUIRE(value >= 0 && T(value) == value, "Value out-of-range for requested type.", value) {
1644
    // Use it anyway.
1645
    break;
1646 1647 1648 1649 1650 1651
  }
  return value;
}

template <>
uint64_t signedToUnsigned<uint64_t>(long long value) {
1652
  KJ_REQUIRE(value >= 0, "Value out-of-range for requested type.", value) {
1653
    // Use it anyway.
1654
    break;
1655 1656 1657 1658 1659 1660
  }
  return value;
}

template <typename T>
T unsignedToSigned(unsigned long long value) {
1661 1662
  KJ_REQUIRE(T(value) >= 0 && (unsigned long long)T(value) == value,
             "Value out-of-range for requested type.", value) {
1663
    // Use it anyway.
1664
    break;
1665 1666 1667 1668 1669 1670
  }
  return value;
}

template <>
int64_t unsignedToSigned<int64_t>(unsigned long long value) {
1671
  KJ_REQUIRE(int64_t(value) >= 0, "Value out-of-range for requested type.", value) {
1672
    // Use it anyway.
1673
    break;
1674 1675 1676 1677 1678 1679
  }
  return value;
}

template <typename T, typename U>
T checkRoundTrip(U value) {
1680
  KJ_REQUIRE(T(value) == value, "Value out-of-range for requested type.", value) {
1681
    // Use it anyway.
1682
    break;
1683 1684 1685 1686 1687 1688 1689
  }
  return value;
}

}  // namespace

#define HANDLE_NUMERIC_TYPE(typeName, ifInt, ifUint, ifFloat) \
1690
typeName DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
1691 1692 1693 1694 1695 1696 1697 1698
  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
1699
      KJ_FAIL_REQUIRE("Value type mismatch.") { \
1700
        return 0; \
1701
      } \
1702 1703
  } \
} \
1704
typeName DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
1705 1706 1707 1708 1709 1710 1711 1712
  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
1713
      KJ_FAIL_REQUIRE("Value type mismatch.") { \
1714
        return 0; \
1715
      } \
1716 1717 1718 1719 1720 1721
  } \
}

HANDLE_NUMERIC_TYPE(int8_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
HANDLE_NUMERIC_TYPE(int16_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
HANDLE_NUMERIC_TYPE(int32_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
1722
HANDLE_NUMERIC_TYPE(int64_t, kj::implicitCast, unsignedToSigned, checkRoundTrip)
1723 1724 1725
HANDLE_NUMERIC_TYPE(uint8_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
HANDLE_NUMERIC_TYPE(uint16_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
HANDLE_NUMERIC_TYPE(uint32_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
1726 1727 1728
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)
1729 1730 1731

#undef HANDLE_NUMERIC_TYPE

Kenton Varda's avatar
Kenton Varda committed
1732
#define HANDLE_TYPE(name, discrim, typeName) \
1733
ReaderFor<typeName> DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
Kenton Varda's avatar
Kenton Varda committed
1734
  KJ_REQUIRE(reader.type == discrim, "Value type mismatch.") { \
1735 1736
    return ReaderFor<typeName>(); \
  } \
Kenton Varda's avatar
Kenton Varda committed
1737 1738
  return reader.name##Value; \
} \
1739
BuilderFor<typeName> DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
1740
  KJ_REQUIRE(builder.type == discrim, "Value type mismatch."); \
Kenton Varda's avatar
Kenton Varda committed
1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
  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)
1751
HANDLE_TYPE(anyPointer, ANY_POINTER, AnyPointer)
Kenton Varda's avatar
Kenton Varda committed
1752 1753 1754

#undef HANDLE_TYPE

1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782
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);
}

1783 1784 1785
Data::Reader DynamicValue::Reader::AsImpl<Data>::apply(const Reader& reader) {
  if (reader.type == TEXT) {
    // Coerce text to data.
1786
    return reader.textValue.asBytes();
1787 1788 1789 1790 1791 1792 1793 1794 1795
  }
  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.
1796
    return builder.textValue.asBytes();
1797 1798 1799 1800 1801 1802 1803
  }
  KJ_REQUIRE(builder.type == DATA, "Value type mismatch.") {
    return BuilderFor<Data>();
  }
  return builder.dataValue;
}

Kenton Varda's avatar
Kenton Varda committed
1804
// As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
1805
Void DynamicValue::Reader::AsImpl<Void>::apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1806
  KJ_REQUIRE(reader.type == VOID, "Value type mismatch.") {
Kenton Varda's avatar
Kenton Varda committed
1807 1808 1809 1810
    return Void();
  }
  return reader.voidValue;
}
1811
Void DynamicValue::Builder::AsImpl<Void>::apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1812
  KJ_REQUIRE(builder.type == VOID, "Value type mismatch.") {
Kenton Varda's avatar
Kenton Varda committed
1813 1814 1815 1816 1817
    return Void();
  }
  return builder.voidValue;
}

Kenton Varda's avatar
Kenton Varda committed
1818 1819
// =======================================================================================

1820
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
1821

1822
DynamicStruct::Reader PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
1823
    PointerReader reader, StructSchema schema) {
1824 1825
  KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1826
  return DynamicStruct::Reader(schema, reader.getStruct(nullptr));
Kenton Varda's avatar
Kenton Varda committed
1827
}
1828
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
1829
    PointerBuilder builder, StructSchema schema) {
1830 1831
  KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1832
  return DynamicStruct::Builder(schema, builder.getStruct(
1833
      structSizeFromSchema(schema), nullptr));
Kenton Varda's avatar
Kenton Varda committed
1834
}
1835
void PointerHelpers<DynamicStruct, Kind::OTHER>::set(
1836
    PointerBuilder builder, const DynamicStruct::Reader& value) {
1837 1838
  KJ_REQUIRE(!value.schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1839
  builder.setStruct(value.reader);
Kenton Varda's avatar
Kenton Varda committed
1840
}
1841
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::init(
1842
    PointerBuilder builder, StructSchema schema) {
1843 1844
  KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1845
  return DynamicStruct::Builder(schema,
1846
      builder.initStruct(structSizeFromSchema(schema)));
Kenton Varda's avatar
Kenton Varda committed
1847 1848
}

1849
DynamicList::Reader PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
1850
    PointerReader reader, ListSchema schema) {
1851
  return DynamicList::Reader(schema,
1852
      reader.getList(elementSizeFor(schema.whichElementType()), nullptr));
Kenton Varda's avatar
Kenton Varda committed
1853
}
1854
DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
1855
    PointerBuilder builder, ListSchema schema) {
Kenton Varda's avatar
Kenton Varda committed
1856
  if (schema.whichElementType() == schema::Type::STRUCT) {
1857
    return DynamicList::Builder(schema,
1858
        builder.getStructList(
1859 1860 1861 1862
            structSizeFromSchema(schema.getStructElementType()),
            nullptr));
  } else {
    return DynamicList::Builder(schema,
1863
        builder.getList(elementSizeFor(schema.whichElementType()), nullptr));
1864
  }
Kenton Varda's avatar
Kenton Varda committed
1865
}
1866
void PointerHelpers<DynamicList, Kind::OTHER>::set(
1867 1868
    PointerBuilder builder, const DynamicList::Reader& value) {
  builder.setList(value.reader);
Kenton Varda's avatar
Kenton Varda committed
1869
}
1870
DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::init(
1871
    PointerBuilder builder, ListSchema schema, uint size) {
Kenton Varda's avatar
Kenton Varda committed
1872
  if (schema.whichElementType() == schema::Type::STRUCT) {
1873
    return DynamicList::Builder(schema,
1874
        builder.initStructList(size * ELEMENTS,
1875
            structSizeFromSchema(schema.getStructElementType())));
Kenton Varda's avatar
Kenton Varda committed
1876
  } else {
1877
    return DynamicList::Builder(schema,
1878
        builder.initList(elementSizeFor(schema.whichElementType()), size * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1879 1880 1881
  }
}

1882
DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
1883 1884 1885
    PointerReader reader, InterfaceSchema schema) {
  return DynamicCapability::Client(schema, reader.getCapability());
}
1886
DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
1887 1888 1889
    PointerBuilder builder, InterfaceSchema schema) {
  return DynamicCapability::Client(schema, builder.getCapability());
}
1890
void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
1891
    PointerBuilder builder, DynamicCapability::Client& value) {
1892 1893
  builder.setCapability(value.hook->addRef());
}
1894
void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
1895 1896 1897 1898
    PointerBuilder builder, DynamicCapability::Client&& value) {
  builder.setCapability(kj::mv(value.hook));
}

1899
}  // namespace _ (private)
Kenton Varda's avatar
Kenton Varda committed
1900

1901
template <>
1902
void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan) {
1903 1904 1905 1906 1907 1908 1909 1910
  switch (orphan.getType()) {
    case DynamicValue::UNKNOWN:
    case DynamicValue::VOID:
    case DynamicValue::BOOL:
    case DynamicValue::INT:
    case DynamicValue::UINT:
    case DynamicValue::FLOAT:
    case DynamicValue::ENUM:
1911
      KJ_FAIL_REQUIRE("AnyPointer cannot adopt primitive (non-object) value.");
1912 1913 1914 1915 1916

    case DynamicValue::STRUCT:
    case DynamicValue::LIST:
    case DynamicValue::TEXT:
    case DynamicValue::DATA:
1917
    case DynamicValue::CAPABILITY:
1918
    case DynamicValue::ANY_POINTER:
1919 1920 1921 1922 1923
      builder.adopt(kj::mv(orphan.builder));
      break;
  }
}

1924
template <>
1925
DynamicStruct::Builder Orphan<AnyPointer>::getAs<DynamicStruct>(StructSchema schema) {
1926 1927 1928
  return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema)));
}
template <>
1929
DynamicStruct::Reader Orphan<AnyPointer>::getAsReader<DynamicStruct>(StructSchema schema) const {
1930 1931 1932
  return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
}
template <>
1933
Orphan<DynamicStruct> Orphan<AnyPointer>::releaseAs<DynamicStruct>(StructSchema schema) {
1934 1935 1936 1937
  return Orphan<DynamicStruct>(schema, kj::mv(builder));
}

template <>
1938
DynamicList::Builder Orphan<AnyPointer>::getAs<DynamicList>(ListSchema schema) {
1939 1940 1941 1942 1943 1944 1945 1946
  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 <>
1947
DynamicList::Reader Orphan<AnyPointer>::getAsReader<DynamicList>(ListSchema schema) const {
1948 1949 1950 1951
  return DynamicList::Reader(schema, builder.asListReader(
      elementSizeFor(schema.whichElementType())));
}
template <>
1952
Orphan<DynamicList> Orphan<AnyPointer>::releaseAs<DynamicList>(ListSchema schema) {
1953 1954 1955
  return Orphan<DynamicList>(schema, kj::mv(builder));
}

1956
template <>
1957
DynamicCapability::Client Orphan<AnyPointer>::getAs<DynamicCapability>(InterfaceSchema schema) {
1958 1959 1960
  return DynamicCapability::Client(schema, builder.asCapability());
}
template <>
1961
DynamicCapability::Client Orphan<AnyPointer>::getAsReader<DynamicCapability>(
1962 1963 1964 1965
    InterfaceSchema schema) const {
  return DynamicCapability::Client(schema, builder.asCapability());
}
template <>
1966
Orphan<DynamicCapability> Orphan<AnyPointer>::releaseAs<DynamicCapability>(
1967 1968 1969 1970
    InterfaceSchema schema) {
  return Orphan<DynamicCapability>(schema, kj::mv(builder));
}

1971 1972
// -------------------------------------------------------------------

1973
Orphan<DynamicStruct> Orphanage::newOrphan(StructSchema schema) const {
1974
  return Orphan<DynamicStruct>(
1975
      schema, _::OrphanBuilder::initStruct(arena, capTable, structSizeFromSchema(schema)));
1976 1977
}

1978
Orphan<DynamicList> Orphanage::newOrphan(ListSchema schema, uint size) const {
Kenton Varda's avatar
Kenton Varda committed
1979
  if (schema.whichElementType() == schema::Type::STRUCT) {
1980
    return Orphan<DynamicList>(schema, _::OrphanBuilder::initStructList(
1981
        arena, capTable, size * ELEMENTS, structSizeFromSchema(schema.getStructElementType())));
1982 1983
  } else {
    return Orphan<DynamicList>(schema, _::OrphanBuilder::initList(
1984
        arena, capTable, size * ELEMENTS, elementSizeFor(schema.whichElementType())));
1985 1986 1987 1988 1989 1990 1991
  }
}

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

1992 1993 1994 1995
DynamicStruct::Reader Orphan<DynamicStruct>::getReader() const {
  return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
}

1996
DynamicList::Builder Orphan<DynamicList>::get() {
Kenton Varda's avatar
Kenton Varda committed
1997
  if (schema.whichElementType() == schema::Type::STRUCT) {
1998 1999 2000 2001 2002 2003 2004 2005
    return DynamicList::Builder(
        schema, builder.asStructList(structSizeFromSchema(schema.getStructElementType())));
  } else {
    return DynamicList::Builder(
        schema, builder.asList(elementSizeFor(schema.whichElementType())));
  }
}

2006 2007 2008 2009 2010
DynamicList::Reader Orphan<DynamicList>::getReader() const {
  return DynamicList::Reader(
      schema, builder.asListReader(elementSizeFor(schema.whichElementType())));
}

2011 2012 2013 2014 2015 2016 2017 2018
DynamicCapability::Client Orphan<DynamicCapability>::get() {
  return DynamicCapability::Client(schema, builder.asCapability());
}

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

2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033
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;
2034
    case DynamicValue::CAPABILITY: interfaceSchema = value.capabilityValue.getSchema(); break;
2035
    case DynamicValue::ANY_POINTER: break;
2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061
  }
}

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)));
2062 2063
    case DynamicValue::CAPABILITY:
      return DynamicCapability::Client(interfaceSchema, builder.asCapability());
2064 2065 2066
    case DynamicValue::ANY_POINTER:
      KJ_FAIL_REQUIRE("Can't get() an AnyPointer orphan; there is no underlying pointer to "
                      "wrap in an AnyPointer::Builder.");
2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087
  }
  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)));
2088 2089
    case DynamicValue::CAPABILITY:
      return DynamicCapability::Client(interfaceSchema, builder.asCapability());
2090 2091 2092
    case DynamicValue::ANY_POINTER:
      KJ_FAIL_ASSERT("Can't get() an AnyPointer orphan; there is no underlying pointer to "
                     "wrap in an AnyPointer::Builder.");
2093 2094 2095 2096
  }
  KJ_UNREACHABLE;
}

2097
template <>
2098 2099
Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>() {
  KJ_REQUIRE(type == DynamicValue::ANY_POINTER, "Value type mismatch.");
2100
  type = DynamicValue::UNKNOWN;
2101
  return Orphan<AnyPointer>(kj::mv(builder));
2102
}
2103 2104 2105
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>() {
  KJ_REQUIRE(type == DynamicValue::STRUCT, "Value type mismatch.");
2106
  type = DynamicValue::UNKNOWN;
2107 2108 2109 2110 2111
  return Orphan<DynamicStruct>(structSchema, kj::mv(builder));
}
template <>
Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>() {
  KJ_REQUIRE(type == DynamicValue::LIST, "Value type mismatch.");
2112
  type = DynamicValue::UNKNOWN;
2113 2114 2115
  return Orphan<DynamicList>(listSchema, kj::mv(builder));
}

2116 2117
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
2118
    DynamicValue::Reader copyFrom) const {
2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131
  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);
2132
    case DynamicValue::CAPABILITY: return newOrphanCopy(copyFrom.capabilityValue);
2133
    case DynamicValue::ANY_POINTER: return newOrphanCopy(copyFrom.anyPointerValue);
2134 2135 2136 2137
  }
  KJ_UNREACHABLE;
}

2138
}  // namespace capnp