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