dynamic.c++ 75.2 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 102
      bounded(node.getDataWordCount()) * WORDS,
      bounded(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
    uint16_t discrim = reader.getDataField<uint16_t>(
133
        assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()));
Kenton Varda's avatar
Kenton Varda committed
134
    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
    uint16_t discrim = builder.getDataField<uint16_t>(
150
        assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()));
Kenton Varda's avatar
Kenton Varda committed
151
    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>(
168
        assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()),
Kenton Varda's avatar
Kenton Varda committed
169
        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>(assumeDataOffset(slot.getOffset()));
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
              assumeDataOffset(slot.getOffset()), \
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>(assumeDataOffset(slot.getOffset()), 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 223
          return reader.getPointerField(assumePointerOffset(slot.getOffset()))
                       .getBlob<Text>(typedDval.begin(),
                           assumeMax<MAX_TEXT_SIZE>(typedDval.size()) * BYTES);
224 225
        }

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

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

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

247
        case schema::Type::ANY_POINTER:
248
          return AnyPointer::Reader(reader.getPointerField(assumePointerOffset(slot.getOffset())));
249

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

Kenton Varda's avatar
Kenton Varda committed
255
      KJ_UNREACHABLE;
Kenton Varda's avatar
Kenton Varda committed
256
    }
Kenton Varda's avatar
Kenton Varda committed
257

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

Kenton Varda's avatar
Kenton Varda committed
262
  KJ_UNREACHABLE;
Kenton Varda's avatar
Kenton Varda committed
263 264
}

Kenton Varda's avatar
Kenton Varda committed
265 266 267
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
268

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

      // 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.
279
      auto dval = slot.getDefaultValue();
280 281

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

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

        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
302 303 304

#undef HANDLE_TYPE

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

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

Kenton Varda's avatar
Kenton Varda committed
318
        case schema::Type::DATA: {
319
          Data::Reader typedDval = dval.isAnyPointer() ? Data::Reader() : dval.getData();
320 321 322
          return builder.getPointerField(assumePointerOffset(slot.getOffset()))
                        .getBlob<Data>(typedDval.begin(),
                            assumeBits<BLOB_SIZE_BITS>(typedDval.size()) * BYTES);
323 324
        }

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

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

351
        case schema::Type::ANY_POINTER:
352 353
          return AnyPointer::Builder(
              builder.getPointerField(assumePointerOffset(slot.getOffset())));
354

Kenton Varda's avatar
Kenton Varda committed
355
        case schema::Type::INTERFACE:
356
          return DynamicCapability::Client(type.asInterface(),
357
              builder.getPointerField(assumePointerOffset(slot.getOffset())).getCapability());
358
      }
Kenton Varda's avatar
Kenton Varda committed
359

Kenton Varda's avatar
Kenton Varda committed
360
      KJ_UNREACHABLE;
Kenton Varda's avatar
Kenton Varda committed
361
    }
Kenton Varda's avatar
Kenton Varda committed
362

Kenton Varda's avatar
Kenton Varda committed
363
    case schema::Field::GROUP:
364
      return DynamicStruct::Builder(type.asStruct(), builder);
Kenton Varda's avatar
Kenton Varda committed
365 366
  }

Kenton Varda's avatar
Kenton Varda committed
367
  KJ_UNREACHABLE;
Kenton Varda's avatar
Kenton Varda committed
368
}
Kenton Varda's avatar
Kenton Varda committed
369

370
DynamicValue::Pipeline DynamicStruct::Pipeline::get(StructSchema::Field field) {
371 372 373
  KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");

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

376 377
  auto type = field.getType();

378 379 380 381 382 383
  switch (proto.which()) {
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();

      switch (type.which()) {
        case schema::Type::STRUCT:
384
          return DynamicStruct::Pipeline(type.asStruct(),
385 386 387
              typeless.getPointerField(slot.getOffset()));

        case schema::Type::INTERFACE:
388
          return DynamicCapability::Client(type.asInterface(),
389 390
              typeless.getPointerField(slot.getOffset()).asCap());

391 392 393 394 395 396 397 398 399 400 401 402
        case schema::Type::ANY_POINTER:
          switch (type.whichAnyPointerKind()) {
            case schema::Type::AnyPointer::Unconstrained::STRUCT:
              return DynamicStruct::Pipeline(StructSchema(),
                  typeless.getPointerField(slot.getOffset()));
            case schema::Type::AnyPointer::Unconstrained::CAPABILITY:
              return DynamicCapability::Client(Capability::Client(
                  typeless.getPointerField(slot.getOffset()).asCap()));
            default:
              KJ_FAIL_REQUIRE("Can only pipeline on struct and interface fields.");
          }

403 404 405 406 407 408 409 410
        default:
          KJ_FAIL_REQUIRE("Can only pipeline on struct and interface fields.");
      }

      KJ_UNREACHABLE;
    }

    case schema::Field::GROUP:
411
      return DynamicStruct::Pipeline(type.asStruct(), typeless.noop());
412 413 414 415 416
  }

  KJ_UNREACHABLE;
}

417
bool DynamicStruct::Reader::has(StructSchema::Field field, HasMode mode) const {
Kenton Varda's avatar
Kenton Varda committed
418 419 420
  KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");

  auto proto = field.getProto();
421
  if (hasDiscriminantValue(proto)) {
Kenton Varda's avatar
Kenton Varda committed
422
    uint16_t discrim = reader.getDataField<uint16_t>(
423
        assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()));
Kenton Varda's avatar
Kenton Varda committed
424 425 426 427
    if (discrim != proto.getDiscriminantValue()) {
      // Field is not active in the union.
      return false;
    }
428
  }
Kenton Varda's avatar
Kenton Varda committed
429 430

  switch (proto.which()) {
431
    case schema::Field::SLOT:
Kenton Varda's avatar
Kenton Varda committed
432 433 434
      // Continue to below.
      break;

435 436
    case schema::Field::GROUP:
      return true;
Kenton Varda's avatar
Kenton Varda committed
437 438
  }

439
  auto slot = proto.getSlot();
440
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
441 442

  switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
443
    case schema::Type::VOID:
444 445 446
      // Void is always equal to the default.
      return mode == HasMode::NON_NULL;

447
    case schema::Type::BOOL:
448 449 450
      return mode == HasMode::NON_NULL ||
          reader.getDataField<bool>(assumeDataOffset(slot.getOffset()), 0) != 0;

451 452
    case schema::Type::INT8:
    case schema::Type::UINT8:
453 454 455 456
      return mode == HasMode::NON_NULL ||
          reader.getDataField<uint8_t>(assumeDataOffset(slot.getOffset()), 0) != 0;

    case schema::Type::INT16:
457
    case schema::Type::UINT16:
458 459 460 461 462
    case schema::Type::ENUM:
      return mode == HasMode::NON_NULL ||
          reader.getDataField<uint16_t>(assumeDataOffset(slot.getOffset()), 0) != 0;

    case schema::Type::INT32:
463 464
    case schema::Type::UINT32:
    case schema::Type::FLOAT32:
465 466 467 468 469
      return mode == HasMode::NON_NULL ||
          reader.getDataField<uint32_t>(assumeDataOffset(slot.getOffset()), 0) != 0;

    case schema::Type::INT64:
    case schema::Type::UINT64:
470
    case schema::Type::FLOAT64:
471 472
      return mode == HasMode::NON_NULL ||
          reader.getDataField<uint64_t>(assumeDataOffset(slot.getOffset()), 0) != 0;
Kenton Varda's avatar
Kenton Varda committed
473

Kenton Varda's avatar
Kenton Varda committed
474 475 476 477
    case schema::Type::TEXT:
    case schema::Type::DATA:
    case schema::Type::LIST:
    case schema::Type::STRUCT:
478
    case schema::Type::ANY_POINTER:
Kenton Varda's avatar
Kenton Varda committed
479
    case schema::Type::INTERFACE:
480
      return !reader.getPointerField(assumePointerOffset(slot.getOffset())).isNull();
Kenton Varda's avatar
Kenton Varda committed
481 482 483 484 485 486 487 488 489 490 491 492
  }

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

493 494
  uint16_t discrim = reader.getDataField<uint16_t>(
      assumeDataOffset(structProto.getDiscriminantOffset()));
Kenton Varda's avatar
Kenton Varda committed
495 496 497 498 499 500 501 502 503
  return schema.getFieldByDiscriminant(discrim);
}

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

504 505
  uint16_t discrim = builder.getDataField<uint16_t>(
      assumeDataOffset(structProto.getDiscriminantOffset()));
Kenton Varda's avatar
Kenton Varda committed
506 507 508 509 510 511 512 513
  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();
514
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
515
  switch (proto.which()) {
516 517 518
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
      auto dval = slot.getDefaultValue();
Kenton Varda's avatar
Kenton Varda committed
519

520
      switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
521
        case schema::Type::VOID:
522
          builder.setDataField<Void>(assumeDataOffset(slot.getOffset()), value.as<Void>());
523
          return;
Kenton Varda's avatar
Kenton Varda committed
524

525
#define HANDLE_TYPE(discrim, titleCase, type) \
Kenton Varda's avatar
Kenton Varda committed
526
        case schema::Type::discrim: \
527
          builder.setDataField<type>( \
528
              assumeDataOffset(slot.getOffset()), value.as<type>(), \
Kenton Varda's avatar
Kenton Varda committed
529
              bitCast<_::Mask<type> >(dval.get##titleCase())); \
530 531 532 533 534 535 536 537 538 539 540 541 542
          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
543 544 545

#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
546
        case schema::Type::ENUM: {
547
          uint16_t rawValue;
548
          auto enumSchema = type.asEnum();
549 550 551
          if (value.getType() == DynamicValue::TEXT) {
            // Convert from text.
            rawValue = enumSchema.getEnumerantByName(value.as<Text>()).getOrdinal();
552 553
          } else if (value.getType() == DynamicValue::INT ||
                     value.getType() == DynamicValue::UINT) {
554
            rawValue = value.as<uint16_t>();
Kenton Varda's avatar
Kenton Varda committed
555
          } else {
556
            DynamicEnum enumValue = value.as<DynamicEnum>();
557
            KJ_REQUIRE(enumValue.getSchema() == enumSchema, "Value type mismatch.") {
558 559 560 561
              return;
            }
            rawValue = enumValue.getRaw();
          }
562
          builder.setDataField<uint16_t>(assumeDataOffset(slot.getOffset()), rawValue,
Kenton Varda's avatar
Kenton Varda committed
563
                                         dval.getEnum());
564
          return;
565
        }
566

Kenton Varda's avatar
Kenton Varda committed
567
        case schema::Type::TEXT:
568 569
          builder.getPointerField(assumePointerOffset(slot.getOffset()))
                 .setBlob<Text>(value.as<Text>());
570 571
          return;

Kenton Varda's avatar
Kenton Varda committed
572
        case schema::Type::DATA:
573 574
          builder.getPointerField(assumePointerOffset(slot.getOffset()))
                 .setBlob<Data>(value.as<Data>());
575 576
          return;

577
        case schema::Type::LIST: {
578
          ListSchema listType = type.asList();
579 580 581 582
          auto listValue = value.as<DynamicList>();
          KJ_REQUIRE(listValue.getSchema() == listType, "Value type mismatch.") {
            return;
          }
583 584
          builder.getPointerField(assumePointerOffset(slot.getOffset()))
                 .setList(listValue.reader);
585
          return;
586
        }
587

588
        case schema::Type::STRUCT: {
589
          auto structType = type.asStruct();
590 591 592 593
          auto structValue = value.as<DynamicStruct>();
          KJ_REQUIRE(structValue.getSchema() == structType, "Value type mismatch.") {
            return;
          }
594 595
          builder.getPointerField(assumePointerOffset(slot.getOffset()))
                 .setStruct(structValue.reader);
596
          return;
597
        }
598

599
        case schema::Type::ANY_POINTER: {
600 601
          auto target = AnyPointer::Builder(
              builder.getPointerField(assumePointerOffset(slot.getOffset())));
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634

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

636
        case schema::Type::INTERFACE: {
637
          auto interfaceType = type.asInterface();
638 639 640 641
          auto capability = value.as<DynamicCapability>();
          KJ_REQUIRE(capability.getSchema().extends(interfaceType), "Value type mismatch.") {
            return;
          }
642 643
          builder.getPointerField(assumePointerOffset(slot.getOffset()))
                 .setCapability(kj::mv(capability.hook));
644
          return;
645
        }
646
      }
Kenton Varda's avatar
Kenton Varda committed
647

Kenton Varda's avatar
Kenton Varda committed
648 649 650
      KJ_UNREACHABLE;
    }

Kenton Varda's avatar
Kenton Varda committed
651
    case schema::Field::GROUP: {
Kenton Varda's avatar
Kenton Varda committed
652 653 654 655 656 657 658 659 660 661 662
      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));
        }
663
      }
Kenton Varda's avatar
Kenton Varda committed
664
    }
665
  }
Kenton Varda's avatar
Kenton Varda committed
666

Kenton Varda's avatar
Kenton Varda committed
667
  KJ_UNREACHABLE;
668
}
Kenton Varda's avatar
Kenton Varda committed
669

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

  switch (proto.which()) {
678 679
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
680 681
      switch (type.which()) {
        case schema::Type::STRUCT: {
682
          auto subSchema = type.asStruct();
683
          return DynamicStruct::Builder(subSchema,
684
              builder.getPointerField(assumePointerOffset(slot.getOffset()))
685 686
                     .initStruct(structSizeFromSchema(subSchema)));
        }
687
        case schema::Type::ANY_POINTER: {
688
          auto pointer = builder.getPointerField(assumePointerOffset(slot.getOffset()));
689
          pointer.clear();
690
          return AnyPointer::Builder(pointer);
691 692 693 694
        }
        default:
          KJ_FAIL_REQUIRE("init() without a size is only valid for struct and object fields.");
      }
Kenton Varda's avatar
Kenton Varda committed
695 696
    }

Kenton Varda's avatar
Kenton Varda committed
697
    case schema::Field::GROUP: {
Kenton Varda's avatar
Kenton Varda committed
698
      clear(field);
699
      return DynamicStruct::Builder(type.asStruct(), builder);
Kenton Varda's avatar
Kenton Varda committed
700 701 702 703 704
    }
  }

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

Kenton Varda's avatar
Kenton Varda committed
706 707 708 709 710
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();
711
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
712 713

  switch (proto.which()) {
714 715
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
716
      switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
717
        case schema::Type::LIST: {
718
          auto listType = type.asList();
Kenton Varda's avatar
Kenton Varda committed
719
          if (listType.whichElementType() == schema::Type::STRUCT) {
Kenton Varda's avatar
Kenton Varda committed
720
            return DynamicList::Builder(listType,
721
                builder.getPointerField(assumePointerOffset(slot.getOffset()))
722
                       .initStructList(bounded(size) * ELEMENTS,
723
                                       structSizeFromSchema(listType.getStructElementType())));
Kenton Varda's avatar
Kenton Varda committed
724 725
          } else {
            return DynamicList::Builder(listType,
726 727
                builder.getPointerField(assumePointerOffset(slot.getOffset()))
                       .initList(elementSizeFor(listType.whichElementType()),
728
                                 bounded(size) * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
729 730
          }
        }
Kenton Varda's avatar
Kenton Varda committed
731
        case schema::Type::TEXT:
732
          return builder.getPointerField(assumePointerOffset(slot.getOffset()))
733
                        .initBlob<Text>(bounded(size) * BYTES);
Kenton Varda's avatar
Kenton Varda committed
734
        case schema::Type::DATA:
735
          return builder.getPointerField(assumePointerOffset(slot.getOffset()))
736
                        .initBlob<Data>(bounded(size) * BYTES);
737
        default:
738
          KJ_FAIL_REQUIRE(
739 740
              "init() with size is only valid for list, text, or data fields.",
              (uint)type.which());
741 742
          break;
      }
743
      KJ_UNREACHABLE;
744
    }
Kenton Varda's avatar
Kenton Varda committed
745

Kenton Varda's avatar
Kenton Varda committed
746
    case schema::Field::GROUP:
Kenton Varda's avatar
Kenton Varda committed
747
      KJ_FAIL_REQUIRE("init() with size is only valid for list, text, or data fields.");
Kenton Varda's avatar
Kenton Varda committed
748 749
  }

Kenton Varda's avatar
Kenton Varda committed
750
  KJ_UNREACHABLE;
Kenton Varda's avatar
Kenton Varda committed
751 752
}

753 754 755 756 757 758
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()) {
759 760
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
761
      auto type = field.getType();
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780

      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:
781
          KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch.");
782 783 784
          break;

        case schema::Type::DATA:
785
          KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
786 787 788
          break;

        case schema::Type::LIST: {
789
          ListSchema listType = type.asList();
790
          KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == listType,
791 792 793
                     "Value type mismatch.") {
            return;
          }
794 795 796 797
          break;
        }

        case schema::Type::STRUCT: {
798
          auto structType = type.asStruct();
799
          KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == structType,
800 801 802
                     "Value type mismatch.") {
            return;
          }
803 804 805
          break;
        }

806
        case schema::Type::ANY_POINTER:
807 808
          KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT ||
                     orphan.getType() == DynamicValue::LIST ||
809 810
                     orphan.getType() == DynamicValue::TEXT ||
                     orphan.getType() == DynamicValue::DATA ||
811
                     orphan.getType() == DynamicValue::CAPABILITY ||
812
                     orphan.getType() == DynamicValue::ANY_POINTER,
813 814 815
                     "Value type mismatch.") {
            return;
          }
816 817
          break;

818
        case schema::Type::INTERFACE: {
819
          auto interfaceType = type.asInterface();
820 821 822 823 824
          KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY &&
                     orphan.interfaceSchema.extends(interfaceType),
                     "Value type mismatch.") {
            return;
          }
825
          break;
826
        }
827 828
      }

829
      builder.getPointerField(assumePointerOffset(slot.getOffset())).adopt(kj::mv(orphan.builder));
830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
      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()) {
862 863
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
864

865
      switch (field.getType().which()) {
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
        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:
888
        case schema::Type::ANY_POINTER:
889 890
        case schema::Type::INTERFACE: {
          auto value = get(field);
891
          return Orphan<DynamicValue>(
892
              value, builder.getPointerField(assumePointerOffset(slot.getOffset())).disown());
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
        }
      }
      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
927 928 929 930 931 932

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();
933
  auto type = field.getType();
Kenton Varda's avatar
Kenton Varda committed
934
  switch (proto.which()) {
935 936
    case schema::Field::SLOT: {
      auto slot = proto.getSlot();
Kenton Varda's avatar
Kenton Varda committed
937 938

      switch (type.which()) {
Kenton Varda's avatar
Kenton Varda committed
939
        case schema::Type::VOID:
940
          builder.setDataField<Void>(assumeDataOffset(slot.getOffset()), VOID);
Kenton Varda's avatar
Kenton Varda committed
941 942 943
          return;

#define HANDLE_TYPE(discrim, type) \
Kenton Varda's avatar
Kenton Varda committed
944
        case schema::Type::discrim: \
945
          builder.setDataField<type>(assumeDataOffset(slot.getOffset()), 0); \
Kenton Varda's avatar
Kenton Varda committed
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962
          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
963 964 965 966
        case schema::Type::TEXT:
        case schema::Type::DATA:
        case schema::Type::LIST:
        case schema::Type::STRUCT:
967
        case schema::Type::ANY_POINTER:
Kenton Varda's avatar
Kenton Varda committed
968
        case schema::Type::INTERFACE:
969
          builder.getPointerField(assumePointerOffset(slot.getOffset())).clear();
Kenton Varda's avatar
Kenton Varda committed
970 971 972 973 974 975
          return;
      }

      KJ_UNREACHABLE;
    }

Kenton Varda's avatar
Kenton Varda committed
976
    case schema::Field::GROUP: {
977
      DynamicStruct::Builder group(type.asStruct(), builder);
978 979 980

      // 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
981 982 983
      KJ_IF_MAYBE(unionField, group.schema.getFieldByDiscriminant(0)) {
        group.clear(*unionField);
      }
984

Kenton Varda's avatar
Kenton Varda committed
985 986 987
      for (auto subField: group.schema.getNonUnionFields()) {
        group.clear(subField);
      }
988
      return;
Kenton Varda's avatar
Kenton Varda committed
989 990
    }
  }
991

Kenton Varda's avatar
Kenton Varda committed
992 993 994 995 996 997 998 999 1000
  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));
}
1001
DynamicValue::Pipeline DynamicStruct::Pipeline::get(kj::StringPtr name) {
1002 1003
  return get(schema.getFieldByName(name));
}
1004 1005
bool DynamicStruct::Reader::has(kj::StringPtr name, HasMode mode) const {
  return has(schema.getFieldByName(name), mode);
Kenton Varda's avatar
Kenton Varda committed
1006
}
1007 1008
bool DynamicStruct::Builder::has(kj::StringPtr name, HasMode mode) {
  return has(schema.getFieldByName(name), mode);
Kenton Varda's avatar
Kenton Varda committed
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
}
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);
}
1027 1028 1029 1030 1031 1032
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
1033
void DynamicStruct::Builder::clear(kj::StringPtr name) {
1034
  clear(schema.getFieldByName(name));
Kenton Varda's avatar
Kenton Varda committed
1035
}
Kenton Varda's avatar
Kenton Varda committed
1036 1037 1038

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

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

1042
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1043
#define HANDLE_TYPE(name, discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1044
    case schema::Type::discrim: \
1045
      return reader.getDataElement<typeName>(bounded(index) * ELEMENTS);
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058

    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
1059 1060
#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
1061
    case schema::Type::TEXT:
1062
      return reader.getPointerElement(bounded(index) * ELEMENTS)
1063
                   .getBlob<Text>(nullptr, ZERO * BYTES);
Kenton Varda's avatar
Kenton Varda committed
1064
    case schema::Type::DATA:
1065
      return reader.getPointerElement(bounded(index) * ELEMENTS)
1066
                   .getBlob<Data>(nullptr, ZERO * BYTES);
Kenton Varda's avatar
Kenton Varda committed
1067

Kenton Varda's avatar
Kenton Varda committed
1068
    case schema::Type::LIST: {
1069
      auto elementType = schema.getListElementType();
1070
      return DynamicList::Reader(elementType,
1071
          reader.getPointerElement(bounded(index) * ELEMENTS)
1072
                .getList(elementSizeFor(elementType.whichElementType()), nullptr));
1073
    }
Kenton Varda's avatar
Kenton Varda committed
1074

Kenton Varda's avatar
Kenton Varda committed
1075
    case schema::Type::STRUCT:
1076
      return DynamicStruct::Reader(schema.getStructElementType(),
1077
                                   reader.getStructElement(bounded(index) * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1078

Kenton Varda's avatar
Kenton Varda committed
1079
    case schema::Type::ENUM:
1080
      return DynamicEnum(schema.getEnumElementType(),
1081
                         reader.getDataElement<uint16_t>(bounded(index) * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1082

1083
    case schema::Type::ANY_POINTER:
1084
      return AnyPointer::Reader(reader.getPointerElement(bounded(index) * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1085

Kenton Varda's avatar
Kenton Varda committed
1086
    case schema::Type::INTERFACE:
1087
      return DynamicCapability::Client(schema.getInterfaceElementType(),
1088
                                       reader.getPointerElement(bounded(index) * ELEMENTS)
1089
                                             .getCapability());
Kenton Varda's avatar
Kenton Varda committed
1090
  }
1091

1092
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1093 1094
}

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

1098
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1099
#define HANDLE_TYPE(name, discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1100
    case schema::Type::discrim: \
1101
      return builder.getDataElement<typeName>(bounded(index) * ELEMENTS);
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114

    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
1115 1116
#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
1117
    case schema::Type::TEXT:
1118
      return builder.getPointerElement(bounded(index) * ELEMENTS)
1119
                    .getBlob<Text>(nullptr, ZERO * BYTES);
Kenton Varda's avatar
Kenton Varda committed
1120
    case schema::Type::DATA:
1121
      return builder.getPointerElement(bounded(index) * ELEMENTS)
1122
                    .getBlob<Data>(nullptr, ZERO * BYTES);
Kenton Varda's avatar
Kenton Varda committed
1123

Kenton Varda's avatar
Kenton Varda committed
1124
    case schema::Type::LIST: {
1125
      ListSchema elementType = schema.getListElementType();
Kenton Varda's avatar
Kenton Varda committed
1126
      if (elementType.whichElementType() == schema::Type::STRUCT) {
1127
        return DynamicList::Builder(elementType,
1128
            builder.getPointerElement(bounded(index) * ELEMENTS)
1129 1130
                   .getStructList(structSizeFromSchema(elementType.getStructElementType()),
                                  nullptr));
1131
      } else {
1132
        return DynamicList::Builder(elementType,
1133
            builder.getPointerElement(bounded(index) * ELEMENTS)
1134
                   .getList(elementSizeFor(elementType.whichElementType()), nullptr));
1135 1136
      }
    }
Kenton Varda's avatar
Kenton Varda committed
1137

Kenton Varda's avatar
Kenton Varda committed
1138
    case schema::Type::STRUCT:
1139
      return DynamicStruct::Builder(schema.getStructElementType(),
1140
                                    builder.getStructElement(bounded(index) * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1141

Kenton Varda's avatar
Kenton Varda committed
1142
    case schema::Type::ENUM:
1143
      return DynamicEnum(schema.getEnumElementType(),
1144
                         builder.getDataElement<uint16_t>(bounded(index) * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1145

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

Kenton Varda's avatar
Kenton Varda committed
1150
    case schema::Type::INTERFACE:
1151
      return DynamicCapability::Client(schema.getInterfaceElementType(),
1152
                                       builder.getPointerElement(bounded(index) * ELEMENTS)
1153
                                              .getCapability());
Kenton Varda's avatar
Kenton Varda committed
1154
  }
1155

1156
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1157 1158
}

1159
void DynamicList::Builder::set(uint index, const DynamicValue::Reader& value) {
1160
  KJ_REQUIRE(index < size(), "List index out-of-bounds.") {
1161 1162
    return;
  }
Kenton Varda's avatar
Kenton Varda committed
1163

1164
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1165
#define HANDLE_TYPE(name, discrim, typeName) \
Kenton Varda's avatar
Kenton Varda committed
1166
    case schema::Type::discrim: \
1167
      builder.setDataElement<typeName>(bounded(index) * ELEMENTS, value.as<typeName>()); \
1168
      return;
Kenton Varda's avatar
Kenton Varda committed
1169

1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
    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
1182 1183
#undef HANDLE_TYPE

Kenton Varda's avatar
Kenton Varda committed
1184
    case schema::Type::TEXT:
1185
      builder.getPointerElement(bounded(index) * ELEMENTS).setBlob<Text>(value.as<Text>());
1186
      return;
Kenton Varda's avatar
Kenton Varda committed
1187
    case schema::Type::DATA:
1188
      builder.getPointerElement(bounded(index) * ELEMENTS).setBlob<Data>(value.as<Data>());
1189
      return;
Kenton Varda's avatar
Kenton Varda committed
1190

Kenton Varda's avatar
Kenton Varda committed
1191
    case schema::Type::LIST: {
1192 1193 1194 1195
      auto listValue = value.as<DynamicList>();
      KJ_REQUIRE(listValue.getSchema() == schema.getListElementType(), "Value type mismatch.") {
        return;
      }
1196
      builder.getPointerElement(bounded(index) * ELEMENTS).setList(listValue.reader);
1197
      return;
1198
    }
Kenton Varda's avatar
Kenton Varda committed
1199

1200
    case schema::Type::STRUCT: {
1201 1202 1203 1204
      auto structValue = value.as<DynamicStruct>();
      KJ_REQUIRE(structValue.getSchema() == schema.getStructElementType(), "Value type mismatch.") {
        return;
      }
1205
      builder.getStructElement(bounded(index) * ELEMENTS).copyContentFrom(structValue.reader);
1206 1207
      return;
    }
Kenton Varda's avatar
Kenton Varda committed
1208

Kenton Varda's avatar
Kenton Varda committed
1209
    case schema::Type::ENUM: {
1210 1211 1212 1213 1214 1215
      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>();
1216 1217
        KJ_REQUIRE(schema.getEnumElementType() == enumValue.getSchema(),
                   "Type mismatch when using DynamicList::Builder::set().") {
1218 1219 1220
          return;
        }
        rawValue = enumValue.getRaw();
1221
      }
1222
      builder.setDataElement<uint16_t>(bounded(index) * ELEMENTS, rawValue);
1223
      return;
1224
    }
Kenton Varda's avatar
Kenton Varda committed
1225

1226 1227
    case schema::Type::ANY_POINTER:
      KJ_FAIL_ASSERT("List(AnyPointer) not supported.") {
1228 1229
        return;
      }
Kenton Varda's avatar
Kenton Varda committed
1230

1231 1232 1233 1234
    case schema::Type::INTERFACE: {
      auto capValue = value.as<DynamicCapability>();
      KJ_REQUIRE(capValue.getSchema().extends(schema.getInterfaceElementType()),
                 "Value type mismatch.") {
1235 1236
        return;
      }
1237
      builder.getPointerElement(bounded(index) * ELEMENTS).setCapability(kj::mv(capValue.hook));
1238 1239
      return;
    }
Kenton Varda's avatar
Kenton Varda committed
1240
  }
1241

1242 1243 1244
  KJ_FAIL_REQUIRE("can't set element of unknown type", (uint)schema.whichElementType()) {
    return;
  }
Kenton Varda's avatar
Kenton Varda committed
1245 1246 1247
}

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

1250
  switch (schema.whichElementType()) {
Kenton Varda's avatar
Kenton Varda committed
1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
    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:
1266
      KJ_FAIL_REQUIRE("Expected a list or blob.");
1267
      return nullptr;
1268

Kenton Varda's avatar
Kenton Varda committed
1269
    case schema::Type::TEXT:
1270 1271
      return builder.getPointerElement(bounded(index) * ELEMENTS)
                    .initBlob<Text>(bounded(size) * BYTES);
1272

Kenton Varda's avatar
Kenton Varda committed
1273
    case schema::Type::DATA:
1274 1275
      return builder.getPointerElement(bounded(index) * ELEMENTS)
                    .initBlob<Data>(bounded(size) * BYTES);
1276

Kenton Varda's avatar
Kenton Varda committed
1277
    case schema::Type::LIST: {
1278 1279
      auto elementType = schema.getListElementType();

Kenton Varda's avatar
Kenton Varda committed
1280
      if (elementType.whichElementType() == schema::Type::STRUCT) {
1281
        return DynamicList::Builder(elementType,
1282 1283
            builder.getPointerElement(bounded(index) * ELEMENTS)
                   .initStructList(bounded(size) * ELEMENTS,
1284
                                   structSizeFromSchema(elementType.getStructElementType())));
1285
      } else {
1286
        return DynamicList::Builder(elementType,
1287
            builder.getPointerElement(bounded(index) * ELEMENTS)
1288
                   .initList(elementSizeFor(elementType.whichElementType()),
1289
                             bounded(size) * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1290 1291 1292
      }
    }

1293 1294
    case schema::Type::ANY_POINTER: {
      KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
1295
      return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1296 1297
    }
  }
1298

1299
  return nullptr;
Kenton Varda's avatar
Kenton Varda committed
1300 1301
}

1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321
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.");
1322
      builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
1323 1324 1325 1326
      return;

    case schema::Type::DATA:
      KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
1327
      builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
1328 1329 1330 1331 1332 1333
      return;

    case schema::Type::LIST: {
      ListSchema elementType = schema.getListElementType();
      KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == elementType,
                 "Value type mismatch.");
1334
      builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
1335 1336 1337 1338 1339 1340 1341
      return;
    }

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

1347 1348
    case schema::Type::ANY_POINTER:
      KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
1349

1350 1351 1352 1353 1354
    case schema::Type::INTERFACE: {
      auto elementType = schema.getInterfaceElementType();
      KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY &&
                 orphan.interfaceSchema.extends(elementType),
                 "Value type mismatch.");
1355
      builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
1356 1357
      return;
    }
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379
  }

  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())) {
1380
        case ElementSize::VOID: break;
1381 1382 1383 1384 1385
        case ElementSize::BIT: builder.setDataElement<bool>(bounded(index) * ELEMENTS, false); break;
        case ElementSize::BYTE: builder.setDataElement<uint8_t>(bounded(index) * ELEMENTS, 0); break;
        case ElementSize::TWO_BYTES: builder.setDataElement<uint16_t>(bounded(index) * ELEMENTS, 0); break;
        case ElementSize::FOUR_BYTES: builder.setDataElement<uint32_t>(bounded(index) * ELEMENTS, 0); break;
        case ElementSize::EIGHT_BYTES: builder.setDataElement<uint64_t>(bounded(index) * ELEMENTS, 0);break;
1386 1387 1388

        case ElementSize::POINTER:
        case ElementSize::INLINE_COMPOSITE:
1389 1390 1391 1392 1393 1394 1395 1396
          KJ_UNREACHABLE;
      }
      return kj::mv(result);
    }

    case schema::Type::TEXT:
    case schema::Type::DATA:
    case schema::Type::LIST:
1397
    case schema::Type::ANY_POINTER:
1398 1399
    case schema::Type::INTERFACE: {
      auto value = operator[](index);
1400
      return Orphan<DynamicValue>(value, builder.getPointerElement(bounded(index) * ELEMENTS).disown());
1401 1402 1403 1404 1405 1406
    }

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

1416
void DynamicList::Builder::copyFrom(std::initializer_list<DynamicValue::Reader> value) {
1417
  KJ_REQUIRE(value.size() == size(), "DynamicList::copyFrom() argument had different size.");
1418 1419 1420 1421 1422 1423
  uint i = 0;
  for (auto element: value) {
    set(i++, element);
  }
}

1424
DynamicList::Reader DynamicList::Builder::asReader() const {
1425
  return DynamicList::Reader(schema, builder.asReader());
Kenton Varda's avatar
Kenton Varda committed
1426 1427
}

Kenton Varda's avatar
Kenton Varda committed
1428 1429
// =======================================================================================

Kenton Varda's avatar
Kenton Varda committed
1430
DynamicValue::Reader::Reader(ConstSchema constant): type(VOID) {
1431
  auto type = constant.getType();
1432
  auto value = constant.getProto().getConst().getValue();
1433
  switch (type.which()) {
1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
    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:
1450
      *this = DynamicEnum(type.asEnum(), value.getEnum());
1451 1452 1453
      break;

    case schema::Type::STRUCT:
1454
      *this = value.getStruct().getAs<DynamicStruct>(type.asStruct());
1455 1456 1457
      break;

    case schema::Type::LIST:
1458
      *this = value.getList().getAs<DynamicList>(type.asList());
1459 1460
      break;

1461 1462
    case schema::Type::ANY_POINTER:
      *this = value.getAnyPointer();
1463 1464 1465 1466 1467 1468 1469
      break;

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

1470
DynamicValue::Reader::Reader(const Reader& other) {
Kenton Varda's avatar
Kenton Varda committed
1471
  switch (other.type) {
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
    case UNKNOWN:
    case VOID:
    case BOOL:
    case INT:
    case UINT:
    case FLOAT:
    case TEXT:
    case DATA:
    case LIST:
    case ENUM:
    case STRUCT:
1483
    case ANY_POINTER:
1484 1485 1486 1487 1488 1489
      KJ_ASSERT_CAN_MEMCPY(Text::Reader);
      KJ_ASSERT_CAN_MEMCPY(Data::Reader);
      KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader);
      KJ_ASSERT_CAN_MEMCPY(DynamicEnum);
      KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader);
      KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader);
1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
      break;

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

  memcpy(this, &other, sizeof(*this));
}
Kenton Varda's avatar
Kenton Varda committed
1500 1501
DynamicValue::Reader::Reader(Reader&& other) noexcept {
  switch (other.type) {
1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
    case UNKNOWN:
    case VOID:
    case BOOL:
    case INT:
    case UINT:
    case FLOAT:
    case TEXT:
    case DATA:
    case LIST:
    case ENUM:
    case STRUCT:
1513
    case ANY_POINTER:
1514 1515 1516 1517 1518 1519
      KJ_ASSERT_CAN_MEMCPY(Text::Reader);
      KJ_ASSERT_CAN_MEMCPY(Data::Reader);
      KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader);
      KJ_ASSERT_CAN_MEMCPY(DynamicEnum);
      KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader);
      KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader);
1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
      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
1530
DynamicValue::Reader::~Reader() noexcept(false) {
1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551
  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
1552
  switch (other.type) {
1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
    case UNKNOWN:
    case VOID:
    case BOOL:
    case INT:
    case UINT:
    case FLOAT:
    case TEXT:
    case DATA:
    case LIST:
    case ENUM:
    case STRUCT:
1564
    case ANY_POINTER:
1565
      // Unfortunately canMemcpy() doesn't work on these types due to the use of
1566 1567 1568 1569 1570 1571 1572
      // 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) &&
1573
                    __has_trivial_destructor(AnyPointer::Builder),
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584
                    "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
1585 1586
DynamicValue::Builder::Builder(Builder&& other) noexcept {
  switch (other.type) {
1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597
    case UNKNOWN:
    case VOID:
    case BOOL:
    case INT:
    case UINT:
    case FLOAT:
    case TEXT:
    case DATA:
    case LIST:
    case ENUM:
    case STRUCT:
1598
    case ANY_POINTER:
1599 1600 1601 1602 1603 1604 1605 1606
      // 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) &&
1607
                    __has_trivial_destructor(AnyPointer::Builder),
1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618
                    "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
1619
DynamicValue::Builder::~Builder() noexcept(false) {
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639
  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;
}

1640
DynamicValue::Reader DynamicValue::Builder::asReader() const {
Kenton Varda's avatar
Kenton Varda committed
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652
  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());
1653
    case CAPABILITY: return Reader(capabilityValue);
1654
    case ANY_POINTER: return Reader(anyPointerValue.asReader());
Kenton Varda's avatar
Kenton Varda committed
1655
  }
1656
  KJ_FAIL_ASSERT("Missing switch case.");
Kenton Varda's avatar
Kenton Varda committed
1657 1658 1659
  return Reader();
}

1660
DynamicValue::Pipeline::Pipeline(Pipeline&& other) noexcept: type(other.type) {
1661 1662 1663 1664 1665
  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:
1666 1667
      KJ_LOG(ERROR, "Unexpected pipeline type.", (uint)type);
      type = UNKNOWN;
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686
      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;
  }
}

1687 1688 1689 1690
namespace {

template <typename T>
T signedToUnsigned(long long value) {
1691
  KJ_REQUIRE(value >= 0 && T(value) == value, "Value out-of-range for requested type.", value) {
1692
    // Use it anyway.
1693
    break;
1694 1695 1696 1697 1698 1699
  }
  return value;
}

template <>
uint64_t signedToUnsigned<uint64_t>(long long value) {
1700
  KJ_REQUIRE(value >= 0, "Value out-of-range for requested type.", value) {
1701
    // Use it anyway.
1702
    break;
1703 1704 1705 1706 1707 1708
  }
  return value;
}

template <typename T>
T unsignedToSigned(unsigned long long value) {
1709 1710
  KJ_REQUIRE(T(value) >= 0 && (unsigned long long)T(value) == value,
             "Value out-of-range for requested type.", value) {
1711
    // Use it anyway.
1712
    break;
1713 1714 1715 1716 1717 1718
  }
  return value;
}

template <>
int64_t unsignedToSigned<int64_t>(unsigned long long value) {
1719
  KJ_REQUIRE(int64_t(value) >= 0, "Value out-of-range for requested type.", value) {
1720
    // Use it anyway.
1721
    break;
1722 1723 1724 1725 1726 1727
  }
  return value;
}

template <typename T, typename U>
T checkRoundTrip(U value) {
1728
  KJ_REQUIRE(T(value) == value, "Value out-of-range for requested type.", value) {
1729
    // Use it anyway.
1730
    break;
1731 1732 1733 1734 1735 1736 1737
  }
  return value;
}

}  // namespace

#define HANDLE_NUMERIC_TYPE(typeName, ifInt, ifUint, ifFloat) \
1738
typeName DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
1739 1740 1741 1742 1743 1744 1745 1746
  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
1747
      KJ_FAIL_REQUIRE("Value type mismatch.") { \
1748
        return 0; \
1749
      } \
1750 1751
  } \
} \
1752
typeName DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
1753 1754 1755 1756 1757 1758 1759 1760
  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
1761
      KJ_FAIL_REQUIRE("Value type mismatch.") { \
1762
        return 0; \
1763
      } \
1764 1765 1766 1767 1768 1769
  } \
}

HANDLE_NUMERIC_TYPE(int8_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
HANDLE_NUMERIC_TYPE(int16_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
HANDLE_NUMERIC_TYPE(int32_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
1770
HANDLE_NUMERIC_TYPE(int64_t, kj::implicitCast, unsignedToSigned, checkRoundTrip)
1771 1772 1773
HANDLE_NUMERIC_TYPE(uint8_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
HANDLE_NUMERIC_TYPE(uint16_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
HANDLE_NUMERIC_TYPE(uint32_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
1774 1775 1776
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)
1777 1778 1779

#undef HANDLE_NUMERIC_TYPE

Kenton Varda's avatar
Kenton Varda committed
1780
#define HANDLE_TYPE(name, discrim, typeName) \
1781
ReaderFor<typeName> DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
Kenton Varda's avatar
Kenton Varda committed
1782
  KJ_REQUIRE(reader.type == discrim, "Value type mismatch.") { \
1783 1784
    return ReaderFor<typeName>(); \
  } \
Kenton Varda's avatar
Kenton Varda committed
1785 1786
  return reader.name##Value; \
} \
1787
BuilderFor<typeName> DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
1788
  KJ_REQUIRE(builder.type == discrim, "Value type mismatch."); \
Kenton Varda's avatar
Kenton Varda committed
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798
  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)
1799
HANDLE_TYPE(anyPointer, ANY_POINTER, AnyPointer)
Kenton Varda's avatar
Kenton Varda committed
1800 1801 1802

#undef HANDLE_TYPE

1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830
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);
}

1831 1832 1833
Data::Reader DynamicValue::Reader::AsImpl<Data>::apply(const Reader& reader) {
  if (reader.type == TEXT) {
    // Coerce text to data.
1834
    return reader.textValue.asBytes();
1835 1836 1837 1838 1839 1840 1841 1842 1843
  }
  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.
1844
    return builder.textValue.asBytes();
1845 1846 1847 1848 1849 1850 1851
  }
  KJ_REQUIRE(builder.type == DATA, "Value type mismatch.") {
    return BuilderFor<Data>();
  }
  return builder.dataValue;
}

Kenton Varda's avatar
Kenton Varda committed
1852
// As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
1853
Void DynamicValue::Reader::AsImpl<Void>::apply(const Reader& reader) {
Kenton Varda's avatar
Kenton Varda committed
1854
  KJ_REQUIRE(reader.type == VOID, "Value type mismatch.") {
Kenton Varda's avatar
Kenton Varda committed
1855 1856 1857 1858
    return Void();
  }
  return reader.voidValue;
}
1859
Void DynamicValue::Builder::AsImpl<Void>::apply(Builder& builder) {
Kenton Varda's avatar
Kenton Varda committed
1860
  KJ_REQUIRE(builder.type == VOID, "Value type mismatch.") {
Kenton Varda's avatar
Kenton Varda committed
1861 1862 1863 1864 1865
    return Void();
  }
  return builder.voidValue;
}

Kenton Varda's avatar
Kenton Varda committed
1866 1867
// =======================================================================================

1868
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
1869

1870
DynamicStruct::Reader PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
1871
    PointerReader reader, StructSchema schema) {
1872 1873
  KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1874
  return DynamicStruct::Reader(schema, reader.getStruct(nullptr));
Kenton Varda's avatar
Kenton Varda committed
1875
}
1876
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
1877
    PointerBuilder builder, StructSchema schema) {
1878 1879
  KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1880
  return DynamicStruct::Builder(schema, builder.getStruct(
1881
      structSizeFromSchema(schema), nullptr));
Kenton Varda's avatar
Kenton Varda committed
1882
}
1883
void PointerHelpers<DynamicStruct, Kind::OTHER>::set(
1884
    PointerBuilder builder, const DynamicStruct::Reader& value) {
1885 1886
  KJ_REQUIRE(!value.schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1887
  builder.setStruct(value.reader);
Kenton Varda's avatar
Kenton Varda committed
1888
}
1889
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::init(
1890
    PointerBuilder builder, StructSchema schema) {
1891 1892
  KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
             "Cannot form pointer to group type.");
1893
  return DynamicStruct::Builder(schema,
1894
      builder.initStruct(structSizeFromSchema(schema)));
Kenton Varda's avatar
Kenton Varda committed
1895 1896
}

1897
DynamicList::Reader PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
1898
    PointerReader reader, ListSchema schema) {
1899
  return DynamicList::Reader(schema,
1900
      reader.getList(elementSizeFor(schema.whichElementType()), nullptr));
Kenton Varda's avatar
Kenton Varda committed
1901
}
1902
DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
1903
    PointerBuilder builder, ListSchema schema) {
Kenton Varda's avatar
Kenton Varda committed
1904
  if (schema.whichElementType() == schema::Type::STRUCT) {
1905
    return DynamicList::Builder(schema,
1906
        builder.getStructList(
1907 1908 1909 1910
            structSizeFromSchema(schema.getStructElementType()),
            nullptr));
  } else {
    return DynamicList::Builder(schema,
1911
        builder.getList(elementSizeFor(schema.whichElementType()), nullptr));
1912
  }
Kenton Varda's avatar
Kenton Varda committed
1913
}
1914
void PointerHelpers<DynamicList, Kind::OTHER>::set(
1915 1916
    PointerBuilder builder, const DynamicList::Reader& value) {
  builder.setList(value.reader);
Kenton Varda's avatar
Kenton Varda committed
1917
}
1918
DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::init(
1919
    PointerBuilder builder, ListSchema schema, uint size) {
Kenton Varda's avatar
Kenton Varda committed
1920
  if (schema.whichElementType() == schema::Type::STRUCT) {
1921
    return DynamicList::Builder(schema,
1922
        builder.initStructList(bounded(size) * ELEMENTS,
1923
            structSizeFromSchema(schema.getStructElementType())));
Kenton Varda's avatar
Kenton Varda committed
1924
  } else {
1925
    return DynamicList::Builder(schema,
1926
        builder.initList(elementSizeFor(schema.whichElementType()), bounded(size) * ELEMENTS));
Kenton Varda's avatar
Kenton Varda committed
1927 1928 1929
  }
}

1930
DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
1931 1932 1933
    PointerReader reader, InterfaceSchema schema) {
  return DynamicCapability::Client(schema, reader.getCapability());
}
1934
DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
1935 1936 1937
    PointerBuilder builder, InterfaceSchema schema) {
  return DynamicCapability::Client(schema, builder.getCapability());
}
1938
void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
1939
    PointerBuilder builder, DynamicCapability::Client& value) {
1940 1941
  builder.setCapability(value.hook->addRef());
}
1942
void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
1943 1944 1945 1946
    PointerBuilder builder, DynamicCapability::Client&& value) {
  builder.setCapability(kj::mv(value.hook));
}

1947
}  // namespace _ (private)
Kenton Varda's avatar
Kenton Varda committed
1948

1949
template <>
1950
void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan) {
1951 1952 1953 1954 1955 1956 1957 1958
  switch (orphan.getType()) {
    case DynamicValue::UNKNOWN:
    case DynamicValue::VOID:
    case DynamicValue::BOOL:
    case DynamicValue::INT:
    case DynamicValue::UINT:
    case DynamicValue::FLOAT:
    case DynamicValue::ENUM:
1959
      KJ_FAIL_REQUIRE("AnyPointer cannot adopt primitive (non-object) value.");
1960 1961 1962 1963 1964

    case DynamicValue::STRUCT:
    case DynamicValue::LIST:
    case DynamicValue::TEXT:
    case DynamicValue::DATA:
1965
    case DynamicValue::CAPABILITY:
1966
    case DynamicValue::ANY_POINTER:
1967 1968 1969 1970 1971
      builder.adopt(kj::mv(orphan.builder));
      break;
  }
}

1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982
DynamicStruct::Reader::Reader(StructSchema schema, const _::OrphanBuilder& orphan)
    : schema(schema), reader(orphan.asStructReader(structSizeFromSchema(schema))) {}
DynamicStruct::Builder::Builder(StructSchema schema, _::OrphanBuilder& orphan)
    : schema(schema), builder(orphan.asStruct(structSizeFromSchema(schema))) {}

DynamicList::Reader::Reader(ListSchema schema, const _::OrphanBuilder& orphan)
    : schema(schema), reader(orphan.asListReader(elementSizeFor(schema.whichElementType()))) {}
DynamicList::Builder::Builder(ListSchema schema, _::OrphanBuilder& orphan)
    : schema(schema), builder(schema.whichElementType() == schema::Type::STRUCT
        ? orphan.asStructList(structSizeFromSchema(schema.getStructElementType()))
        : orphan.asList(elementSizeFor(schema.whichElementType()))) {}
1983

1984 1985
// -------------------------------------------------------------------

1986
Orphan<DynamicStruct> Orphanage::newOrphan(StructSchema schema) const {
1987
  return Orphan<DynamicStruct>(
1988
      schema, _::OrphanBuilder::initStruct(arena, capTable, structSizeFromSchema(schema)));
1989 1990
}

1991
Orphan<DynamicList> Orphanage::newOrphan(ListSchema schema, uint size) const {
Kenton Varda's avatar
Kenton Varda committed
1992
  if (schema.whichElementType() == schema::Type::STRUCT) {
1993
    return Orphan<DynamicList>(schema, _::OrphanBuilder::initStructList(
1994
        arena, capTable, bounded(size) * ELEMENTS,
1995
        structSizeFromSchema(schema.getStructElementType())));
1996 1997
  } else {
    return Orphan<DynamicList>(schema, _::OrphanBuilder::initList(
1998
        arena, capTable, bounded(size) * ELEMENTS,
1999
        elementSizeFor(schema.whichElementType())));
2000 2001 2002 2003 2004 2005 2006
  }
}

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

2007 2008 2009 2010
DynamicStruct::Reader Orphan<DynamicStruct>::getReader() const {
  return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
}

2011
DynamicList::Builder Orphan<DynamicList>::get() {
Kenton Varda's avatar
Kenton Varda committed
2012
  if (schema.whichElementType() == schema::Type::STRUCT) {
2013 2014 2015 2016 2017 2018 2019 2020
    return DynamicList::Builder(
        schema, builder.asStructList(structSizeFromSchema(schema.getStructElementType())));
  } else {
    return DynamicList::Builder(
        schema, builder.asList(elementSizeFor(schema.whichElementType())));
  }
}

2021 2022 2023 2024 2025
DynamicList::Reader Orphan<DynamicList>::getReader() const {
  return DynamicList::Reader(
      schema, builder.asListReader(elementSizeFor(schema.whichElementType())));
}

2026 2027 2028 2029 2030 2031 2032 2033
DynamicCapability::Client Orphan<DynamicCapability>::get() {
  return DynamicCapability::Client(schema, builder.asCapability());
}

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

2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048
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;
2049
    case DynamicValue::CAPABILITY: interfaceSchema = value.capabilityValue.getSchema(); break;
2050
    case DynamicValue::ANY_POINTER: break;
2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076
  }
}

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)));
2077 2078
    case DynamicValue::CAPABILITY:
      return DynamicCapability::Client(interfaceSchema, builder.asCapability());
2079 2080 2081
    case DynamicValue::ANY_POINTER:
      KJ_FAIL_REQUIRE("Can't get() an AnyPointer orphan; there is no underlying pointer to "
                      "wrap in an AnyPointer::Builder.");
2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102
  }
  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)));
2103 2104
    case DynamicValue::CAPABILITY:
      return DynamicCapability::Client(interfaceSchema, builder.asCapability());
2105 2106 2107
    case DynamicValue::ANY_POINTER:
      KJ_FAIL_ASSERT("Can't get() an AnyPointer orphan; there is no underlying pointer to "
                     "wrap in an AnyPointer::Builder.");
2108 2109 2110 2111
  }
  KJ_UNREACHABLE;
}

2112
template <>
2113 2114
Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>() {
  KJ_REQUIRE(type == DynamicValue::ANY_POINTER, "Value type mismatch.");
2115
  type = DynamicValue::UNKNOWN;
2116
  return Orphan<AnyPointer>(kj::mv(builder));
2117
}
2118 2119 2120
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>() {
  KJ_REQUIRE(type == DynamicValue::STRUCT, "Value type mismatch.");
2121
  type = DynamicValue::UNKNOWN;
2122 2123 2124 2125 2126
  return Orphan<DynamicStruct>(structSchema, kj::mv(builder));
}
template <>
Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>() {
  KJ_REQUIRE(type == DynamicValue::LIST, "Value type mismatch.");
2127
  type = DynamicValue::UNKNOWN;
2128 2129 2130
  return Orphan<DynamicList>(listSchema, kj::mv(builder));
}

2131 2132
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
2133
    DynamicValue::Reader copyFrom) const {
2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146
  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);
2147
    case DynamicValue::CAPABILITY: return newOrphanCopy(copyFrom.capabilityValue);
2148
    case DynamicValue::ANY_POINTER: return newOrphanCopy(copyFrom.anyPointerValue);
2149 2150 2151 2152
  }
  KJ_UNREACHABLE;
}

2153
}  // namespace capnp