capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

dynamic.c++ (78174B)


      1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #include "dynamic.h"
     23 #include <kj/debug.h>
     24 
     25 namespace capnp {
     26 
     27 namespace {
     28 
     29 bool hasDiscriminantValue(const schema::Field::Reader& reader) {
     30   return reader.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT;
     31 }
     32 
     33 template <typename T, typename U>
     34 KJ_ALWAYS_INLINE(T bitCast(U value));
     35 
     36 template <typename T, typename U>
     37 inline T bitCast(U value) {
     38   static_assert(sizeof(T) == sizeof(U), "Size must match.");
     39   return value;
     40 }
     41 template <>
     42 inline float bitCast<float, uint32_t>(uint32_t value) KJ_UNUSED;
     43 template <>
     44 inline float bitCast<float, uint32_t>(uint32_t value) {
     45   float result;
     46   memcpy(&result, &value, sizeof(value));
     47   return result;
     48 }
     49 template <>
     50 inline double bitCast<double, uint64_t>(uint64_t value) KJ_UNUSED;
     51 template <>
     52 inline double bitCast<double, uint64_t>(uint64_t value) {
     53   double result;
     54   memcpy(&result, &value, sizeof(value));
     55   return result;
     56 }
     57 template <>
     58 inline uint32_t bitCast<uint32_t, float>(float value) {
     59   uint32_t result;
     60   memcpy(&result, &value, sizeof(value));
     61   return result;
     62 }
     63 template <>
     64 inline uint64_t bitCast<uint64_t, double>(double value) {
     65   uint64_t result;
     66   memcpy(&result, &value, sizeof(value));
     67   return result;
     68 }
     69 
     70 ElementSize elementSizeFor(schema::Type::Which elementType) {
     71   switch (elementType) {
     72     case schema::Type::VOID: return ElementSize::VOID;
     73     case schema::Type::BOOL: return ElementSize::BIT;
     74     case schema::Type::INT8: return ElementSize::BYTE;
     75     case schema::Type::INT16: return ElementSize::TWO_BYTES;
     76     case schema::Type::INT32: return ElementSize::FOUR_BYTES;
     77     case schema::Type::INT64: return ElementSize::EIGHT_BYTES;
     78     case schema::Type::UINT8: return ElementSize::BYTE;
     79     case schema::Type::UINT16: return ElementSize::TWO_BYTES;
     80     case schema::Type::UINT32: return ElementSize::FOUR_BYTES;
     81     case schema::Type::UINT64: return ElementSize::EIGHT_BYTES;
     82     case schema::Type::FLOAT32: return ElementSize::FOUR_BYTES;
     83     case schema::Type::FLOAT64: return ElementSize::EIGHT_BYTES;
     84 
     85     case schema::Type::TEXT: return ElementSize::POINTER;
     86     case schema::Type::DATA: return ElementSize::POINTER;
     87     case schema::Type::LIST: return ElementSize::POINTER;
     88     case schema::Type::ENUM: return ElementSize::TWO_BYTES;
     89     case schema::Type::STRUCT: return ElementSize::INLINE_COMPOSITE;
     90     case schema::Type::INTERFACE: return ElementSize::POINTER;
     91     case schema::Type::ANY_POINTER: KJ_FAIL_ASSERT("List(AnyPointer) not supported."); break;
     92   }
     93 
     94   // Unknown type.  Treat it as zero-size.
     95   return ElementSize::VOID;
     96 }
     97 
     98 inline _::StructSize structSizeFromSchema(StructSchema schema) {
     99   auto node = schema.getProto().getStruct();
    100   return _::StructSize(
    101       bounded(node.getDataWordCount()) * WORDS,
    102       bounded(node.getPointerCount()) * POINTERS);
    103 }
    104 
    105 }  // namespace
    106 
    107 // =======================================================================================
    108 
    109 kj::Maybe<EnumSchema::Enumerant> DynamicEnum::getEnumerant() const {
    110   auto enumerants = schema.getEnumerants();
    111   if (value < enumerants.size()) {
    112     return enumerants[value];
    113   } else {
    114     return nullptr;
    115   }
    116 }
    117 
    118 uint16_t DynamicEnum::asImpl(uint64_t requestedTypeId) const {
    119   KJ_REQUIRE(requestedTypeId == schema.getProto().getId(),
    120              "Type mismatch in DynamicEnum.as().") {
    121     // use it anyway
    122     break;
    123   }
    124   return value;
    125 }
    126 
    127 // =======================================================================================
    128 
    129 bool DynamicStruct::Reader::isSetInUnion(StructSchema::Field field) const {
    130   auto proto = field.getProto();
    131   if (hasDiscriminantValue(proto)) {
    132     uint16_t discrim = reader.getDataField<uint16_t>(
    133         assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()));
    134     return discrim == proto.getDiscriminantValue();
    135   } else {
    136     return true;
    137   }
    138 }
    139 
    140 void DynamicStruct::Reader::verifySetInUnion(StructSchema::Field field) const {
    141   KJ_REQUIRE(isSetInUnion(field),
    142       "Tried to get() a union member which is not currently initialized.",
    143       field.getProto().getName(), schema.getProto().getDisplayName());
    144 }
    145 
    146 bool DynamicStruct::Builder::isSetInUnion(StructSchema::Field field) {
    147   auto proto = field.getProto();
    148   if (hasDiscriminantValue(proto)) {
    149     uint16_t discrim = builder.getDataField<uint16_t>(
    150         assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()));
    151     return discrim == proto.getDiscriminantValue();
    152   } else {
    153     return true;
    154   }
    155 }
    156 
    157 void DynamicStruct::Builder::verifySetInUnion(StructSchema::Field field) {
    158   KJ_REQUIRE(isSetInUnion(field),
    159       "Tried to get() a union member which is not currently initialized.",
    160       field.getProto().getName(), schema.getProto().getDisplayName());
    161 }
    162 
    163 void DynamicStruct::Builder::setInUnion(StructSchema::Field field) {
    164   // If a union member, set the discriminant to match.
    165   auto proto = field.getProto();
    166   if (hasDiscriminantValue(proto)) {
    167     builder.setDataField<uint16_t>(
    168         assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()),
    169         proto.getDiscriminantValue());
    170   }
    171 }
    172 
    173 DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const {
    174   KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
    175   verifySetInUnion(field);
    176 
    177   auto type = field.getType();
    178   auto proto = field.getProto();
    179   switch (proto.which()) {
    180     case schema::Field::SLOT: {
    181       auto slot = proto.getSlot();
    182 
    183       // Note that the default value might be "anyPointer" even if the type is some poniter type
    184       // *other than* anyPointer. This happens with generics -- the field is actually a generic
    185       // parameter that has been bound, but the default value was of course compiled without any
    186       // binding available.
    187       auto dval = slot.getDefaultValue();
    188 
    189       switch (type.which()) {
    190         case schema::Type::VOID:
    191           return reader.getDataField<Void>(assumeDataOffset(slot.getOffset()));
    192 
    193 #define HANDLE_TYPE(discrim, titleCase, type) \
    194         case schema::Type::discrim: \
    195           return reader.getDataField<type>( \
    196               assumeDataOffset(slot.getOffset()), \
    197               bitCast<_::Mask<type>>(dval.get##titleCase()));
    198 
    199         HANDLE_TYPE(BOOL, Bool, bool)
    200         HANDLE_TYPE(INT8, Int8, int8_t)
    201         HANDLE_TYPE(INT16, Int16, int16_t)
    202         HANDLE_TYPE(INT32, Int32, int32_t)
    203         HANDLE_TYPE(INT64, Int64, int64_t)
    204         HANDLE_TYPE(UINT8, Uint8, uint8_t)
    205         HANDLE_TYPE(UINT16, Uint16, uint16_t)
    206         HANDLE_TYPE(UINT32, Uint32, uint32_t)
    207         HANDLE_TYPE(UINT64, Uint64, uint64_t)
    208         HANDLE_TYPE(FLOAT32, Float32, float)
    209         HANDLE_TYPE(FLOAT64, Float64, double)
    210 
    211 #undef HANDLE_TYPE
    212 
    213         case schema::Type::ENUM: {
    214           uint16_t typedDval = dval.getEnum();
    215           return DynamicEnum(type.asEnum(),
    216               reader.getDataField<uint16_t>(assumeDataOffset(slot.getOffset()), typedDval));
    217         }
    218 
    219         case schema::Type::TEXT: {
    220           Text::Reader typedDval = dval.isAnyPointer() ? Text::Reader() : dval.getText();
    221           return reader.getPointerField(assumePointerOffset(slot.getOffset()))
    222                        .getBlob<Text>(typedDval.begin(),
    223                            assumeMax<MAX_TEXT_SIZE>(typedDval.size()) * BYTES);
    224         }
    225 
    226         case schema::Type::DATA: {
    227           Data::Reader typedDval = dval.isAnyPointer() ? Data::Reader() : dval.getData();
    228           return reader.getPointerField(assumePointerOffset(slot.getOffset()))
    229                        .getBlob<Data>(typedDval.begin(),
    230                            assumeBits<BLOB_SIZE_BITS>(typedDval.size()) * BYTES);
    231         }
    232 
    233         case schema::Type::LIST: {
    234           auto elementType = type.asList().getElementType();
    235           return DynamicList::Reader(type.asList(),
    236               reader.getPointerField(assumePointerOffset(slot.getOffset()))
    237                     .getList(elementSizeFor(elementType.which()), dval.isAnyPointer() ? nullptr :
    238                         dval.getList().getAs<_::UncheckedMessage>()));
    239         }
    240 
    241         case schema::Type::STRUCT:
    242           return DynamicStruct::Reader(type.asStruct(),
    243               reader.getPointerField(assumePointerOffset(slot.getOffset()))
    244                     .getStruct(dval.isAnyPointer() ? nullptr :
    245                         dval.getStruct().getAs<_::UncheckedMessage>()));
    246 
    247         case schema::Type::ANY_POINTER:
    248           return AnyPointer::Reader(reader.getPointerField(assumePointerOffset(slot.getOffset())));
    249 
    250         case schema::Type::INTERFACE:
    251           return DynamicCapability::Client(type.asInterface(),
    252               reader.getPointerField(assumePointerOffset(slot.getOffset())).getCapability());
    253       }
    254 
    255       KJ_UNREACHABLE;
    256     }
    257 
    258     case schema::Field::GROUP:
    259       return DynamicStruct::Reader(type.asStruct(), reader);
    260   }
    261 
    262   KJ_UNREACHABLE;
    263 }
    264 
    265 DynamicValue::Builder DynamicStruct::Builder::get(StructSchema::Field field) {
    266   KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
    267   verifySetInUnion(field);
    268 
    269   auto proto = field.getProto();
    270   auto type = field.getType();
    271   switch (proto.which()) {
    272     case schema::Field::SLOT: {
    273       auto slot = proto.getSlot();
    274 
    275       // Note that the default value might be "anyPointer" even if the type is some poniter type
    276       // *other than* anyPointer. This happens with generics -- the field is actually a generic
    277       // parameter that has been bound, but the default value was of course compiled without any
    278       // binding available.
    279       auto dval = slot.getDefaultValue();
    280 
    281       switch (type.which()) {
    282         case schema::Type::VOID:
    283           return builder.getDataField<Void>(assumeDataOffset(slot.getOffset()));
    284 
    285 #define HANDLE_TYPE(discrim, titleCase, type) \
    286         case schema::Type::discrim: \
    287           return builder.getDataField<type>( \
    288               assumeDataOffset(slot.getOffset()), \
    289               bitCast<_::Mask<type>>(dval.get##titleCase()));
    290 
    291         HANDLE_TYPE(BOOL, Bool, bool)
    292         HANDLE_TYPE(INT8, Int8, int8_t)
    293         HANDLE_TYPE(INT16, Int16, int16_t)
    294         HANDLE_TYPE(INT32, Int32, int32_t)
    295         HANDLE_TYPE(INT64, Int64, int64_t)
    296         HANDLE_TYPE(UINT8, Uint8, uint8_t)
    297         HANDLE_TYPE(UINT16, Uint16, uint16_t)
    298         HANDLE_TYPE(UINT32, Uint32, uint32_t)
    299         HANDLE_TYPE(UINT64, Uint64, uint64_t)
    300         HANDLE_TYPE(FLOAT32, Float32, float)
    301         HANDLE_TYPE(FLOAT64, Float64, double)
    302 
    303 #undef HANDLE_TYPE
    304 
    305         case schema::Type::ENUM: {
    306           uint16_t typedDval = dval.getEnum();
    307           return DynamicEnum(type.asEnum(),
    308               builder.getDataField<uint16_t>(assumeDataOffset(slot.getOffset()), typedDval));
    309         }
    310 
    311         case schema::Type::TEXT: {
    312           Text::Reader typedDval = dval.isAnyPointer() ? Text::Reader() : dval.getText();
    313           return builder.getPointerField(assumePointerOffset(slot.getOffset()))
    314                         .getBlob<Text>(typedDval.begin(),
    315                             assumeMax<MAX_TEXT_SIZE>(typedDval.size()) * BYTES);
    316         }
    317 
    318         case schema::Type::DATA: {
    319           Data::Reader typedDval = dval.isAnyPointer() ? Data::Reader() : dval.getData();
    320           return builder.getPointerField(assumePointerOffset(slot.getOffset()))
    321                         .getBlob<Data>(typedDval.begin(),
    322                             assumeBits<BLOB_SIZE_BITS>(typedDval.size()) * BYTES);
    323         }
    324 
    325         case schema::Type::LIST: {
    326           ListSchema listType = type.asList();
    327           if (listType.whichElementType() == schema::Type::STRUCT) {
    328             return DynamicList::Builder(listType,
    329                 builder.getPointerField(assumePointerOffset(slot.getOffset()))
    330                        .getStructList(structSizeFromSchema(listType.getStructElementType()),
    331                                       dval.isAnyPointer() ? nullptr :
    332                                           dval.getList().getAs<_::UncheckedMessage>()));
    333           } else {
    334             return DynamicList::Builder(listType,
    335                 builder.getPointerField(assumePointerOffset(slot.getOffset()))
    336                        .getList(elementSizeFor(listType.whichElementType()),
    337                                 dval.isAnyPointer() ? nullptr :
    338                                     dval.getList().getAs<_::UncheckedMessage>()));
    339           }
    340         }
    341 
    342         case schema::Type::STRUCT: {
    343           auto structSchema = type.asStruct();
    344           return DynamicStruct::Builder(structSchema,
    345               builder.getPointerField(assumePointerOffset(slot.getOffset()))
    346                      .getStruct(structSizeFromSchema(structSchema),
    347                                 dval.isAnyPointer() ? nullptr :
    348                                     dval.getStruct().getAs<_::UncheckedMessage>()));
    349         }
    350 
    351         case schema::Type::ANY_POINTER:
    352           return AnyPointer::Builder(
    353               builder.getPointerField(assumePointerOffset(slot.getOffset())));
    354 
    355         case schema::Type::INTERFACE:
    356           return DynamicCapability::Client(type.asInterface(),
    357               builder.getPointerField(assumePointerOffset(slot.getOffset())).getCapability());
    358       }
    359 
    360       KJ_UNREACHABLE;
    361     }
    362 
    363     case schema::Field::GROUP:
    364       return DynamicStruct::Builder(type.asStruct(), builder);
    365   }
    366 
    367   KJ_UNREACHABLE;
    368 }
    369 
    370 DynamicValue::Pipeline DynamicStruct::Pipeline::get(StructSchema::Field field) {
    371   KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
    372 
    373   auto proto = field.getProto();
    374   KJ_REQUIRE(!hasDiscriminantValue(proto), "Can't pipeline on union members.");
    375 
    376   auto type = field.getType();
    377 
    378   switch (proto.which()) {
    379     case schema::Field::SLOT: {
    380       auto slot = proto.getSlot();
    381 
    382       switch (type.which()) {
    383         case schema::Type::STRUCT:
    384           return DynamicStruct::Pipeline(type.asStruct(),
    385               typeless.getPointerField(slot.getOffset()));
    386 
    387         case schema::Type::INTERFACE:
    388           return DynamicCapability::Client(type.asInterface(),
    389               typeless.getPointerField(slot.getOffset()).asCap());
    390 
    391         case schema::Type::ANY_POINTER:
    392           switch (type.whichAnyPointerKind()) {
    393             case schema::Type::AnyPointer::Unconstrained::STRUCT:
    394               return DynamicStruct::Pipeline(StructSchema(),
    395                   typeless.getPointerField(slot.getOffset()));
    396             case schema::Type::AnyPointer::Unconstrained::CAPABILITY:
    397               return DynamicCapability::Client(Capability::Client(
    398                   typeless.getPointerField(slot.getOffset()).asCap()));
    399             default:
    400               KJ_FAIL_REQUIRE("Can only pipeline on struct and interface fields.");
    401           }
    402 
    403         default:
    404           KJ_FAIL_REQUIRE("Can only pipeline on struct and interface fields.");
    405       }
    406 
    407       KJ_UNREACHABLE;
    408     }
    409 
    410     case schema::Field::GROUP:
    411       return DynamicStruct::Pipeline(type.asStruct(), typeless.noop());
    412   }
    413 
    414   KJ_UNREACHABLE;
    415 }
    416 
    417 bool DynamicStruct::Reader::has(StructSchema::Field field, HasMode mode) const {
    418   KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
    419 
    420   auto proto = field.getProto();
    421   if (hasDiscriminantValue(proto)) {
    422     uint16_t discrim = reader.getDataField<uint16_t>(
    423         assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()));
    424     if (discrim != proto.getDiscriminantValue()) {
    425       // Field is not active in the union.
    426       return false;
    427     }
    428   }
    429 
    430   switch (proto.which()) {
    431     case schema::Field::SLOT:
    432       // Continue to below.
    433       break;
    434 
    435     case schema::Field::GROUP:
    436       return true;
    437   }
    438 
    439   auto slot = proto.getSlot();
    440   auto type = field.getType();
    441 
    442   switch (type.which()) {
    443     case schema::Type::VOID:
    444       // Void is always equal to the default.
    445       return mode == HasMode::NON_NULL;
    446 
    447     case schema::Type::BOOL:
    448       return mode == HasMode::NON_NULL ||
    449           reader.getDataField<bool>(assumeDataOffset(slot.getOffset()), 0) != 0;
    450 
    451     case schema::Type::INT8:
    452     case schema::Type::UINT8:
    453       return mode == HasMode::NON_NULL ||
    454           reader.getDataField<uint8_t>(assumeDataOffset(slot.getOffset()), 0) != 0;
    455 
    456     case schema::Type::INT16:
    457     case schema::Type::UINT16:
    458     case schema::Type::ENUM:
    459       return mode == HasMode::NON_NULL ||
    460           reader.getDataField<uint16_t>(assumeDataOffset(slot.getOffset()), 0) != 0;
    461 
    462     case schema::Type::INT32:
    463     case schema::Type::UINT32:
    464     case schema::Type::FLOAT32:
    465       return mode == HasMode::NON_NULL ||
    466           reader.getDataField<uint32_t>(assumeDataOffset(slot.getOffset()), 0) != 0;
    467 
    468     case schema::Type::INT64:
    469     case schema::Type::UINT64:
    470     case schema::Type::FLOAT64:
    471       return mode == HasMode::NON_NULL ||
    472           reader.getDataField<uint64_t>(assumeDataOffset(slot.getOffset()), 0) != 0;
    473 
    474     case schema::Type::TEXT:
    475     case schema::Type::DATA:
    476     case schema::Type::LIST:
    477     case schema::Type::STRUCT:
    478     case schema::Type::ANY_POINTER:
    479     case schema::Type::INTERFACE:
    480       return !reader.getPointerField(assumePointerOffset(slot.getOffset())).isNull();
    481   }
    482 
    483   // Unknown type.  As far as we know, it isn't set.
    484   return false;
    485 }
    486 
    487 kj::Maybe<StructSchema::Field> DynamicStruct::Reader::which() const {
    488   auto structProto = schema.getProto().getStruct();
    489   if (structProto.getDiscriminantCount() == 0) {
    490     return nullptr;
    491   }
    492 
    493   uint16_t discrim = reader.getDataField<uint16_t>(
    494       assumeDataOffset(structProto.getDiscriminantOffset()));
    495   return schema.getFieldByDiscriminant(discrim);
    496 }
    497 
    498 kj::Maybe<StructSchema::Field> DynamicStruct::Builder::which() {
    499   auto structProto = schema.getProto().getStruct();
    500   if (structProto.getDiscriminantCount() == 0) {
    501     return nullptr;
    502   }
    503 
    504   uint16_t discrim = builder.getDataField<uint16_t>(
    505       assumeDataOffset(structProto.getDiscriminantOffset()));
    506   return schema.getFieldByDiscriminant(discrim);
    507 }
    508 
    509 void DynamicStruct::Builder::set(StructSchema::Field field, const DynamicValue::Reader& value) {
    510   KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
    511   setInUnion(field);
    512 
    513   auto proto = field.getProto();
    514   auto type = field.getType();
    515   switch (proto.which()) {
    516     case schema::Field::SLOT: {
    517       auto slot = proto.getSlot();
    518       auto dval = slot.getDefaultValue();
    519 
    520       switch (type.which()) {
    521         case schema::Type::VOID:
    522           builder.setDataField<Void>(assumeDataOffset(slot.getOffset()), value.as<Void>());
    523           return;
    524 
    525 #define HANDLE_TYPE(discrim, titleCase, type) \
    526         case schema::Type::discrim: \
    527           builder.setDataField<type>( \
    528               assumeDataOffset(slot.getOffset()), value.as<type>(), \
    529               bitCast<_::Mask<type> >(dval.get##titleCase())); \
    530           return;
    531 
    532         HANDLE_TYPE(BOOL, Bool, bool)
    533         HANDLE_TYPE(INT8, Int8, int8_t)
    534         HANDLE_TYPE(INT16, Int16, int16_t)
    535         HANDLE_TYPE(INT32, Int32, int32_t)
    536         HANDLE_TYPE(INT64, Int64, int64_t)
    537         HANDLE_TYPE(UINT8, Uint8, uint8_t)
    538         HANDLE_TYPE(UINT16, Uint16, uint16_t)
    539         HANDLE_TYPE(UINT32, Uint32, uint32_t)
    540         HANDLE_TYPE(UINT64, Uint64, uint64_t)
    541         HANDLE_TYPE(FLOAT32, Float32, float)
    542         HANDLE_TYPE(FLOAT64, Float64, double)
    543 
    544 #undef HANDLE_TYPE
    545 
    546         case schema::Type::ENUM: {
    547           uint16_t rawValue;
    548           auto enumSchema = type.asEnum();
    549           if (value.getType() == DynamicValue::TEXT) {
    550             // Convert from text.
    551             rawValue = enumSchema.getEnumerantByName(value.as<Text>()).getOrdinal();
    552           } else if (value.getType() == DynamicValue::INT ||
    553                      value.getType() == DynamicValue::UINT) {
    554             rawValue = value.as<uint16_t>();
    555           } else {
    556             DynamicEnum enumValue = value.as<DynamicEnum>();
    557             KJ_REQUIRE(enumValue.getSchema() == enumSchema, "Value type mismatch.") {
    558               return;
    559             }
    560             rawValue = enumValue.getRaw();
    561           }
    562           builder.setDataField<uint16_t>(assumeDataOffset(slot.getOffset()), rawValue,
    563                                          dval.getEnum());
    564           return;
    565         }
    566 
    567         case schema::Type::TEXT:
    568           builder.getPointerField(assumePointerOffset(slot.getOffset()))
    569                  .setBlob<Text>(value.as<Text>());
    570           return;
    571 
    572         case schema::Type::DATA:
    573           builder.getPointerField(assumePointerOffset(slot.getOffset()))
    574                  .setBlob<Data>(value.as<Data>());
    575           return;
    576 
    577         case schema::Type::LIST: {
    578           ListSchema listType = type.asList();
    579           auto listValue = value.as<DynamicList>();
    580           KJ_REQUIRE(listValue.getSchema() == listType, "Value type mismatch.") {
    581             return;
    582           }
    583           builder.getPointerField(assumePointerOffset(slot.getOffset()))
    584                  .setList(listValue.reader);
    585           return;
    586         }
    587 
    588         case schema::Type::STRUCT: {
    589           auto structType = type.asStruct();
    590           auto structValue = value.as<DynamicStruct>();
    591           KJ_REQUIRE(structValue.getSchema() == structType, "Value type mismatch.") {
    592             return;
    593           }
    594           builder.getPointerField(assumePointerOffset(slot.getOffset()))
    595                  .setStruct(structValue.reader);
    596           return;
    597         }
    598 
    599         case schema::Type::ANY_POINTER: {
    600           auto target = AnyPointer::Builder(
    601               builder.getPointerField(assumePointerOffset(slot.getOffset())));
    602 
    603           switch (value.getType()) {
    604             case DynamicValue::Type::TEXT:
    605               target.setAs<Text>(value.as<Text>());
    606               return;
    607             case DynamicValue::Type::DATA:
    608               target.setAs<Data>(value.as<Data>());
    609               return;
    610             case DynamicValue::Type::LIST:
    611               target.setAs<DynamicList>(value.as<DynamicList>());
    612               return;
    613             case DynamicValue::Type::STRUCT:
    614               target.setAs<DynamicStruct>(value.as<DynamicStruct>());
    615               return;
    616             case DynamicValue::Type::CAPABILITY:
    617               target.setAs<DynamicCapability>(value.as<DynamicCapability>());
    618               return;
    619             case DynamicValue::Type::ANY_POINTER:
    620               target.set(value.as<AnyPointer>());
    621               return;
    622 
    623             case DynamicValue::Type::UNKNOWN:
    624             case DynamicValue::Type::VOID:
    625             case DynamicValue::Type::BOOL:
    626             case DynamicValue::Type::INT:
    627             case DynamicValue::Type::UINT:
    628             case DynamicValue::Type::FLOAT:
    629             case DynamicValue::Type::ENUM:
    630               KJ_FAIL_ASSERT("Value type mismatch; expected AnyPointer");
    631           }
    632 
    633           KJ_UNREACHABLE;
    634         }
    635 
    636         case schema::Type::INTERFACE: {
    637           auto interfaceType = type.asInterface();
    638           auto capability = value.as<DynamicCapability>();
    639           KJ_REQUIRE(capability.getSchema().extends(interfaceType), "Value type mismatch.") {
    640             return;
    641           }
    642           builder.getPointerField(assumePointerOffset(slot.getOffset()))
    643                  .setCapability(kj::mv(capability.hook));
    644           return;
    645         }
    646       }
    647 
    648       KJ_UNREACHABLE;
    649     }
    650 
    651     case schema::Field::GROUP: {
    652       auto src = value.as<DynamicStruct>();
    653       auto dst = init(field).as<DynamicStruct>();
    654 
    655       KJ_IF_MAYBE(unionField, src.which()) {
    656         dst.set(*unionField, src.get(*unionField));
    657       }
    658 
    659       for (auto field: src.schema.getNonUnionFields()) {
    660         if (src.has(field)) {
    661           dst.set(field, src.get(field));
    662         }
    663       }
    664     }
    665   }
    666 
    667   KJ_UNREACHABLE;
    668 }
    669 
    670 DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Field field) {
    671   KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
    672   setInUnion(field);
    673 
    674   auto proto = field.getProto();
    675   auto type = field.getType();
    676 
    677   switch (proto.which()) {
    678     case schema::Field::SLOT: {
    679       auto slot = proto.getSlot();
    680       switch (type.which()) {
    681         case schema::Type::STRUCT: {
    682           auto subSchema = type.asStruct();
    683           return DynamicStruct::Builder(subSchema,
    684               builder.getPointerField(assumePointerOffset(slot.getOffset()))
    685                      .initStruct(structSizeFromSchema(subSchema)));
    686         }
    687         case schema::Type::ANY_POINTER: {
    688           auto pointer = builder.getPointerField(assumePointerOffset(slot.getOffset()));
    689           pointer.clear();
    690           return AnyPointer::Builder(pointer);
    691         }
    692         default:
    693           KJ_FAIL_REQUIRE("init() without a size is only valid for struct and object fields.");
    694       }
    695     }
    696 
    697     case schema::Field::GROUP: {
    698       clear(field);
    699       return DynamicStruct::Builder(type.asStruct(), builder);
    700     }
    701   }
    702 
    703   KJ_UNREACHABLE;
    704 }
    705 
    706 DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Field field, uint size) {
    707   KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
    708   setInUnion(field);
    709 
    710   auto proto = field.getProto();
    711   auto type = field.getType();
    712 
    713   switch (proto.which()) {
    714     case schema::Field::SLOT: {
    715       auto slot = proto.getSlot();
    716       switch (type.which()) {
    717         case schema::Type::LIST: {
    718           auto listType = type.asList();
    719           if (listType.whichElementType() == schema::Type::STRUCT) {
    720             return DynamicList::Builder(listType,
    721                 builder.getPointerField(assumePointerOffset(slot.getOffset()))
    722                        .initStructList(bounded(size) * ELEMENTS,
    723                                        structSizeFromSchema(listType.getStructElementType())));
    724           } else {
    725             return DynamicList::Builder(listType,
    726                 builder.getPointerField(assumePointerOffset(slot.getOffset()))
    727                        .initList(elementSizeFor(listType.whichElementType()),
    728                                  bounded(size) * ELEMENTS));
    729           }
    730         }
    731         case schema::Type::TEXT:
    732           return builder.getPointerField(assumePointerOffset(slot.getOffset()))
    733                         .initBlob<Text>(bounded(size) * BYTES);
    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               "init() with size is only valid for list, text, or data fields.",
    740               (uint)type.which());
    741           break;
    742       }
    743       KJ_UNREACHABLE;
    744     }
    745 
    746     case schema::Field::GROUP:
    747       KJ_FAIL_REQUIRE("init() with size is only valid for list, text, or data fields.");
    748   }
    749 
    750   KJ_UNREACHABLE;
    751 }
    752 
    753 void DynamicStruct::Builder::adopt(StructSchema::Field field, Orphan<DynamicValue>&& orphan) {
    754   KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
    755   setInUnion(field);
    756 
    757   auto proto = field.getProto();
    758   switch (proto.which()) {
    759     case schema::Field::SLOT: {
    760       auto slot = proto.getSlot();
    761       auto type = field.getType();
    762 
    763       switch (type.which()) {
    764         case schema::Type::VOID:
    765         case schema::Type::BOOL:
    766         case schema::Type::INT8:
    767         case schema::Type::INT16:
    768         case schema::Type::INT32:
    769         case schema::Type::INT64:
    770         case schema::Type::UINT8:
    771         case schema::Type::UINT16:
    772         case schema::Type::UINT32:
    773         case schema::Type::UINT64:
    774         case schema::Type::FLOAT32:
    775         case schema::Type::FLOAT64:
    776         case schema::Type::ENUM:
    777           set(field, orphan.getReader());
    778           return;
    779 
    780         case schema::Type::TEXT:
    781           KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch.");
    782           break;
    783 
    784         case schema::Type::DATA:
    785           KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
    786           break;
    787 
    788         case schema::Type::LIST: {
    789           ListSchema listType = type.asList();
    790           KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == listType,
    791                      "Value type mismatch.") {
    792             return;
    793           }
    794           break;
    795         }
    796 
    797         case schema::Type::STRUCT: {
    798           auto structType = type.asStruct();
    799           KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == structType,
    800                      "Value type mismatch.") {
    801             return;
    802           }
    803           break;
    804         }
    805 
    806         case schema::Type::ANY_POINTER:
    807           KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT ||
    808                      orphan.getType() == DynamicValue::LIST ||
    809                      orphan.getType() == DynamicValue::TEXT ||
    810                      orphan.getType() == DynamicValue::DATA ||
    811                      orphan.getType() == DynamicValue::CAPABILITY ||
    812                      orphan.getType() == DynamicValue::ANY_POINTER,
    813                      "Value type mismatch.") {
    814             return;
    815           }
    816           break;
    817 
    818         case schema::Type::INTERFACE: {
    819           auto interfaceType = type.asInterface();
    820           KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY &&
    821                      orphan.interfaceSchema.extends(interfaceType),
    822                      "Value type mismatch.") {
    823             return;
    824           }
    825           break;
    826         }
    827       }
    828 
    829       builder.getPointerField(assumePointerOffset(slot.getOffset())).adopt(kj::mv(orphan.builder));
    830       return;
    831     }
    832 
    833     case schema::Field::GROUP:
    834       // Have to transfer fields.
    835       auto src = orphan.get().as<DynamicStruct>();
    836       auto dst = init(field).as<DynamicStruct>();
    837 
    838       KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == dst.getSchema(),
    839                  "Value type mismatch.");
    840 
    841       KJ_IF_MAYBE(unionField, src.which()) {
    842         dst.adopt(*unionField, src.disown(*unionField));
    843       }
    844 
    845       for (auto field: src.schema.getNonUnionFields()) {
    846         if (src.has(field)) {
    847           dst.adopt(field, src.disown(field));
    848         }
    849       }
    850 
    851       return;
    852   }
    853 
    854   KJ_UNREACHABLE;
    855 }
    856 
    857 Orphan<DynamicValue> DynamicStruct::Builder::disown(StructSchema::Field field) {
    858   // We end up calling get(field) below, so we don't need to validate `field` here.
    859 
    860   auto proto = field.getProto();
    861   switch (proto.which()) {
    862     case schema::Field::SLOT: {
    863       auto slot = proto.getSlot();
    864 
    865       switch (field.getType().which()) {
    866         case schema::Type::VOID:
    867         case schema::Type::BOOL:
    868         case schema::Type::INT8:
    869         case schema::Type::INT16:
    870         case schema::Type::INT32:
    871         case schema::Type::INT64:
    872         case schema::Type::UINT8:
    873         case schema::Type::UINT16:
    874         case schema::Type::UINT32:
    875         case schema::Type::UINT64:
    876         case schema::Type::FLOAT32:
    877         case schema::Type::FLOAT64:
    878         case schema::Type::ENUM: {
    879           auto result = Orphan<DynamicValue>(get(field), _::OrphanBuilder());
    880           clear(field);
    881           return kj::mv(result);
    882         }
    883 
    884         case schema::Type::TEXT:
    885         case schema::Type::DATA:
    886         case schema::Type::LIST:
    887         case schema::Type::STRUCT:
    888         case schema::Type::ANY_POINTER:
    889         case schema::Type::INTERFACE: {
    890           auto value = get(field);
    891           return Orphan<DynamicValue>(
    892               value, builder.getPointerField(assumePointerOffset(slot.getOffset())).disown());
    893         }
    894       }
    895       KJ_UNREACHABLE;
    896     }
    897 
    898     case schema::Field::GROUP: {
    899       // We have to allocate new space for the group, unfortunately.
    900       auto src = get(field).as<DynamicStruct>();
    901 
    902       Orphan<DynamicStruct> result =
    903           Orphanage::getForMessageContaining(*this).newOrphan(src.getSchema());
    904       auto dst = result.get();
    905 
    906       KJ_IF_MAYBE(unionField, src.which()) {
    907         dst.adopt(*unionField, src.disown(*unionField));
    908       }
    909 
    910       // We need to explicitly reset the union to its default field.
    911       KJ_IF_MAYBE(unionField, src.schema.getFieldByDiscriminant(0)) {
    912         src.clear(*unionField);
    913       }
    914 
    915       for (auto field: src.schema.getNonUnionFields()) {
    916         if (src.has(field)) {
    917           dst.adopt(field, src.disown(field));
    918         }
    919       }
    920 
    921       return kj::mv(result);
    922     }
    923   }
    924 
    925   KJ_UNREACHABLE;
    926 }
    927 
    928 void DynamicStruct::Builder::clear(StructSchema::Field field) {
    929   KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
    930   setInUnion(field);
    931 
    932   auto proto = field.getProto();
    933   auto type = field.getType();
    934   switch (proto.which()) {
    935     case schema::Field::SLOT: {
    936       auto slot = proto.getSlot();
    937 
    938       switch (type.which()) {
    939         case schema::Type::VOID:
    940           builder.setDataField<Void>(assumeDataOffset(slot.getOffset()), VOID);
    941           return;
    942 
    943 #define HANDLE_TYPE(discrim, type) \
    944         case schema::Type::discrim: \
    945           builder.setDataField<type>(assumeDataOffset(slot.getOffset()), 0); \
    946           return;
    947 
    948         HANDLE_TYPE(BOOL, bool)
    949         HANDLE_TYPE(INT8, uint8_t)
    950         HANDLE_TYPE(INT16, uint16_t)
    951         HANDLE_TYPE(INT32, uint32_t)
    952         HANDLE_TYPE(INT64, uint64_t)
    953         HANDLE_TYPE(UINT8, uint8_t)
    954         HANDLE_TYPE(UINT16, uint16_t)
    955         HANDLE_TYPE(UINT32, uint32_t)
    956         HANDLE_TYPE(UINT64, uint64_t)
    957         HANDLE_TYPE(FLOAT32, uint32_t)
    958         HANDLE_TYPE(FLOAT64, uint64_t)
    959         HANDLE_TYPE(ENUM, uint16_t)
    960 
    961 #undef HANDLE_TYPE
    962 
    963         case schema::Type::TEXT:
    964         case schema::Type::DATA:
    965         case schema::Type::LIST:
    966         case schema::Type::STRUCT:
    967         case schema::Type::ANY_POINTER:
    968         case schema::Type::INTERFACE:
    969           builder.getPointerField(assumePointerOffset(slot.getOffset())).clear();
    970           return;
    971       }
    972 
    973       KJ_UNREACHABLE;
    974     }
    975 
    976     case schema::Field::GROUP: {
    977       DynamicStruct::Builder group(type.asStruct(), builder);
    978 
    979       // We clear the union field with discriminant 0 rather than the one that is set because
    980       // we want the union to end up with its default field active.
    981       KJ_IF_MAYBE(unionField, group.schema.getFieldByDiscriminant(0)) {
    982         group.clear(*unionField);
    983       }
    984 
    985       for (auto subField: group.schema.getNonUnionFields()) {
    986         group.clear(subField);
    987       }
    988       return;
    989     }
    990   }
    991 
    992   KJ_UNREACHABLE;
    993 }
    994 
    995 DynamicValue::Reader DynamicStruct::Reader::get(kj::StringPtr name) const {
    996   return get(schema.getFieldByName(name));
    997 }
    998 DynamicValue::Builder DynamicStruct::Builder::get(kj::StringPtr name) {
    999   return get(schema.getFieldByName(name));
   1000 }
   1001 DynamicValue::Pipeline DynamicStruct::Pipeline::get(kj::StringPtr name) {
   1002   return get(schema.getFieldByName(name));
   1003 }
   1004 bool DynamicStruct::Reader::has(kj::StringPtr name, HasMode mode) const {
   1005   return has(schema.getFieldByName(name), mode);
   1006 }
   1007 bool DynamicStruct::Builder::has(kj::StringPtr name, HasMode mode) {
   1008   return has(schema.getFieldByName(name), mode);
   1009 }
   1010 void DynamicStruct::Builder::set(kj::StringPtr name, const DynamicValue::Reader& value) {
   1011   set(schema.getFieldByName(name), value);
   1012 }
   1013 void DynamicStruct::Builder::set(kj::StringPtr name,
   1014                                  std::initializer_list<DynamicValue::Reader> value) {
   1015   auto list = init(name, value.size()).as<DynamicList>();
   1016   uint i = 0;
   1017   for (auto element: value) {
   1018     list.set(i++, element);
   1019   }
   1020 }
   1021 DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name) {
   1022   return init(schema.getFieldByName(name));
   1023 }
   1024 DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name, uint size) {
   1025   return init(schema.getFieldByName(name), size);
   1026 }
   1027 void DynamicStruct::Builder::adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan) {
   1028   adopt(schema.getFieldByName(name), kj::mv(orphan));
   1029 }
   1030 Orphan<DynamicValue> DynamicStruct::Builder::disown(kj::StringPtr name) {
   1031   return disown(schema.getFieldByName(name));
   1032 }
   1033 void DynamicStruct::Builder::clear(kj::StringPtr name) {
   1034   clear(schema.getFieldByName(name));
   1035 }
   1036 
   1037 // =======================================================================================
   1038 
   1039 DynamicValue::Reader DynamicList::Reader::operator[](uint index) const {
   1040   KJ_REQUIRE(index < size(), "List index out-of-bounds.");
   1041 
   1042   switch (schema.whichElementType()) {
   1043 #define HANDLE_TYPE(name, discrim, typeName) \
   1044     case schema::Type::discrim: \
   1045       return reader.getDataElement<typeName>(bounded(index) * ELEMENTS);
   1046 
   1047     HANDLE_TYPE(void, VOID, Void)
   1048     HANDLE_TYPE(bool, BOOL, bool)
   1049     HANDLE_TYPE(int8, INT8, int8_t)
   1050     HANDLE_TYPE(int16, INT16, int16_t)
   1051     HANDLE_TYPE(int32, INT32, int32_t)
   1052     HANDLE_TYPE(int64, INT64, int64_t)
   1053     HANDLE_TYPE(uint8, UINT8, uint8_t)
   1054     HANDLE_TYPE(uint16, UINT16, uint16_t)
   1055     HANDLE_TYPE(uint32, UINT32, uint32_t)
   1056     HANDLE_TYPE(uint64, UINT64, uint64_t)
   1057     HANDLE_TYPE(float32, FLOAT32, float)
   1058     HANDLE_TYPE(float64, FLOAT64, double)
   1059 #undef HANDLE_TYPE
   1060 
   1061     case schema::Type::TEXT:
   1062       return reader.getPointerElement(bounded(index) * ELEMENTS)
   1063                    .getBlob<Text>(nullptr, ZERO * BYTES);
   1064     case schema::Type::DATA:
   1065       return reader.getPointerElement(bounded(index) * ELEMENTS)
   1066                    .getBlob<Data>(nullptr, ZERO * BYTES);
   1067 
   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     }
   1074 
   1075     case schema::Type::STRUCT:
   1076       return DynamicStruct::Reader(schema.getStructElementType(),
   1077                                    reader.getStructElement(bounded(index) * ELEMENTS));
   1078 
   1079     case schema::Type::ENUM:
   1080       return DynamicEnum(schema.getEnumElementType(),
   1081                          reader.getDataElement<uint16_t>(bounded(index) * ELEMENTS));
   1082 
   1083     case schema::Type::ANY_POINTER:
   1084       return AnyPointer::Reader(reader.getPointerElement(bounded(index) * ELEMENTS));
   1085 
   1086     case schema::Type::INTERFACE:
   1087       return DynamicCapability::Client(schema.getInterfaceElementType(),
   1088                                        reader.getPointerElement(bounded(index) * ELEMENTS)
   1089                                              .getCapability());
   1090   }
   1091 
   1092   return nullptr;
   1093 }
   1094 
   1095 DynamicValue::Builder DynamicList::Builder::operator[](uint index) {
   1096   KJ_REQUIRE(index < size(), "List index out-of-bounds.");
   1097 
   1098   switch (schema.whichElementType()) {
   1099 #define HANDLE_TYPE(name, discrim, typeName) \
   1100     case schema::Type::discrim: \
   1101       return builder.getDataElement<typeName>(bounded(index) * ELEMENTS);
   1102 
   1103     HANDLE_TYPE(void, VOID, Void)
   1104     HANDLE_TYPE(bool, BOOL, bool)
   1105     HANDLE_TYPE(int8, INT8, int8_t)
   1106     HANDLE_TYPE(int16, INT16, int16_t)
   1107     HANDLE_TYPE(int32, INT32, int32_t)
   1108     HANDLE_TYPE(int64, INT64, int64_t)
   1109     HANDLE_TYPE(uint8, UINT8, uint8_t)
   1110     HANDLE_TYPE(uint16, UINT16, uint16_t)
   1111     HANDLE_TYPE(uint32, UINT32, uint32_t)
   1112     HANDLE_TYPE(uint64, UINT64, uint64_t)
   1113     HANDLE_TYPE(float32, FLOAT32, float)
   1114     HANDLE_TYPE(float64, FLOAT64, double)
   1115 #undef HANDLE_TYPE
   1116 
   1117     case schema::Type::TEXT:
   1118       return builder.getPointerElement(bounded(index) * ELEMENTS)
   1119                     .getBlob<Text>(nullptr, ZERO * BYTES);
   1120     case schema::Type::DATA:
   1121       return builder.getPointerElement(bounded(index) * ELEMENTS)
   1122                     .getBlob<Data>(nullptr, ZERO * BYTES);
   1123 
   1124     case schema::Type::LIST: {
   1125       ListSchema elementType = schema.getListElementType();
   1126       if (elementType.whichElementType() == schema::Type::STRUCT) {
   1127         return DynamicList::Builder(elementType,
   1128             builder.getPointerElement(bounded(index) * ELEMENTS)
   1129                    .getStructList(structSizeFromSchema(elementType.getStructElementType()),
   1130                                   nullptr));
   1131       } else {
   1132         return DynamicList::Builder(elementType,
   1133             builder.getPointerElement(bounded(index) * ELEMENTS)
   1134                    .getList(elementSizeFor(elementType.whichElementType()), nullptr));
   1135       }
   1136     }
   1137 
   1138     case schema::Type::STRUCT:
   1139       return DynamicStruct::Builder(schema.getStructElementType(),
   1140                                     builder.getStructElement(bounded(index) * ELEMENTS));
   1141 
   1142     case schema::Type::ENUM:
   1143       return DynamicEnum(schema.getEnumElementType(),
   1144                          builder.getDataElement<uint16_t>(bounded(index) * ELEMENTS));
   1145 
   1146     case schema::Type::ANY_POINTER:
   1147       KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
   1148       return nullptr;
   1149 
   1150     case schema::Type::INTERFACE:
   1151       return DynamicCapability::Client(schema.getInterfaceElementType(),
   1152                                        builder.getPointerElement(bounded(index) * ELEMENTS)
   1153                                               .getCapability());
   1154   }
   1155 
   1156   return nullptr;
   1157 }
   1158 
   1159 void DynamicList::Builder::set(uint index, const DynamicValue::Reader& value) {
   1160   KJ_REQUIRE(index < size(), "List index out-of-bounds.") {
   1161     return;
   1162   }
   1163 
   1164   switch (schema.whichElementType()) {
   1165 #define HANDLE_TYPE(name, discrim, typeName) \
   1166     case schema::Type::discrim: \
   1167       builder.setDataElement<typeName>(bounded(index) * ELEMENTS, value.as<typeName>()); \
   1168       return;
   1169 
   1170     HANDLE_TYPE(void, VOID, Void)
   1171     HANDLE_TYPE(bool, BOOL, bool)
   1172     HANDLE_TYPE(int8, INT8, int8_t)
   1173     HANDLE_TYPE(int16, INT16, int16_t)
   1174     HANDLE_TYPE(int32, INT32, int32_t)
   1175     HANDLE_TYPE(int64, INT64, int64_t)
   1176     HANDLE_TYPE(uint8, UINT8, uint8_t)
   1177     HANDLE_TYPE(uint16, UINT16, uint16_t)
   1178     HANDLE_TYPE(uint32, UINT32, uint32_t)
   1179     HANDLE_TYPE(uint64, UINT64, uint64_t)
   1180     HANDLE_TYPE(float32, FLOAT32, float)
   1181     HANDLE_TYPE(float64, FLOAT64, double)
   1182 #undef HANDLE_TYPE
   1183 
   1184     case schema::Type::TEXT:
   1185       builder.getPointerElement(bounded(index) * ELEMENTS).setBlob<Text>(value.as<Text>());
   1186       return;
   1187     case schema::Type::DATA:
   1188       builder.getPointerElement(bounded(index) * ELEMENTS).setBlob<Data>(value.as<Data>());
   1189       return;
   1190 
   1191     case schema::Type::LIST: {
   1192       auto listValue = value.as<DynamicList>();
   1193       KJ_REQUIRE(listValue.getSchema() == schema.getListElementType(), "Value type mismatch.") {
   1194         return;
   1195       }
   1196       builder.getPointerElement(bounded(index) * ELEMENTS).setList(listValue.reader);
   1197       return;
   1198     }
   1199 
   1200     case schema::Type::STRUCT: {
   1201       auto structValue = value.as<DynamicStruct>();
   1202       KJ_REQUIRE(structValue.getSchema() == schema.getStructElementType(), "Value type mismatch.") {
   1203         return;
   1204       }
   1205       builder.getStructElement(bounded(index) * ELEMENTS).copyContentFrom(structValue.reader);
   1206       return;
   1207     }
   1208 
   1209     case schema::Type::ENUM: {
   1210       uint16_t rawValue;
   1211       if (value.getType() == DynamicValue::TEXT) {
   1212         // Convert from text.
   1213         rawValue = schema.getEnumElementType().getEnumerantByName(value.as<Text>()).getOrdinal();
   1214       } else {
   1215         DynamicEnum enumValue = value.as<DynamicEnum>();
   1216         KJ_REQUIRE(schema.getEnumElementType() == enumValue.getSchema(),
   1217                    "Type mismatch when using DynamicList::Builder::set().") {
   1218           return;
   1219         }
   1220         rawValue = enumValue.getRaw();
   1221       }
   1222       builder.setDataElement<uint16_t>(bounded(index) * ELEMENTS, rawValue);
   1223       return;
   1224     }
   1225 
   1226     case schema::Type::ANY_POINTER:
   1227       KJ_FAIL_ASSERT("List(AnyPointer) not supported.") {
   1228         return;
   1229       }
   1230 
   1231     case schema::Type::INTERFACE: {
   1232       auto capValue = value.as<DynamicCapability>();
   1233       KJ_REQUIRE(capValue.getSchema().extends(schema.getInterfaceElementType()),
   1234                  "Value type mismatch.") {
   1235         return;
   1236       }
   1237       builder.getPointerElement(bounded(index) * ELEMENTS).setCapability(kj::mv(capValue.hook));
   1238       return;
   1239     }
   1240   }
   1241 
   1242   KJ_FAIL_REQUIRE("can't set element of unknown type", (uint)schema.whichElementType()) {
   1243     return;
   1244   }
   1245 }
   1246 
   1247 DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) {
   1248   KJ_REQUIRE(index < this->size(), "List index out-of-bounds.");
   1249 
   1250   switch (schema.whichElementType()) {
   1251     case schema::Type::VOID:
   1252     case schema::Type::BOOL:
   1253     case schema::Type::INT8:
   1254     case schema::Type::INT16:
   1255     case schema::Type::INT32:
   1256     case schema::Type::INT64:
   1257     case schema::Type::UINT8:
   1258     case schema::Type::UINT16:
   1259     case schema::Type::UINT32:
   1260     case schema::Type::UINT64:
   1261     case schema::Type::FLOAT32:
   1262     case schema::Type::FLOAT64:
   1263     case schema::Type::ENUM:
   1264     case schema::Type::STRUCT:
   1265     case schema::Type::INTERFACE:
   1266       KJ_FAIL_REQUIRE("Expected a list or blob.");
   1267       return nullptr;
   1268 
   1269     case schema::Type::TEXT:
   1270       return builder.getPointerElement(bounded(index) * ELEMENTS)
   1271                     .initBlob<Text>(bounded(size) * BYTES);
   1272 
   1273     case schema::Type::DATA:
   1274       return builder.getPointerElement(bounded(index) * ELEMENTS)
   1275                     .initBlob<Data>(bounded(size) * BYTES);
   1276 
   1277     case schema::Type::LIST: {
   1278       auto elementType = schema.getListElementType();
   1279 
   1280       if (elementType.whichElementType() == schema::Type::STRUCT) {
   1281         return DynamicList::Builder(elementType,
   1282             builder.getPointerElement(bounded(index) * ELEMENTS)
   1283                    .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));
   1290       }
   1291     }
   1292 
   1293     case schema::Type::ANY_POINTER: {
   1294       KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
   1295       return nullptr;
   1296     }
   1297   }
   1298 
   1299   return nullptr;
   1300 }
   1301 
   1302 void DynamicList::Builder::adopt(uint index, Orphan<DynamicValue>&& orphan) {
   1303   switch (schema.whichElementType()) {
   1304     case schema::Type::VOID:
   1305     case schema::Type::BOOL:
   1306     case schema::Type::INT8:
   1307     case schema::Type::INT16:
   1308     case schema::Type::INT32:
   1309     case schema::Type::INT64:
   1310     case schema::Type::UINT8:
   1311     case schema::Type::UINT16:
   1312     case schema::Type::UINT32:
   1313     case schema::Type::UINT64:
   1314     case schema::Type::FLOAT32:
   1315     case schema::Type::FLOAT64:
   1316     case schema::Type::ENUM:
   1317       set(index, orphan.getReader());
   1318       return;
   1319 
   1320     case schema::Type::TEXT:
   1321       KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch.");
   1322       builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
   1323       return;
   1324 
   1325     case schema::Type::DATA:
   1326       KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
   1327       builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
   1328       return;
   1329 
   1330     case schema::Type::LIST: {
   1331       ListSchema elementType = schema.getListElementType();
   1332       KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == elementType,
   1333                  "Value type mismatch.");
   1334       builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
   1335       return;
   1336     }
   1337 
   1338     case schema::Type::STRUCT: {
   1339       auto elementType = schema.getStructElementType();
   1340       KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == elementType,
   1341                  "Value type mismatch.");
   1342       builder.getStructElement(bounded(index) * ELEMENTS).transferContentFrom(
   1343           orphan.builder.asStruct(structSizeFromSchema(elementType)));
   1344       return;
   1345     }
   1346 
   1347     case schema::Type::ANY_POINTER:
   1348       KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
   1349 
   1350     case schema::Type::INTERFACE: {
   1351       auto elementType = schema.getInterfaceElementType();
   1352       KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY &&
   1353                  orphan.interfaceSchema.extends(elementType),
   1354                  "Value type mismatch.");
   1355       builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
   1356       return;
   1357     }
   1358   }
   1359 
   1360   KJ_UNREACHABLE;
   1361 }
   1362 
   1363 Orphan<DynamicValue> DynamicList::Builder::disown(uint index) {
   1364   switch (schema.whichElementType()) {
   1365     case schema::Type::VOID:
   1366     case schema::Type::BOOL:
   1367     case schema::Type::INT8:
   1368     case schema::Type::INT16:
   1369     case schema::Type::INT32:
   1370     case schema::Type::INT64:
   1371     case schema::Type::UINT8:
   1372     case schema::Type::UINT16:
   1373     case schema::Type::UINT32:
   1374     case schema::Type::UINT64:
   1375     case schema::Type::FLOAT32:
   1376     case schema::Type::FLOAT64:
   1377     case schema::Type::ENUM: {
   1378       auto result = Orphan<DynamicValue>(operator[](index), _::OrphanBuilder());
   1379       switch (elementSizeFor(schema.whichElementType())) {
   1380         case ElementSize::VOID: break;
   1381         case ElementSize::BIT: builder.setDataElement<bool>(bounded(index) * ELEMENTS, false); break;
   1382         case ElementSize::BYTE: builder.setDataElement<uint8_t>(bounded(index) * ELEMENTS, 0); break;
   1383         case ElementSize::TWO_BYTES: builder.setDataElement<uint16_t>(bounded(index) * ELEMENTS, 0); break;
   1384         case ElementSize::FOUR_BYTES: builder.setDataElement<uint32_t>(bounded(index) * ELEMENTS, 0); break;
   1385         case ElementSize::EIGHT_BYTES: builder.setDataElement<uint64_t>(bounded(index) * ELEMENTS, 0);break;
   1386 
   1387         case ElementSize::POINTER:
   1388         case ElementSize::INLINE_COMPOSITE:
   1389           KJ_UNREACHABLE;
   1390       }
   1391       return kj::mv(result);
   1392     }
   1393 
   1394     case schema::Type::TEXT:
   1395     case schema::Type::DATA:
   1396     case schema::Type::LIST:
   1397     case schema::Type::ANY_POINTER:
   1398     case schema::Type::INTERFACE: {
   1399       auto value = operator[](index);
   1400       return Orphan<DynamicValue>(value, builder.getPointerElement(bounded(index) * ELEMENTS).disown());
   1401     }
   1402 
   1403     case schema::Type::STRUCT: {
   1404       // We have to make a copy.
   1405       Orphan<DynamicStruct> result =
   1406           Orphanage::getForMessageContaining(*this).newOrphan(schema.getStructElementType());
   1407       auto element = builder.getStructElement(bounded(index) * ELEMENTS);
   1408       result.get().builder.transferContentFrom(element);
   1409       element.clearAll();
   1410       return kj::mv(result);
   1411     }
   1412   }
   1413   KJ_UNREACHABLE;
   1414 }
   1415 
   1416 void DynamicList::Builder::copyFrom(std::initializer_list<DynamicValue::Reader> value) {
   1417   KJ_REQUIRE(value.size() == size(), "DynamicList::copyFrom() argument had different size.");
   1418   uint i = 0;
   1419   for (auto element: value) {
   1420     set(i++, element);
   1421   }
   1422 }
   1423 
   1424 DynamicList::Reader DynamicList::Builder::asReader() const {
   1425   return DynamicList::Reader(schema, builder.asReader());
   1426 }
   1427 
   1428 // =======================================================================================
   1429 
   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     case schema::Type::VOID: *this = capnp::VOID; break;
   1435     case schema::Type::BOOL: *this = value.getBool(); break;
   1436     case schema::Type::INT8: *this = value.getInt8(); break;
   1437     case schema::Type::INT16: *this = value.getInt16(); break;
   1438     case schema::Type::INT32: *this = value.getInt32(); break;
   1439     case schema::Type::INT64: *this = value.getInt64(); break;
   1440     case schema::Type::UINT8: *this = value.getUint8(); break;
   1441     case schema::Type::UINT16: *this = value.getUint16(); break;
   1442     case schema::Type::UINT32: *this = value.getUint32(); break;
   1443     case schema::Type::UINT64: *this = value.getUint64(); break;
   1444     case schema::Type::FLOAT32: *this = value.getFloat32(); break;
   1445     case schema::Type::FLOAT64: *this = value.getFloat64(); break;
   1446     case schema::Type::TEXT: *this = value.getText(); break;
   1447     case schema::Type::DATA: *this = value.getData(); break;
   1448 
   1449     case schema::Type::ENUM:
   1450       *this = DynamicEnum(type.asEnum(), value.getEnum());
   1451       break;
   1452 
   1453     case schema::Type::STRUCT:
   1454       *this = value.getStruct().getAs<DynamicStruct>(type.asStruct());
   1455       break;
   1456 
   1457     case schema::Type::LIST:
   1458       *this = value.getList().getAs<DynamicList>(type.asList());
   1459       break;
   1460 
   1461     case schema::Type::ANY_POINTER:
   1462       *this = value.getAnyPointer();
   1463       break;
   1464 
   1465     case schema::Type::INTERFACE:
   1466       KJ_FAIL_ASSERT("Constants can't have interface type.");
   1467   }
   1468 }
   1469 
   1470 #if __GNUC__ && !__clang__ && __GNUC__ >= 9
   1471 // In the copy constructors below, we use memcpy() to copy only after verifying that it is safe.
   1472 // But GCC 9 doesn't know we've checked, and whines. I suppose GCC is probably right: our checks
   1473 // probably don't technically make memcpy safe according to the standard. But it works in practice,
   1474 // and if it ever stops working, the tests will catch it.
   1475 #pragma GCC diagnostic ignored "-Wclass-memaccess"
   1476 #endif
   1477 
   1478 DynamicValue::Reader::Reader(const Reader& other) {
   1479   switch (other.type) {
   1480     case UNKNOWN:
   1481     case VOID:
   1482     case BOOL:
   1483     case INT:
   1484     case UINT:
   1485     case FLOAT:
   1486     case TEXT:
   1487     case DATA:
   1488     case LIST:
   1489     case ENUM:
   1490     case STRUCT:
   1491     case ANY_POINTER:
   1492       KJ_ASSERT_CAN_MEMCPY(Text::Reader);
   1493       KJ_ASSERT_CAN_MEMCPY(Data::Reader);
   1494       KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader);
   1495       KJ_ASSERT_CAN_MEMCPY(DynamicEnum);
   1496       KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader);
   1497       KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader);
   1498       break;
   1499 
   1500     case CAPABILITY:
   1501       type = CAPABILITY;
   1502       kj::ctor(capabilityValue, other.capabilityValue);
   1503       return;
   1504   }
   1505 
   1506   memcpy(this, &other, sizeof(*this));
   1507 }
   1508 DynamicValue::Reader::Reader(Reader&& other) noexcept {
   1509   switch (other.type) {
   1510     case UNKNOWN:
   1511     case VOID:
   1512     case BOOL:
   1513     case INT:
   1514     case UINT:
   1515     case FLOAT:
   1516     case TEXT:
   1517     case DATA:
   1518     case LIST:
   1519     case ENUM:
   1520     case STRUCT:
   1521     case ANY_POINTER:
   1522       KJ_ASSERT_CAN_MEMCPY(Text::Reader);
   1523       KJ_ASSERT_CAN_MEMCPY(Data::Reader);
   1524       KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader);
   1525       KJ_ASSERT_CAN_MEMCPY(DynamicEnum);
   1526       KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader);
   1527       KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader);
   1528       break;
   1529 
   1530     case CAPABILITY:
   1531       type = CAPABILITY;
   1532       kj::ctor(capabilityValue, kj::mv(other.capabilityValue));
   1533       return;
   1534   }
   1535 
   1536   memcpy(this, &other, sizeof(*this));
   1537 }
   1538 DynamicValue::Reader::~Reader() noexcept(false) {
   1539   if (type == CAPABILITY) {
   1540     kj::dtor(capabilityValue);
   1541   }
   1542 }
   1543 
   1544 DynamicValue::Reader& DynamicValue::Reader::operator=(const Reader& other) {
   1545   if (type == CAPABILITY) {
   1546     kj::dtor(capabilityValue);
   1547   }
   1548   kj::ctor(*this, other);
   1549   return *this;
   1550 }
   1551 DynamicValue::Reader& DynamicValue::Reader::operator=(Reader&& other) {
   1552   if (type == CAPABILITY) {
   1553     kj::dtor(capabilityValue);
   1554   }
   1555   kj::ctor(*this, kj::mv(other));
   1556   return *this;
   1557 }
   1558 
   1559 DynamicValue::Builder::Builder(Builder& other) {
   1560   switch (other.type) {
   1561     case UNKNOWN:
   1562     case VOID:
   1563     case BOOL:
   1564     case INT:
   1565     case UINT:
   1566     case FLOAT:
   1567     case TEXT:
   1568     case DATA:
   1569     case LIST:
   1570     case ENUM:
   1571     case STRUCT:
   1572     case ANY_POINTER:
   1573       // Unfortunately canMemcpy() doesn't work on these types due to the use of
   1574       // DisallowConstCopy, but __has_trivial_destructor should detect if any of these types
   1575       // become non-trivial.
   1576       static_assert(__has_trivial_destructor(Text::Builder) &&
   1577                     __has_trivial_destructor(Data::Builder) &&
   1578                     __has_trivial_destructor(DynamicList::Builder) &&
   1579                     __has_trivial_destructor(DynamicEnum) &&
   1580                     __has_trivial_destructor(DynamicStruct::Builder) &&
   1581                     __has_trivial_destructor(AnyPointer::Builder),
   1582                     "Assumptions here don't hold.");
   1583       break;
   1584 
   1585     case CAPABILITY:
   1586       type = CAPABILITY;
   1587       kj::ctor(capabilityValue, other.capabilityValue);
   1588       return;
   1589   }
   1590 
   1591   memcpy(this, &other, sizeof(*this));
   1592 }
   1593 DynamicValue::Builder::Builder(Builder&& other) noexcept {
   1594   switch (other.type) {
   1595     case UNKNOWN:
   1596     case VOID:
   1597     case BOOL:
   1598     case INT:
   1599     case UINT:
   1600     case FLOAT:
   1601     case TEXT:
   1602     case DATA:
   1603     case LIST:
   1604     case ENUM:
   1605     case STRUCT:
   1606     case ANY_POINTER:
   1607       // Unfortunately __has_trivial_copy doesn't work on these types due to the use of
   1608       // DisallowConstCopy, but __has_trivial_destructor should detect if any of these types
   1609       // become non-trivial.
   1610       static_assert(__has_trivial_destructor(Text::Builder) &&
   1611                     __has_trivial_destructor(Data::Builder) &&
   1612                     __has_trivial_destructor(DynamicList::Builder) &&
   1613                     __has_trivial_destructor(DynamicEnum) &&
   1614                     __has_trivial_destructor(DynamicStruct::Builder) &&
   1615                     __has_trivial_destructor(AnyPointer::Builder),
   1616                     "Assumptions here don't hold.");
   1617       break;
   1618 
   1619     case CAPABILITY:
   1620       type = CAPABILITY;
   1621       kj::ctor(capabilityValue, kj::mv(other.capabilityValue));
   1622       return;
   1623   }
   1624 
   1625   memcpy(this, &other, sizeof(*this));
   1626 }
   1627 DynamicValue::Builder::~Builder() noexcept(false) {
   1628   if (type == CAPABILITY) {
   1629     kj::dtor(capabilityValue);
   1630   }
   1631 }
   1632 
   1633 DynamicValue::Builder& DynamicValue::Builder::operator=(Builder& other) {
   1634   if (type == CAPABILITY) {
   1635     kj::dtor(capabilityValue);
   1636   }
   1637   kj::ctor(*this, other);
   1638   return *this;
   1639 }
   1640 DynamicValue::Builder& DynamicValue::Builder::operator=(Builder&& other) {
   1641   if (type == CAPABILITY) {
   1642     kj::dtor(capabilityValue);
   1643   }
   1644   kj::ctor(*this, kj::mv(other));
   1645   return *this;
   1646 }
   1647 
   1648 DynamicValue::Reader DynamicValue::Builder::asReader() const {
   1649   switch (type) {
   1650     case UNKNOWN: return Reader();
   1651     case VOID: return Reader(voidValue);
   1652     case BOOL: return Reader(boolValue);
   1653     case INT: return Reader(intValue);
   1654     case UINT: return Reader(uintValue);
   1655     case FLOAT: return Reader(floatValue);
   1656     case TEXT: return Reader(textValue.asReader());
   1657     case DATA: return Reader(dataValue.asReader());
   1658     case LIST: return Reader(listValue.asReader());
   1659     case ENUM: return Reader(enumValue);
   1660     case STRUCT: return Reader(structValue.asReader());
   1661     case CAPABILITY: return Reader(capabilityValue);
   1662     case ANY_POINTER: return Reader(anyPointerValue.asReader());
   1663   }
   1664   KJ_FAIL_ASSERT("Missing switch case.");
   1665   return Reader();
   1666 }
   1667 
   1668 DynamicValue::Pipeline::Pipeline(Pipeline&& other) noexcept: type(other.type) {
   1669   switch (type) {
   1670     case UNKNOWN: break;
   1671     case STRUCT: kj::ctor(structValue, kj::mv(other.structValue)); break;
   1672     case CAPABILITY: kj::ctor(capabilityValue, kj::mv(other.capabilityValue)); break;
   1673     default:
   1674       KJ_LOG(ERROR, "Unexpected pipeline type.", (uint)type);
   1675       type = UNKNOWN;
   1676       break;
   1677   }
   1678 }
   1679 DynamicValue::Pipeline& DynamicValue::Pipeline::operator=(Pipeline&& other) {
   1680   kj::dtor(*this);
   1681   kj::ctor(*this, kj::mv(other));
   1682   return *this;
   1683 }
   1684 DynamicValue::Pipeline::~Pipeline() noexcept(false) {
   1685   switch (type) {
   1686     case UNKNOWN: break;
   1687     case STRUCT: kj::dtor(structValue); break;
   1688     case CAPABILITY: kj::dtor(capabilityValue); break;
   1689     default:
   1690       KJ_FAIL_ASSERT("Unexpected pipeline type.", (uint)type) { type = UNKNOWN; break; }
   1691       break;
   1692   }
   1693 }
   1694 
   1695 namespace {
   1696 
   1697 template <typename T>
   1698 T signedToUnsigned(long long value) {
   1699   KJ_REQUIRE(value >= 0 && T(value) == value, "Value out-of-range for requested type.", value) {
   1700     // Use it anyway.
   1701     break;
   1702   }
   1703   return value;
   1704 }
   1705 
   1706 template <>
   1707 uint64_t signedToUnsigned<uint64_t>(long long value) {
   1708   KJ_REQUIRE(value >= 0, "Value out-of-range for requested type.", value) {
   1709     // Use it anyway.
   1710     break;
   1711   }
   1712   return value;
   1713 }
   1714 
   1715 template <typename T>
   1716 T unsignedToSigned(unsigned long long value) {
   1717   KJ_REQUIRE(T(value) >= 0 && (unsigned long long)T(value) == value,
   1718              "Value out-of-range for requested type.", value) {
   1719     // Use it anyway.
   1720     break;
   1721   }
   1722   return value;
   1723 }
   1724 
   1725 template <>
   1726 int64_t unsignedToSigned<int64_t>(unsigned long long value) {
   1727   KJ_REQUIRE(int64_t(value) >= 0, "Value out-of-range for requested type.", value) {
   1728     // Use it anyway.
   1729     break;
   1730   }
   1731   return value;
   1732 }
   1733 
   1734 template <typename T, typename U>
   1735 T checkRoundTrip(U value) {
   1736   T result = value;
   1737   KJ_REQUIRE(U(result) == value, "Value out-of-range for requested type.", value) {
   1738     // Use it anyway.
   1739     break;
   1740   }
   1741   return result;
   1742 }
   1743 
   1744 template <typename T, typename U>
   1745 T checkRoundTripFromFloat(U value) {
   1746   // When `U` is `float` or `double`, we have to use a different approach, because casting an
   1747   // out-of-range float to an integer is, surprisingly, UB.
   1748   constexpr T MIN = kj::minValue;
   1749   constexpr T MAX = kj::maxValue;
   1750   KJ_REQUIRE(value >= U(MIN), "Value out-of-range for requested type.", value) {
   1751     return MIN;
   1752   }
   1753   KJ_REQUIRE(value <= U(MAX), "Value out-of-range for requested type.", value) {
   1754     return MAX;
   1755   }
   1756   T result = value;
   1757   KJ_REQUIRE(U(result) == value, "Value out-of-range for requested type.", value) {
   1758     // Use it anyway.
   1759     break;
   1760   }
   1761   return result;
   1762 }
   1763 
   1764 }  // namespace
   1765 
   1766 #define HANDLE_NUMERIC_TYPE(typeName, ifInt, ifUint, ifFloat) \
   1767 typeName DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
   1768   switch (reader.type) { \
   1769     case INT: \
   1770       return ifInt<typeName>(reader.intValue); \
   1771     case UINT: \
   1772       return ifUint<typeName>(reader.uintValue); \
   1773     case FLOAT: \
   1774       return ifFloat<typeName>(reader.floatValue); \
   1775     default: \
   1776       KJ_FAIL_REQUIRE("Value type mismatch.") { \
   1777         return 0; \
   1778       } \
   1779   } \
   1780 } \
   1781 typeName DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
   1782   switch (builder.type) { \
   1783     case INT: \
   1784       return ifInt<typeName>(builder.intValue); \
   1785     case UINT: \
   1786       return ifUint<typeName>(builder.uintValue); \
   1787     case FLOAT: \
   1788       return ifFloat<typeName>(builder.floatValue); \
   1789     default: \
   1790       KJ_FAIL_REQUIRE("Value type mismatch.") { \
   1791         return 0; \
   1792       } \
   1793   } \
   1794 }
   1795 
   1796 HANDLE_NUMERIC_TYPE(int8_t, checkRoundTrip, unsignedToSigned, checkRoundTripFromFloat)
   1797 HANDLE_NUMERIC_TYPE(int16_t, checkRoundTrip, unsignedToSigned, checkRoundTripFromFloat)
   1798 HANDLE_NUMERIC_TYPE(int32_t, checkRoundTrip, unsignedToSigned, checkRoundTripFromFloat)
   1799 HANDLE_NUMERIC_TYPE(int64_t, kj::implicitCast, unsignedToSigned, checkRoundTripFromFloat)
   1800 HANDLE_NUMERIC_TYPE(uint8_t, signedToUnsigned, checkRoundTrip, checkRoundTripFromFloat)
   1801 HANDLE_NUMERIC_TYPE(uint16_t, signedToUnsigned, checkRoundTrip, checkRoundTripFromFloat)
   1802 HANDLE_NUMERIC_TYPE(uint32_t, signedToUnsigned, checkRoundTrip, checkRoundTripFromFloat)
   1803 HANDLE_NUMERIC_TYPE(uint64_t, signedToUnsigned, kj::implicitCast, checkRoundTripFromFloat)
   1804 HANDLE_NUMERIC_TYPE(float, kj::implicitCast, kj::implicitCast, kj::implicitCast)
   1805 HANDLE_NUMERIC_TYPE(double, kj::implicitCast, kj::implicitCast, kj::implicitCast)
   1806 
   1807 #undef HANDLE_NUMERIC_TYPE
   1808 
   1809 #define HANDLE_TYPE(name, discrim, typeName) \
   1810 ReaderFor<typeName> DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
   1811   KJ_REQUIRE(reader.type == discrim, "Value type mismatch.") { \
   1812     return ReaderFor<typeName>(); \
   1813   } \
   1814   return reader.name##Value; \
   1815 } \
   1816 BuilderFor<typeName> DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
   1817   KJ_REQUIRE(builder.type == discrim, "Value type mismatch."); \
   1818   return builder.name##Value; \
   1819 }
   1820 
   1821 //HANDLE_TYPE(void, VOID, Void)
   1822 HANDLE_TYPE(bool, BOOL, bool)
   1823 
   1824 HANDLE_TYPE(text, TEXT, Text)
   1825 HANDLE_TYPE(list, LIST, DynamicList)
   1826 HANDLE_TYPE(struct, STRUCT, DynamicStruct)
   1827 HANDLE_TYPE(enum, ENUM, DynamicEnum)
   1828 HANDLE_TYPE(anyPointer, ANY_POINTER, AnyPointer)
   1829 
   1830 #undef HANDLE_TYPE
   1831 
   1832 PipelineFor<DynamicStruct> DynamicValue::Pipeline::AsImpl<DynamicStruct>::apply(
   1833     Pipeline& pipeline) {
   1834   KJ_REQUIRE(pipeline.type == STRUCT, "Pipeline type mismatch.");
   1835   return kj::mv(pipeline.structValue);
   1836 }
   1837 
   1838 ReaderFor<DynamicCapability> DynamicValue::Reader::AsImpl<DynamicCapability>::apply(
   1839     const Reader& reader) {
   1840   KJ_REQUIRE(reader.type == CAPABILITY, "Value type mismatch.") {
   1841     return DynamicCapability::Client();
   1842   }
   1843   return reader.capabilityValue;
   1844 }
   1845 BuilderFor<DynamicCapability> DynamicValue::Builder::AsImpl<DynamicCapability>::apply(
   1846     Builder& builder) {
   1847   KJ_REQUIRE(builder.type == CAPABILITY, "Value type mismatch.") {
   1848     return DynamicCapability::Client();
   1849   }
   1850   return builder.capabilityValue;
   1851 }
   1852 PipelineFor<DynamicCapability> DynamicValue::Pipeline::AsImpl<DynamicCapability>::apply(
   1853     Pipeline& pipeline) {
   1854   KJ_REQUIRE(pipeline.type == CAPABILITY, "Pipeline type mismatch.") {
   1855     return DynamicCapability::Client();
   1856   }
   1857   return kj::mv(pipeline.capabilityValue);
   1858 }
   1859 
   1860 Data::Reader DynamicValue::Reader::AsImpl<Data>::apply(const Reader& reader) {
   1861   if (reader.type == TEXT) {
   1862     // Coerce text to data.
   1863     return reader.textValue.asBytes();
   1864   }
   1865   KJ_REQUIRE(reader.type == DATA, "Value type mismatch.") {
   1866     return Data::Reader();
   1867   }
   1868   return reader.dataValue;
   1869 }
   1870 Data::Builder DynamicValue::Builder::AsImpl<Data>::apply(Builder& builder) {
   1871   if (builder.type == TEXT) {
   1872     // Coerce text to data.
   1873     return builder.textValue.asBytes();
   1874   }
   1875   KJ_REQUIRE(builder.type == DATA, "Value type mismatch.") {
   1876     return BuilderFor<Data>();
   1877   }
   1878   return builder.dataValue;
   1879 }
   1880 
   1881 // As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
   1882 Void DynamicValue::Reader::AsImpl<Void>::apply(const Reader& reader) {
   1883   KJ_REQUIRE(reader.type == VOID, "Value type mismatch.") {
   1884     return Void();
   1885   }
   1886   return reader.voidValue;
   1887 }
   1888 Void DynamicValue::Builder::AsImpl<Void>::apply(Builder& builder) {
   1889   KJ_REQUIRE(builder.type == VOID, "Value type mismatch.") {
   1890     return Void();
   1891   }
   1892   return builder.voidValue;
   1893 }
   1894 
   1895 // =======================================================================================
   1896 
   1897 namespace _ {  // private
   1898 
   1899 DynamicStruct::Reader PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
   1900     PointerReader reader, StructSchema schema) {
   1901   KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
   1902              "Cannot form pointer to group type.");
   1903   return DynamicStruct::Reader(schema, reader.getStruct(nullptr));
   1904 }
   1905 DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
   1906     PointerBuilder builder, StructSchema schema) {
   1907   KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
   1908              "Cannot form pointer to group type.");
   1909   return DynamicStruct::Builder(schema, builder.getStruct(
   1910       structSizeFromSchema(schema), nullptr));
   1911 }
   1912 void PointerHelpers<DynamicStruct, Kind::OTHER>::set(
   1913     PointerBuilder builder, const DynamicStruct::Reader& value) {
   1914   KJ_REQUIRE(!value.schema.getProto().getStruct().getIsGroup(),
   1915              "Cannot form pointer to group type.");
   1916   builder.setStruct(value.reader);
   1917 }
   1918 DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::init(
   1919     PointerBuilder builder, StructSchema schema) {
   1920   KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
   1921              "Cannot form pointer to group type.");
   1922   return DynamicStruct::Builder(schema,
   1923       builder.initStruct(structSizeFromSchema(schema)));
   1924 }
   1925 
   1926 DynamicList::Reader PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
   1927     PointerReader reader, ListSchema schema) {
   1928   return DynamicList::Reader(schema,
   1929       reader.getList(elementSizeFor(schema.whichElementType()), nullptr));
   1930 }
   1931 DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
   1932     PointerBuilder builder, ListSchema schema) {
   1933   if (schema.whichElementType() == schema::Type::STRUCT) {
   1934     return DynamicList::Builder(schema,
   1935         builder.getStructList(
   1936             structSizeFromSchema(schema.getStructElementType()),
   1937             nullptr));
   1938   } else {
   1939     return DynamicList::Builder(schema,
   1940         builder.getList(elementSizeFor(schema.whichElementType()), nullptr));
   1941   }
   1942 }
   1943 void PointerHelpers<DynamicList, Kind::OTHER>::set(
   1944     PointerBuilder builder, const DynamicList::Reader& value) {
   1945   builder.setList(value.reader);
   1946 }
   1947 DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::init(
   1948     PointerBuilder builder, ListSchema schema, uint size) {
   1949   if (schema.whichElementType() == schema::Type::STRUCT) {
   1950     return DynamicList::Builder(schema,
   1951         builder.initStructList(bounded(size) * ELEMENTS,
   1952             structSizeFromSchema(schema.getStructElementType())));
   1953   } else {
   1954     return DynamicList::Builder(schema,
   1955         builder.initList(elementSizeFor(schema.whichElementType()), bounded(size) * ELEMENTS));
   1956   }
   1957 }
   1958 
   1959 DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
   1960     PointerReader reader, InterfaceSchema schema) {
   1961   return DynamicCapability::Client(schema, reader.getCapability());
   1962 }
   1963 DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
   1964     PointerBuilder builder, InterfaceSchema schema) {
   1965   return DynamicCapability::Client(schema, builder.getCapability());
   1966 }
   1967 void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
   1968     PointerBuilder builder, DynamicCapability::Client& value) {
   1969   builder.setCapability(value.hook->addRef());
   1970 }
   1971 void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
   1972     PointerBuilder builder, DynamicCapability::Client&& value) {
   1973   builder.setCapability(kj::mv(value.hook));
   1974 }
   1975 
   1976 }  // namespace _ (private)
   1977 
   1978 template <>
   1979 void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan) {
   1980   switch (orphan.getType()) {
   1981     case DynamicValue::UNKNOWN:
   1982     case DynamicValue::VOID:
   1983     case DynamicValue::BOOL:
   1984     case DynamicValue::INT:
   1985     case DynamicValue::UINT:
   1986     case DynamicValue::FLOAT:
   1987     case DynamicValue::ENUM:
   1988       KJ_FAIL_REQUIRE("AnyPointer cannot adopt primitive (non-object) value.");
   1989 
   1990     case DynamicValue::STRUCT:
   1991     case DynamicValue::LIST:
   1992     case DynamicValue::TEXT:
   1993     case DynamicValue::DATA:
   1994     case DynamicValue::CAPABILITY:
   1995     case DynamicValue::ANY_POINTER:
   1996       builder.adopt(kj::mv(orphan.builder));
   1997       break;
   1998   }
   1999 }
   2000 
   2001 DynamicStruct::Reader::Reader(StructSchema schema, const _::OrphanBuilder& orphan)
   2002     : schema(schema), reader(orphan.asStructReader(structSizeFromSchema(schema))) {}
   2003 DynamicStruct::Builder::Builder(StructSchema schema, _::OrphanBuilder& orphan)
   2004     : schema(schema), builder(orphan.asStruct(structSizeFromSchema(schema))) {}
   2005 
   2006 DynamicList::Reader::Reader(ListSchema schema, const _::OrphanBuilder& orphan)
   2007     : schema(schema), reader(orphan.asListReader(elementSizeFor(schema.whichElementType()))) {}
   2008 DynamicList::Builder::Builder(ListSchema schema, _::OrphanBuilder& orphan)
   2009     : schema(schema), builder(schema.whichElementType() == schema::Type::STRUCT
   2010         ? orphan.asStructList(structSizeFromSchema(schema.getStructElementType()))
   2011         : orphan.asList(elementSizeFor(schema.whichElementType()))) {}
   2012 
   2013 // -------------------------------------------------------------------
   2014 
   2015 Orphan<DynamicStruct> Orphanage::newOrphan(StructSchema schema) const {
   2016   return Orphan<DynamicStruct>(
   2017       schema, _::OrphanBuilder::initStruct(arena, capTable, structSizeFromSchema(schema)));
   2018 }
   2019 
   2020 Orphan<DynamicList> Orphanage::newOrphan(ListSchema schema, uint size) const {
   2021   if (schema.whichElementType() == schema::Type::STRUCT) {
   2022     return Orphan<DynamicList>(schema, _::OrphanBuilder::initStructList(
   2023         arena, capTable, bounded(size) * ELEMENTS,
   2024         structSizeFromSchema(schema.getStructElementType())));
   2025   } else {
   2026     return Orphan<DynamicList>(schema, _::OrphanBuilder::initList(
   2027         arena, capTable, bounded(size) * ELEMENTS,
   2028         elementSizeFor(schema.whichElementType())));
   2029   }
   2030 }
   2031 
   2032 DynamicStruct::Builder Orphan<DynamicStruct>::get() {
   2033   return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema)));
   2034 }
   2035 
   2036 DynamicStruct::Reader Orphan<DynamicStruct>::getReader() const {
   2037   return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
   2038 }
   2039 
   2040 DynamicList::Builder Orphan<DynamicList>::get() {
   2041   if (schema.whichElementType() == schema::Type::STRUCT) {
   2042     return DynamicList::Builder(
   2043         schema, builder.asStructList(structSizeFromSchema(schema.getStructElementType())));
   2044   } else {
   2045     return DynamicList::Builder(
   2046         schema, builder.asList(elementSizeFor(schema.whichElementType())));
   2047   }
   2048 }
   2049 
   2050 DynamicList::Reader Orphan<DynamicList>::getReader() const {
   2051   return DynamicList::Reader(
   2052       schema, builder.asListReader(elementSizeFor(schema.whichElementType())));
   2053 }
   2054 
   2055 DynamicCapability::Client Orphan<DynamicCapability>::get() {
   2056   return DynamicCapability::Client(schema, builder.asCapability());
   2057 }
   2058 
   2059 DynamicCapability::Client Orphan<DynamicCapability>::getReader() const {
   2060   return DynamicCapability::Client(schema, builder.asCapability());
   2061 }
   2062 
   2063 Orphan<DynamicValue>::Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder)
   2064     : type(value.getType()), builder(kj::mv(builder)) {
   2065   switch (type) {
   2066     case DynamicValue::UNKNOWN: break;
   2067     case DynamicValue::VOID: voidValue = value.voidValue; break;
   2068     case DynamicValue::BOOL: boolValue = value.boolValue; break;
   2069     case DynamicValue::INT: intValue = value.intValue; break;
   2070     case DynamicValue::UINT: uintValue = value.uintValue; break;
   2071     case DynamicValue::FLOAT: floatValue = value.floatValue; break;
   2072     case DynamicValue::ENUM: enumValue = value.enumValue; break;
   2073 
   2074     case DynamicValue::TEXT: break;
   2075     case DynamicValue::DATA: break;
   2076     case DynamicValue::LIST: listSchema = value.listValue.getSchema(); break;
   2077     case DynamicValue::STRUCT: structSchema = value.structValue.getSchema(); break;
   2078     case DynamicValue::CAPABILITY: interfaceSchema = value.capabilityValue.getSchema(); break;
   2079     case DynamicValue::ANY_POINTER: break;
   2080   }
   2081 }
   2082 
   2083 DynamicValue::Builder Orphan<DynamicValue>::get() {
   2084   switch (type) {
   2085     case DynamicValue::UNKNOWN: return nullptr;
   2086     case DynamicValue::VOID: return voidValue;
   2087     case DynamicValue::BOOL: return boolValue;
   2088     case DynamicValue::INT: return intValue;
   2089     case DynamicValue::UINT: return uintValue;
   2090     case DynamicValue::FLOAT: return floatValue;
   2091     case DynamicValue::ENUM: return enumValue;
   2092 
   2093     case DynamicValue::TEXT: return builder.asText();
   2094     case DynamicValue::DATA: return builder.asData();
   2095     case DynamicValue::LIST:
   2096       if (listSchema.whichElementType() == schema::Type::STRUCT) {
   2097         return DynamicList::Builder(listSchema,
   2098             builder.asStructList(structSizeFromSchema(listSchema.getStructElementType())));
   2099       } else {
   2100         return DynamicList::Builder(listSchema,
   2101             builder.asList(elementSizeFor(listSchema.whichElementType())));
   2102       }
   2103     case DynamicValue::STRUCT:
   2104       return DynamicStruct::Builder(structSchema,
   2105           builder.asStruct(structSizeFromSchema(structSchema)));
   2106     case DynamicValue::CAPABILITY:
   2107       return DynamicCapability::Client(interfaceSchema, builder.asCapability());
   2108     case DynamicValue::ANY_POINTER:
   2109       KJ_FAIL_REQUIRE("Can't get() an AnyPointer orphan; there is no underlying pointer to "
   2110                       "wrap in an AnyPointer::Builder.");
   2111   }
   2112   KJ_UNREACHABLE;
   2113 }
   2114 DynamicValue::Reader Orphan<DynamicValue>::getReader() const {
   2115   switch (type) {
   2116     case DynamicValue::UNKNOWN: return nullptr;
   2117     case DynamicValue::VOID: return voidValue;
   2118     case DynamicValue::BOOL: return boolValue;
   2119     case DynamicValue::INT: return intValue;
   2120     case DynamicValue::UINT: return uintValue;
   2121     case DynamicValue::FLOAT: return floatValue;
   2122     case DynamicValue::ENUM: return enumValue;
   2123 
   2124     case DynamicValue::TEXT: return builder.asTextReader();
   2125     case DynamicValue::DATA: return builder.asDataReader();
   2126     case DynamicValue::LIST:
   2127       return DynamicList::Reader(listSchema,
   2128           builder.asListReader(elementSizeFor(listSchema.whichElementType())));
   2129     case DynamicValue::STRUCT:
   2130       return DynamicStruct::Reader(structSchema,
   2131           builder.asStructReader(structSizeFromSchema(structSchema)));
   2132     case DynamicValue::CAPABILITY:
   2133       return DynamicCapability::Client(interfaceSchema, builder.asCapability());
   2134     case DynamicValue::ANY_POINTER:
   2135       KJ_FAIL_ASSERT("Can't get() an AnyPointer orphan; there is no underlying pointer to "
   2136                      "wrap in an AnyPointer::Builder.");
   2137   }
   2138   KJ_UNREACHABLE;
   2139 }
   2140 
   2141 template <>
   2142 Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>() {
   2143   KJ_REQUIRE(type == DynamicValue::ANY_POINTER, "Value type mismatch.");
   2144   type = DynamicValue::UNKNOWN;
   2145   return Orphan<AnyPointer>(kj::mv(builder));
   2146 }
   2147 template <>
   2148 Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>() {
   2149   KJ_REQUIRE(type == DynamicValue::STRUCT, "Value type mismatch.");
   2150   type = DynamicValue::UNKNOWN;
   2151   return Orphan<DynamicStruct>(structSchema, kj::mv(builder));
   2152 }
   2153 template <>
   2154 Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>() {
   2155   KJ_REQUIRE(type == DynamicValue::LIST, "Value type mismatch.");
   2156   type = DynamicValue::UNKNOWN;
   2157   return Orphan<DynamicList>(listSchema, kj::mv(builder));
   2158 }
   2159 
   2160 template <>
   2161 Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
   2162     DynamicValue::Reader copyFrom) const {
   2163   switch (copyFrom.getType()) {
   2164     case DynamicValue::UNKNOWN: return nullptr;
   2165     case DynamicValue::VOID: return copyFrom.voidValue;
   2166     case DynamicValue::BOOL: return copyFrom.boolValue;
   2167     case DynamicValue::INT: return copyFrom.intValue;
   2168     case DynamicValue::UINT: return copyFrom.uintValue;
   2169     case DynamicValue::FLOAT: return copyFrom.floatValue;
   2170     case DynamicValue::ENUM: return copyFrom.enumValue;
   2171 
   2172     case DynamicValue::TEXT: return newOrphanCopy(copyFrom.textValue);
   2173     case DynamicValue::DATA: return newOrphanCopy(copyFrom.dataValue);
   2174     case DynamicValue::LIST: return newOrphanCopy(copyFrom.listValue);
   2175     case DynamicValue::STRUCT: return newOrphanCopy(copyFrom.structValue);
   2176     case DynamicValue::CAPABILITY: return newOrphanCopy(copyFrom.capabilityValue);
   2177     case DynamicValue::ANY_POINTER: return newOrphanCopy(copyFrom.anyPointerValue);
   2178   }
   2179   KJ_UNREACHABLE;
   2180 }
   2181 
   2182 }  // namespace capnp