comparison src/capnproto-0.6.0/c++/src/capnp/dynamic.c++ @ 62:0994c39f1e94

Cap'n Proto v0.6 + build for OSX
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 22 May 2017 10:01:37 +0100
parents
children
comparison
equal deleted inserted replaced
61:d101c4099725 62:0994c39f1e94
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) 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 case schema::Type::BOOL:
445 case schema::Type::INT8:
446 case schema::Type::INT16:
447 case schema::Type::INT32:
448 case schema::Type::INT64:
449 case schema::Type::UINT8:
450 case schema::Type::UINT16:
451 case schema::Type::UINT32:
452 case schema::Type::UINT64:
453 case schema::Type::FLOAT32:
454 case schema::Type::FLOAT64:
455 case schema::Type::ENUM:
456 // Primitive types are always present.
457 return true;
458
459 case schema::Type::TEXT:
460 case schema::Type::DATA:
461 case schema::Type::LIST:
462 case schema::Type::STRUCT:
463 case schema::Type::ANY_POINTER:
464 case schema::Type::INTERFACE:
465 return !reader.getPointerField(assumePointerOffset(slot.getOffset())).isNull();
466 }
467
468 // Unknown type. As far as we know, it isn't set.
469 return false;
470 }
471
472 kj::Maybe<StructSchema::Field> DynamicStruct::Reader::which() const {
473 auto structProto = schema.getProto().getStruct();
474 if (structProto.getDiscriminantCount() == 0) {
475 return nullptr;
476 }
477
478 uint16_t discrim = reader.getDataField<uint16_t>(
479 assumeDataOffset(structProto.getDiscriminantOffset()));
480 return schema.getFieldByDiscriminant(discrim);
481 }
482
483 kj::Maybe<StructSchema::Field> DynamicStruct::Builder::which() {
484 auto structProto = schema.getProto().getStruct();
485 if (structProto.getDiscriminantCount() == 0) {
486 return nullptr;
487 }
488
489 uint16_t discrim = builder.getDataField<uint16_t>(
490 assumeDataOffset(structProto.getDiscriminantOffset()));
491 return schema.getFieldByDiscriminant(discrim);
492 }
493
494 void DynamicStruct::Builder::set(StructSchema::Field field, const DynamicValue::Reader& value) {
495 KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
496 setInUnion(field);
497
498 auto proto = field.getProto();
499 auto type = field.getType();
500 switch (proto.which()) {
501 case schema::Field::SLOT: {
502 auto slot = proto.getSlot();
503 auto dval = slot.getDefaultValue();
504
505 switch (type.which()) {
506 case schema::Type::VOID:
507 builder.setDataField<Void>(assumeDataOffset(slot.getOffset()), value.as<Void>());
508 return;
509
510 #define HANDLE_TYPE(discrim, titleCase, type) \
511 case schema::Type::discrim: \
512 builder.setDataField<type>( \
513 assumeDataOffset(slot.getOffset()), value.as<type>(), \
514 bitCast<_::Mask<type> >(dval.get##titleCase())); \
515 return;
516
517 HANDLE_TYPE(BOOL, Bool, bool)
518 HANDLE_TYPE(INT8, Int8, int8_t)
519 HANDLE_TYPE(INT16, Int16, int16_t)
520 HANDLE_TYPE(INT32, Int32, int32_t)
521 HANDLE_TYPE(INT64, Int64, int64_t)
522 HANDLE_TYPE(UINT8, Uint8, uint8_t)
523 HANDLE_TYPE(UINT16, Uint16, uint16_t)
524 HANDLE_TYPE(UINT32, Uint32, uint32_t)
525 HANDLE_TYPE(UINT64, Uint64, uint64_t)
526 HANDLE_TYPE(FLOAT32, Float32, float)
527 HANDLE_TYPE(FLOAT64, Float64, double)
528
529 #undef HANDLE_TYPE
530
531 case schema::Type::ENUM: {
532 uint16_t rawValue;
533 auto enumSchema = type.asEnum();
534 if (value.getType() == DynamicValue::TEXT) {
535 // Convert from text.
536 rawValue = enumSchema.getEnumerantByName(value.as<Text>()).getOrdinal();
537 } else if (value.getType() == DynamicValue::INT ||
538 value.getType() == DynamicValue::UINT) {
539 rawValue = value.as<uint16_t>();
540 } else {
541 DynamicEnum enumValue = value.as<DynamicEnum>();
542 KJ_REQUIRE(enumValue.getSchema() == enumSchema, "Value type mismatch.") {
543 return;
544 }
545 rawValue = enumValue.getRaw();
546 }
547 builder.setDataField<uint16_t>(assumeDataOffset(slot.getOffset()), rawValue,
548 dval.getEnum());
549 return;
550 }
551
552 case schema::Type::TEXT:
553 builder.getPointerField(assumePointerOffset(slot.getOffset()))
554 .setBlob<Text>(value.as<Text>());
555 return;
556
557 case schema::Type::DATA:
558 builder.getPointerField(assumePointerOffset(slot.getOffset()))
559 .setBlob<Data>(value.as<Data>());
560 return;
561
562 case schema::Type::LIST: {
563 ListSchema listType = type.asList();
564 auto listValue = value.as<DynamicList>();
565 KJ_REQUIRE(listValue.getSchema() == listType, "Value type mismatch.") {
566 return;
567 }
568 builder.getPointerField(assumePointerOffset(slot.getOffset()))
569 .setList(listValue.reader);
570 return;
571 }
572
573 case schema::Type::STRUCT: {
574 auto structType = type.asStruct();
575 auto structValue = value.as<DynamicStruct>();
576 KJ_REQUIRE(structValue.getSchema() == structType, "Value type mismatch.") {
577 return;
578 }
579 builder.getPointerField(assumePointerOffset(slot.getOffset()))
580 .setStruct(structValue.reader);
581 return;
582 }
583
584 case schema::Type::ANY_POINTER: {
585 auto target = AnyPointer::Builder(
586 builder.getPointerField(assumePointerOffset(slot.getOffset())));
587
588 switch (value.getType()) {
589 case DynamicValue::Type::TEXT:
590 target.setAs<Text>(value.as<Text>());
591 return;
592 case DynamicValue::Type::DATA:
593 target.setAs<Data>(value.as<Data>());
594 return;
595 case DynamicValue::Type::LIST:
596 target.setAs<DynamicList>(value.as<DynamicList>());
597 return;
598 case DynamicValue::Type::STRUCT:
599 target.setAs<DynamicStruct>(value.as<DynamicStruct>());
600 return;
601 case DynamicValue::Type::CAPABILITY:
602 target.setAs<DynamicCapability>(value.as<DynamicCapability>());
603 return;
604 case DynamicValue::Type::ANY_POINTER:
605 target.set(value.as<AnyPointer>());
606 return;
607
608 case DynamicValue::Type::UNKNOWN:
609 case DynamicValue::Type::VOID:
610 case DynamicValue::Type::BOOL:
611 case DynamicValue::Type::INT:
612 case DynamicValue::Type::UINT:
613 case DynamicValue::Type::FLOAT:
614 case DynamicValue::Type::ENUM:
615 KJ_FAIL_ASSERT("Value type mismatch; expected AnyPointer");
616 }
617
618 KJ_UNREACHABLE;
619 }
620
621 case schema::Type::INTERFACE: {
622 auto interfaceType = type.asInterface();
623 auto capability = value.as<DynamicCapability>();
624 KJ_REQUIRE(capability.getSchema().extends(interfaceType), "Value type mismatch.") {
625 return;
626 }
627 builder.getPointerField(assumePointerOffset(slot.getOffset()))
628 .setCapability(kj::mv(capability.hook));
629 return;
630 }
631 }
632
633 KJ_UNREACHABLE;
634 }
635
636 case schema::Field::GROUP: {
637 auto src = value.as<DynamicStruct>();
638 auto dst = init(field).as<DynamicStruct>();
639
640 KJ_IF_MAYBE(unionField, src.which()) {
641 dst.set(*unionField, src.get(*unionField));
642 }
643
644 for (auto field: src.schema.getNonUnionFields()) {
645 if (src.has(field)) {
646 dst.set(field, src.get(field));
647 }
648 }
649 }
650 }
651
652 KJ_UNREACHABLE;
653 }
654
655 DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Field field) {
656 KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
657 setInUnion(field);
658
659 auto proto = field.getProto();
660 auto type = field.getType();
661
662 switch (proto.which()) {
663 case schema::Field::SLOT: {
664 auto slot = proto.getSlot();
665 switch (type.which()) {
666 case schema::Type::STRUCT: {
667 auto subSchema = type.asStruct();
668 return DynamicStruct::Builder(subSchema,
669 builder.getPointerField(assumePointerOffset(slot.getOffset()))
670 .initStruct(structSizeFromSchema(subSchema)));
671 }
672 case schema::Type::ANY_POINTER: {
673 auto pointer = builder.getPointerField(assumePointerOffset(slot.getOffset()));
674 pointer.clear();
675 return AnyPointer::Builder(pointer);
676 }
677 default:
678 KJ_FAIL_REQUIRE("init() without a size is only valid for struct and object fields.");
679 }
680 }
681
682 case schema::Field::GROUP: {
683 clear(field);
684 return DynamicStruct::Builder(type.asStruct(), builder);
685 }
686 }
687
688 KJ_UNREACHABLE;
689 }
690
691 DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Field field, uint size) {
692 KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
693 setInUnion(field);
694
695 auto proto = field.getProto();
696 auto type = field.getType();
697
698 switch (proto.which()) {
699 case schema::Field::SLOT: {
700 auto slot = proto.getSlot();
701 switch (type.which()) {
702 case schema::Type::LIST: {
703 auto listType = type.asList();
704 if (listType.whichElementType() == schema::Type::STRUCT) {
705 return DynamicList::Builder(listType,
706 builder.getPointerField(assumePointerOffset(slot.getOffset()))
707 .initStructList(bounded(size) * ELEMENTS,
708 structSizeFromSchema(listType.getStructElementType())));
709 } else {
710 return DynamicList::Builder(listType,
711 builder.getPointerField(assumePointerOffset(slot.getOffset()))
712 .initList(elementSizeFor(listType.whichElementType()),
713 bounded(size) * ELEMENTS));
714 }
715 }
716 case schema::Type::TEXT:
717 return builder.getPointerField(assumePointerOffset(slot.getOffset()))
718 .initBlob<Text>(bounded(size) * BYTES);
719 case schema::Type::DATA:
720 return builder.getPointerField(assumePointerOffset(slot.getOffset()))
721 .initBlob<Data>(bounded(size) * BYTES);
722 default:
723 KJ_FAIL_REQUIRE(
724 "init() with size is only valid for list, text, or data fields.",
725 (uint)type.which());
726 break;
727 }
728 }
729
730 case schema::Field::GROUP:
731 KJ_FAIL_REQUIRE("init() with size is only valid for list, text, or data fields.");
732 }
733
734 KJ_UNREACHABLE;
735 }
736
737 void DynamicStruct::Builder::adopt(StructSchema::Field field, Orphan<DynamicValue>&& orphan) {
738 KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
739 setInUnion(field);
740
741 auto proto = field.getProto();
742 switch (proto.which()) {
743 case schema::Field::SLOT: {
744 auto slot = proto.getSlot();
745 auto type = field.getType();
746
747 switch (type.which()) {
748 case schema::Type::VOID:
749 case schema::Type::BOOL:
750 case schema::Type::INT8:
751 case schema::Type::INT16:
752 case schema::Type::INT32:
753 case schema::Type::INT64:
754 case schema::Type::UINT8:
755 case schema::Type::UINT16:
756 case schema::Type::UINT32:
757 case schema::Type::UINT64:
758 case schema::Type::FLOAT32:
759 case schema::Type::FLOAT64:
760 case schema::Type::ENUM:
761 set(field, orphan.getReader());
762 return;
763
764 case schema::Type::TEXT:
765 KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch.");
766 break;
767
768 case schema::Type::DATA:
769 KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
770 break;
771
772 case schema::Type::LIST: {
773 ListSchema listType = type.asList();
774 KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == listType,
775 "Value type mismatch.") {
776 return;
777 }
778 break;
779 }
780
781 case schema::Type::STRUCT: {
782 auto structType = type.asStruct();
783 KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == structType,
784 "Value type mismatch.") {
785 return;
786 }
787 break;
788 }
789
790 case schema::Type::ANY_POINTER:
791 KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT ||
792 orphan.getType() == DynamicValue::LIST ||
793 orphan.getType() == DynamicValue::TEXT ||
794 orphan.getType() == DynamicValue::DATA ||
795 orphan.getType() == DynamicValue::CAPABILITY ||
796 orphan.getType() == DynamicValue::ANY_POINTER,
797 "Value type mismatch.") {
798 return;
799 }
800 break;
801
802 case schema::Type::INTERFACE: {
803 auto interfaceType = type.asInterface();
804 KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY &&
805 orphan.interfaceSchema.extends(interfaceType),
806 "Value type mismatch.") {
807 return;
808 }
809 break;
810 }
811 }
812
813 builder.getPointerField(assumePointerOffset(slot.getOffset())).adopt(kj::mv(orphan.builder));
814 return;
815 }
816
817 case schema::Field::GROUP:
818 // Have to transfer fields.
819 auto src = orphan.get().as<DynamicStruct>();
820 auto dst = init(field).as<DynamicStruct>();
821
822 KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == dst.getSchema(),
823 "Value type mismatch.");
824
825 KJ_IF_MAYBE(unionField, src.which()) {
826 dst.adopt(*unionField, src.disown(*unionField));
827 }
828
829 for (auto field: src.schema.getNonUnionFields()) {
830 if (src.has(field)) {
831 dst.adopt(field, src.disown(field));
832 }
833 }
834
835 return;
836 }
837
838 KJ_UNREACHABLE;
839 }
840
841 Orphan<DynamicValue> DynamicStruct::Builder::disown(StructSchema::Field field) {
842 // We end up calling get(field) below, so we don't need to validate `field` here.
843
844 auto proto = field.getProto();
845 switch (proto.which()) {
846 case schema::Field::SLOT: {
847 auto slot = proto.getSlot();
848
849 switch (field.getType().which()) {
850 case schema::Type::VOID:
851 case schema::Type::BOOL:
852 case schema::Type::INT8:
853 case schema::Type::INT16:
854 case schema::Type::INT32:
855 case schema::Type::INT64:
856 case schema::Type::UINT8:
857 case schema::Type::UINT16:
858 case schema::Type::UINT32:
859 case schema::Type::UINT64:
860 case schema::Type::FLOAT32:
861 case schema::Type::FLOAT64:
862 case schema::Type::ENUM: {
863 auto result = Orphan<DynamicValue>(get(field), _::OrphanBuilder());
864 clear(field);
865 return kj::mv(result);
866 }
867
868 case schema::Type::TEXT:
869 case schema::Type::DATA:
870 case schema::Type::LIST:
871 case schema::Type::STRUCT:
872 case schema::Type::ANY_POINTER:
873 case schema::Type::INTERFACE: {
874 auto value = get(field);
875 return Orphan<DynamicValue>(
876 value, builder.getPointerField(assumePointerOffset(slot.getOffset())).disown());
877 }
878 }
879 KJ_UNREACHABLE;
880 }
881
882 case schema::Field::GROUP: {
883 // We have to allocate new space for the group, unfortunately.
884 auto src = get(field).as<DynamicStruct>();
885
886 Orphan<DynamicStruct> result =
887 Orphanage::getForMessageContaining(*this).newOrphan(src.getSchema());
888 auto dst = result.get();
889
890 KJ_IF_MAYBE(unionField, src.which()) {
891 dst.adopt(*unionField, src.disown(*unionField));
892 }
893
894 // We need to explicitly reset the union to its default field.
895 KJ_IF_MAYBE(unionField, src.schema.getFieldByDiscriminant(0)) {
896 src.clear(*unionField);
897 }
898
899 for (auto field: src.schema.getNonUnionFields()) {
900 if (src.has(field)) {
901 dst.adopt(field, src.disown(field));
902 }
903 }
904
905 return kj::mv(result);
906 }
907 }
908
909 KJ_UNREACHABLE;
910 }
911
912 void DynamicStruct::Builder::clear(StructSchema::Field field) {
913 KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
914 setInUnion(field);
915
916 auto proto = field.getProto();
917 auto type = field.getType();
918 switch (proto.which()) {
919 case schema::Field::SLOT: {
920 auto slot = proto.getSlot();
921
922 switch (type.which()) {
923 case schema::Type::VOID:
924 builder.setDataField<Void>(assumeDataOffset(slot.getOffset()), VOID);
925 return;
926
927 #define HANDLE_TYPE(discrim, type) \
928 case schema::Type::discrim: \
929 builder.setDataField<type>(assumeDataOffset(slot.getOffset()), 0); \
930 return;
931
932 HANDLE_TYPE(BOOL, bool)
933 HANDLE_TYPE(INT8, uint8_t)
934 HANDLE_TYPE(INT16, uint16_t)
935 HANDLE_TYPE(INT32, uint32_t)
936 HANDLE_TYPE(INT64, uint64_t)
937 HANDLE_TYPE(UINT8, uint8_t)
938 HANDLE_TYPE(UINT16, uint16_t)
939 HANDLE_TYPE(UINT32, uint32_t)
940 HANDLE_TYPE(UINT64, uint64_t)
941 HANDLE_TYPE(FLOAT32, uint32_t)
942 HANDLE_TYPE(FLOAT64, uint64_t)
943 HANDLE_TYPE(ENUM, uint16_t)
944
945 #undef HANDLE_TYPE
946
947 case schema::Type::TEXT:
948 case schema::Type::DATA:
949 case schema::Type::LIST:
950 case schema::Type::STRUCT:
951 case schema::Type::ANY_POINTER:
952 case schema::Type::INTERFACE:
953 builder.getPointerField(assumePointerOffset(slot.getOffset())).clear();
954 return;
955 }
956
957 KJ_UNREACHABLE;
958 }
959
960 case schema::Field::GROUP: {
961 DynamicStruct::Builder group(type.asStruct(), builder);
962
963 // We clear the union field with discriminant 0 rather than the one that is set because
964 // we want the union to end up with its default field active.
965 KJ_IF_MAYBE(unionField, group.schema.getFieldByDiscriminant(0)) {
966 group.clear(*unionField);
967 }
968
969 for (auto subField: group.schema.getNonUnionFields()) {
970 group.clear(subField);
971 }
972 return;
973 }
974 }
975
976 KJ_UNREACHABLE;
977 }
978
979 DynamicValue::Reader DynamicStruct::Reader::get(kj::StringPtr name) const {
980 return get(schema.getFieldByName(name));
981 }
982 DynamicValue::Builder DynamicStruct::Builder::get(kj::StringPtr name) {
983 return get(schema.getFieldByName(name));
984 }
985 DynamicValue::Pipeline DynamicStruct::Pipeline::get(kj::StringPtr name) {
986 return get(schema.getFieldByName(name));
987 }
988 bool DynamicStruct::Reader::has(kj::StringPtr name) const {
989 return has(schema.getFieldByName(name));
990 }
991 bool DynamicStruct::Builder::has(kj::StringPtr name) {
992 return has(schema.getFieldByName(name));
993 }
994 void DynamicStruct::Builder::set(kj::StringPtr name, const DynamicValue::Reader& value) {
995 set(schema.getFieldByName(name), value);
996 }
997 void DynamicStruct::Builder::set(kj::StringPtr name,
998 std::initializer_list<DynamicValue::Reader> value) {
999 auto list = init(name, value.size()).as<DynamicList>();
1000 uint i = 0;
1001 for (auto element: value) {
1002 list.set(i++, element);
1003 }
1004 }
1005 DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name) {
1006 return init(schema.getFieldByName(name));
1007 }
1008 DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name, uint size) {
1009 return init(schema.getFieldByName(name), size);
1010 }
1011 void DynamicStruct::Builder::adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan) {
1012 adopt(schema.getFieldByName(name), kj::mv(orphan));
1013 }
1014 Orphan<DynamicValue> DynamicStruct::Builder::disown(kj::StringPtr name) {
1015 return disown(schema.getFieldByName(name));
1016 }
1017 void DynamicStruct::Builder::clear(kj::StringPtr name) {
1018 clear(schema.getFieldByName(name));
1019 }
1020
1021 // =======================================================================================
1022
1023 DynamicValue::Reader DynamicList::Reader::operator[](uint index) const {
1024 KJ_REQUIRE(index < size(), "List index out-of-bounds.");
1025
1026 switch (schema.whichElementType()) {
1027 #define HANDLE_TYPE(name, discrim, typeName) \
1028 case schema::Type::discrim: \
1029 return reader.getDataElement<typeName>(bounded(index) * ELEMENTS);
1030
1031 HANDLE_TYPE(void, VOID, Void)
1032 HANDLE_TYPE(bool, BOOL, bool)
1033 HANDLE_TYPE(int8, INT8, int8_t)
1034 HANDLE_TYPE(int16, INT16, int16_t)
1035 HANDLE_TYPE(int32, INT32, int32_t)
1036 HANDLE_TYPE(int64, INT64, int64_t)
1037 HANDLE_TYPE(uint8, UINT8, uint8_t)
1038 HANDLE_TYPE(uint16, UINT16, uint16_t)
1039 HANDLE_TYPE(uint32, UINT32, uint32_t)
1040 HANDLE_TYPE(uint64, UINT64, uint64_t)
1041 HANDLE_TYPE(float32, FLOAT32, float)
1042 HANDLE_TYPE(float64, FLOAT64, double)
1043 #undef HANDLE_TYPE
1044
1045 case schema::Type::TEXT:
1046 return reader.getPointerElement(bounded(index) * ELEMENTS)
1047 .getBlob<Text>(nullptr, ZERO * BYTES);
1048 case schema::Type::DATA:
1049 return reader.getPointerElement(bounded(index) * ELEMENTS)
1050 .getBlob<Data>(nullptr, ZERO * BYTES);
1051
1052 case schema::Type::LIST: {
1053 auto elementType = schema.getListElementType();
1054 return DynamicList::Reader(elementType,
1055 reader.getPointerElement(bounded(index) * ELEMENTS)
1056 .getList(elementSizeFor(elementType.whichElementType()), nullptr));
1057 }
1058
1059 case schema::Type::STRUCT:
1060 return DynamicStruct::Reader(schema.getStructElementType(),
1061 reader.getStructElement(bounded(index) * ELEMENTS));
1062
1063 case schema::Type::ENUM:
1064 return DynamicEnum(schema.getEnumElementType(),
1065 reader.getDataElement<uint16_t>(bounded(index) * ELEMENTS));
1066
1067 case schema::Type::ANY_POINTER:
1068 return AnyPointer::Reader(reader.getPointerElement(bounded(index) * ELEMENTS));
1069
1070 case schema::Type::INTERFACE:
1071 return DynamicCapability::Client(schema.getInterfaceElementType(),
1072 reader.getPointerElement(bounded(index) * ELEMENTS)
1073 .getCapability());
1074 }
1075
1076 return nullptr;
1077 }
1078
1079 DynamicValue::Builder DynamicList::Builder::operator[](uint index) {
1080 KJ_REQUIRE(index < size(), "List index out-of-bounds.");
1081
1082 switch (schema.whichElementType()) {
1083 #define HANDLE_TYPE(name, discrim, typeName) \
1084 case schema::Type::discrim: \
1085 return builder.getDataElement<typeName>(bounded(index) * ELEMENTS);
1086
1087 HANDLE_TYPE(void, VOID, Void)
1088 HANDLE_TYPE(bool, BOOL, bool)
1089 HANDLE_TYPE(int8, INT8, int8_t)
1090 HANDLE_TYPE(int16, INT16, int16_t)
1091 HANDLE_TYPE(int32, INT32, int32_t)
1092 HANDLE_TYPE(int64, INT64, int64_t)
1093 HANDLE_TYPE(uint8, UINT8, uint8_t)
1094 HANDLE_TYPE(uint16, UINT16, uint16_t)
1095 HANDLE_TYPE(uint32, UINT32, uint32_t)
1096 HANDLE_TYPE(uint64, UINT64, uint64_t)
1097 HANDLE_TYPE(float32, FLOAT32, float)
1098 HANDLE_TYPE(float64, FLOAT64, double)
1099 #undef HANDLE_TYPE
1100
1101 case schema::Type::TEXT:
1102 return builder.getPointerElement(bounded(index) * ELEMENTS)
1103 .getBlob<Text>(nullptr, ZERO * BYTES);
1104 case schema::Type::DATA:
1105 return builder.getPointerElement(bounded(index) * ELEMENTS)
1106 .getBlob<Data>(nullptr, ZERO * BYTES);
1107
1108 case schema::Type::LIST: {
1109 ListSchema elementType = schema.getListElementType();
1110 if (elementType.whichElementType() == schema::Type::STRUCT) {
1111 return DynamicList::Builder(elementType,
1112 builder.getPointerElement(bounded(index) * ELEMENTS)
1113 .getStructList(structSizeFromSchema(elementType.getStructElementType()),
1114 nullptr));
1115 } else {
1116 return DynamicList::Builder(elementType,
1117 builder.getPointerElement(bounded(index) * ELEMENTS)
1118 .getList(elementSizeFor(elementType.whichElementType()), nullptr));
1119 }
1120 }
1121
1122 case schema::Type::STRUCT:
1123 return DynamicStruct::Builder(schema.getStructElementType(),
1124 builder.getStructElement(bounded(index) * ELEMENTS));
1125
1126 case schema::Type::ENUM:
1127 return DynamicEnum(schema.getEnumElementType(),
1128 builder.getDataElement<uint16_t>(bounded(index) * ELEMENTS));
1129
1130 case schema::Type::ANY_POINTER:
1131 KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
1132 return nullptr;
1133
1134 case schema::Type::INTERFACE:
1135 return DynamicCapability::Client(schema.getInterfaceElementType(),
1136 builder.getPointerElement(bounded(index) * ELEMENTS)
1137 .getCapability());
1138 }
1139
1140 return nullptr;
1141 }
1142
1143 void DynamicList::Builder::set(uint index, const DynamicValue::Reader& value) {
1144 KJ_REQUIRE(index < size(), "List index out-of-bounds.") {
1145 return;
1146 }
1147
1148 switch (schema.whichElementType()) {
1149 #define HANDLE_TYPE(name, discrim, typeName) \
1150 case schema::Type::discrim: \
1151 builder.setDataElement<typeName>(bounded(index) * ELEMENTS, value.as<typeName>()); \
1152 return;
1153
1154 HANDLE_TYPE(void, VOID, Void)
1155 HANDLE_TYPE(bool, BOOL, bool)
1156 HANDLE_TYPE(int8, INT8, int8_t)
1157 HANDLE_TYPE(int16, INT16, int16_t)
1158 HANDLE_TYPE(int32, INT32, int32_t)
1159 HANDLE_TYPE(int64, INT64, int64_t)
1160 HANDLE_TYPE(uint8, UINT8, uint8_t)
1161 HANDLE_TYPE(uint16, UINT16, uint16_t)
1162 HANDLE_TYPE(uint32, UINT32, uint32_t)
1163 HANDLE_TYPE(uint64, UINT64, uint64_t)
1164 HANDLE_TYPE(float32, FLOAT32, float)
1165 HANDLE_TYPE(float64, FLOAT64, double)
1166 #undef HANDLE_TYPE
1167
1168 case schema::Type::TEXT:
1169 builder.getPointerElement(bounded(index) * ELEMENTS).setBlob<Text>(value.as<Text>());
1170 return;
1171 case schema::Type::DATA:
1172 builder.getPointerElement(bounded(index) * ELEMENTS).setBlob<Data>(value.as<Data>());
1173 return;
1174
1175 case schema::Type::LIST: {
1176 auto listValue = value.as<DynamicList>();
1177 KJ_REQUIRE(listValue.getSchema() == schema.getListElementType(), "Value type mismatch.") {
1178 return;
1179 }
1180 builder.getPointerElement(bounded(index) * ELEMENTS).setList(listValue.reader);
1181 return;
1182 }
1183
1184 case schema::Type::STRUCT: {
1185 auto structValue = value.as<DynamicStruct>();
1186 KJ_REQUIRE(structValue.getSchema() == schema.getStructElementType(), "Value type mismatch.") {
1187 return;
1188 }
1189 builder.getStructElement(bounded(index) * ELEMENTS).copyContentFrom(structValue.reader);
1190 return;
1191 }
1192
1193 case schema::Type::ENUM: {
1194 uint16_t rawValue;
1195 if (value.getType() == DynamicValue::TEXT) {
1196 // Convert from text.
1197 rawValue = schema.getEnumElementType().getEnumerantByName(value.as<Text>()).getOrdinal();
1198 } else {
1199 DynamicEnum enumValue = value.as<DynamicEnum>();
1200 KJ_REQUIRE(schema.getEnumElementType() == enumValue.getSchema(),
1201 "Type mismatch when using DynamicList::Builder::set().") {
1202 return;
1203 }
1204 rawValue = enumValue.getRaw();
1205 }
1206 builder.setDataElement<uint16_t>(bounded(index) * ELEMENTS, rawValue);
1207 return;
1208 }
1209
1210 case schema::Type::ANY_POINTER:
1211 KJ_FAIL_ASSERT("List(AnyPointer) not supported.") {
1212 return;
1213 }
1214
1215 case schema::Type::INTERFACE: {
1216 auto capValue = value.as<DynamicCapability>();
1217 KJ_REQUIRE(capValue.getSchema().extends(schema.getInterfaceElementType()),
1218 "Value type mismatch.") {
1219 return;
1220 }
1221 builder.getPointerElement(bounded(index) * ELEMENTS).setCapability(kj::mv(capValue.hook));
1222 return;
1223 }
1224 }
1225
1226 KJ_FAIL_REQUIRE("can't set element of unknown type", (uint)schema.whichElementType()) {
1227 return;
1228 }
1229 }
1230
1231 DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) {
1232 KJ_REQUIRE(index < this->size(), "List index out-of-bounds.");
1233
1234 switch (schema.whichElementType()) {
1235 case schema::Type::VOID:
1236 case schema::Type::BOOL:
1237 case schema::Type::INT8:
1238 case schema::Type::INT16:
1239 case schema::Type::INT32:
1240 case schema::Type::INT64:
1241 case schema::Type::UINT8:
1242 case schema::Type::UINT16:
1243 case schema::Type::UINT32:
1244 case schema::Type::UINT64:
1245 case schema::Type::FLOAT32:
1246 case schema::Type::FLOAT64:
1247 case schema::Type::ENUM:
1248 case schema::Type::STRUCT:
1249 case schema::Type::INTERFACE:
1250 KJ_FAIL_REQUIRE("Expected a list or blob.");
1251 return nullptr;
1252
1253 case schema::Type::TEXT:
1254 return builder.getPointerElement(bounded(index) * ELEMENTS)
1255 .initBlob<Text>(bounded(size) * BYTES);
1256
1257 case schema::Type::DATA:
1258 return builder.getPointerElement(bounded(index) * ELEMENTS)
1259 .initBlob<Data>(bounded(size) * BYTES);
1260
1261 case schema::Type::LIST: {
1262 auto elementType = schema.getListElementType();
1263
1264 if (elementType.whichElementType() == schema::Type::STRUCT) {
1265 return DynamicList::Builder(elementType,
1266 builder.getPointerElement(bounded(index) * ELEMENTS)
1267 .initStructList(bounded(size) * ELEMENTS,
1268 structSizeFromSchema(elementType.getStructElementType())));
1269 } else {
1270 return DynamicList::Builder(elementType,
1271 builder.getPointerElement(bounded(index) * ELEMENTS)
1272 .initList(elementSizeFor(elementType.whichElementType()),
1273 bounded(size) * ELEMENTS));
1274 }
1275 }
1276
1277 case schema::Type::ANY_POINTER: {
1278 KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
1279 return nullptr;
1280 }
1281 }
1282
1283 return nullptr;
1284 }
1285
1286 void DynamicList::Builder::adopt(uint index, Orphan<DynamicValue>&& orphan) {
1287 switch (schema.whichElementType()) {
1288 case schema::Type::VOID:
1289 case schema::Type::BOOL:
1290 case schema::Type::INT8:
1291 case schema::Type::INT16:
1292 case schema::Type::INT32:
1293 case schema::Type::INT64:
1294 case schema::Type::UINT8:
1295 case schema::Type::UINT16:
1296 case schema::Type::UINT32:
1297 case schema::Type::UINT64:
1298 case schema::Type::FLOAT32:
1299 case schema::Type::FLOAT64:
1300 case schema::Type::ENUM:
1301 set(index, orphan.getReader());
1302 return;
1303
1304 case schema::Type::TEXT:
1305 KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch.");
1306 builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
1307 return;
1308
1309 case schema::Type::DATA:
1310 KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
1311 builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
1312 return;
1313
1314 case schema::Type::LIST: {
1315 ListSchema elementType = schema.getListElementType();
1316 KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == elementType,
1317 "Value type mismatch.");
1318 builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
1319 return;
1320 }
1321
1322 case schema::Type::STRUCT: {
1323 auto elementType = schema.getStructElementType();
1324 KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == elementType,
1325 "Value type mismatch.");
1326 builder.getStructElement(bounded(index) * ELEMENTS).transferContentFrom(
1327 orphan.builder.asStruct(structSizeFromSchema(elementType)));
1328 return;
1329 }
1330
1331 case schema::Type::ANY_POINTER:
1332 KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
1333
1334 case schema::Type::INTERFACE: {
1335 auto elementType = schema.getInterfaceElementType();
1336 KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY &&
1337 orphan.interfaceSchema.extends(elementType),
1338 "Value type mismatch.");
1339 builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
1340 return;
1341 }
1342 }
1343
1344 KJ_UNREACHABLE;
1345 }
1346
1347 Orphan<DynamicValue> DynamicList::Builder::disown(uint index) {
1348 switch (schema.whichElementType()) {
1349 case schema::Type::VOID:
1350 case schema::Type::BOOL:
1351 case schema::Type::INT8:
1352 case schema::Type::INT16:
1353 case schema::Type::INT32:
1354 case schema::Type::INT64:
1355 case schema::Type::UINT8:
1356 case schema::Type::UINT16:
1357 case schema::Type::UINT32:
1358 case schema::Type::UINT64:
1359 case schema::Type::FLOAT32:
1360 case schema::Type::FLOAT64:
1361 case schema::Type::ENUM: {
1362 auto result = Orphan<DynamicValue>(operator[](index), _::OrphanBuilder());
1363 switch (elementSizeFor(schema.whichElementType())) {
1364 case ElementSize::VOID: break;
1365 case ElementSize::BIT: builder.setDataElement<bool>(bounded(index) * ELEMENTS, false); break;
1366 case ElementSize::BYTE: builder.setDataElement<uint8_t>(bounded(index) * ELEMENTS, 0); break;
1367 case ElementSize::TWO_BYTES: builder.setDataElement<uint16_t>(bounded(index) * ELEMENTS, 0); break;
1368 case ElementSize::FOUR_BYTES: builder.setDataElement<uint32_t>(bounded(index) * ELEMENTS, 0); break;
1369 case ElementSize::EIGHT_BYTES: builder.setDataElement<uint64_t>(bounded(index) * ELEMENTS, 0);break;
1370
1371 case ElementSize::POINTER:
1372 case ElementSize::INLINE_COMPOSITE:
1373 KJ_UNREACHABLE;
1374 }
1375 return kj::mv(result);
1376 }
1377
1378 case schema::Type::TEXT:
1379 case schema::Type::DATA:
1380 case schema::Type::LIST:
1381 case schema::Type::ANY_POINTER:
1382 case schema::Type::INTERFACE: {
1383 auto value = operator[](index);
1384 return Orphan<DynamicValue>(value, builder.getPointerElement(bounded(index) * ELEMENTS).disown());
1385 }
1386
1387 case schema::Type::STRUCT: {
1388 // We have to make a copy.
1389 Orphan<DynamicStruct> result =
1390 Orphanage::getForMessageContaining(*this).newOrphan(schema.getStructElementType());
1391 auto element = builder.getStructElement(bounded(index) * ELEMENTS);
1392 result.get().builder.transferContentFrom(element);
1393 element.clearAll();
1394 return kj::mv(result);
1395 }
1396 }
1397 KJ_UNREACHABLE;
1398 }
1399
1400 void DynamicList::Builder::copyFrom(std::initializer_list<DynamicValue::Reader> value) {
1401 KJ_REQUIRE(value.size() == size(), "DynamicList::copyFrom() argument had different size.");
1402 uint i = 0;
1403 for (auto element: value) {
1404 set(i++, element);
1405 }
1406 }
1407
1408 DynamicList::Reader DynamicList::Builder::asReader() const {
1409 return DynamicList::Reader(schema, builder.asReader());
1410 }
1411
1412 // =======================================================================================
1413
1414 DynamicValue::Reader::Reader(ConstSchema constant): type(VOID) {
1415 auto type = constant.getType();
1416 auto value = constant.getProto().getConst().getValue();
1417 switch (type.which()) {
1418 case schema::Type::VOID: *this = capnp::VOID; break;
1419 case schema::Type::BOOL: *this = value.getBool(); break;
1420 case schema::Type::INT8: *this = value.getInt8(); break;
1421 case schema::Type::INT16: *this = value.getInt16(); break;
1422 case schema::Type::INT32: *this = value.getInt32(); break;
1423 case schema::Type::INT64: *this = value.getInt64(); break;
1424 case schema::Type::UINT8: *this = value.getUint8(); break;
1425 case schema::Type::UINT16: *this = value.getUint16(); break;
1426 case schema::Type::UINT32: *this = value.getUint32(); break;
1427 case schema::Type::UINT64: *this = value.getUint64(); break;
1428 case schema::Type::FLOAT32: *this = value.getFloat32(); break;
1429 case schema::Type::FLOAT64: *this = value.getFloat64(); break;
1430 case schema::Type::TEXT: *this = value.getText(); break;
1431 case schema::Type::DATA: *this = value.getData(); break;
1432
1433 case schema::Type::ENUM:
1434 *this = DynamicEnum(type.asEnum(), value.getEnum());
1435 break;
1436
1437 case schema::Type::STRUCT:
1438 *this = value.getStruct().getAs<DynamicStruct>(type.asStruct());
1439 break;
1440
1441 case schema::Type::LIST:
1442 *this = value.getList().getAs<DynamicList>(type.asList());
1443 break;
1444
1445 case schema::Type::ANY_POINTER:
1446 *this = value.getAnyPointer();
1447 break;
1448
1449 case schema::Type::INTERFACE:
1450 KJ_FAIL_ASSERT("Constants can't have interface type.");
1451 }
1452 }
1453
1454 DynamicValue::Reader::Reader(const Reader& other) {
1455 switch (other.type) {
1456 case UNKNOWN:
1457 case VOID:
1458 case BOOL:
1459 case INT:
1460 case UINT:
1461 case FLOAT:
1462 case TEXT:
1463 case DATA:
1464 case LIST:
1465 case ENUM:
1466 case STRUCT:
1467 case ANY_POINTER:
1468 KJ_ASSERT_CAN_MEMCPY(Text::Reader);
1469 KJ_ASSERT_CAN_MEMCPY(Data::Reader);
1470 KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader);
1471 KJ_ASSERT_CAN_MEMCPY(DynamicEnum);
1472 KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader);
1473 KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader);
1474 break;
1475
1476 case CAPABILITY:
1477 type = CAPABILITY;
1478 kj::ctor(capabilityValue, other.capabilityValue);
1479 return;
1480 }
1481
1482 memcpy(this, &other, sizeof(*this));
1483 }
1484 DynamicValue::Reader::Reader(Reader&& other) noexcept {
1485 switch (other.type) {
1486 case UNKNOWN:
1487 case VOID:
1488 case BOOL:
1489 case INT:
1490 case UINT:
1491 case FLOAT:
1492 case TEXT:
1493 case DATA:
1494 case LIST:
1495 case ENUM:
1496 case STRUCT:
1497 case ANY_POINTER:
1498 KJ_ASSERT_CAN_MEMCPY(Text::Reader);
1499 KJ_ASSERT_CAN_MEMCPY(Data::Reader);
1500 KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader);
1501 KJ_ASSERT_CAN_MEMCPY(DynamicEnum);
1502 KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader);
1503 KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader);
1504 break;
1505
1506 case CAPABILITY:
1507 type = CAPABILITY;
1508 kj::ctor(capabilityValue, kj::mv(other.capabilityValue));
1509 return;
1510 }
1511
1512 memcpy(this, &other, sizeof(*this));
1513 }
1514 DynamicValue::Reader::~Reader() noexcept(false) {
1515 if (type == CAPABILITY) {
1516 kj::dtor(capabilityValue);
1517 }
1518 }
1519
1520 DynamicValue::Reader& DynamicValue::Reader::operator=(const Reader& other) {
1521 if (type == CAPABILITY) {
1522 kj::dtor(capabilityValue);
1523 }
1524 kj::ctor(*this, other);
1525 return *this;
1526 }
1527 DynamicValue::Reader& DynamicValue::Reader::operator=(Reader&& other) {
1528 if (type == CAPABILITY) {
1529 kj::dtor(capabilityValue);
1530 }
1531 kj::ctor(*this, kj::mv(other));
1532 return *this;
1533 }
1534
1535 DynamicValue::Builder::Builder(Builder& other) {
1536 switch (other.type) {
1537 case UNKNOWN:
1538 case VOID:
1539 case BOOL:
1540 case INT:
1541 case UINT:
1542 case FLOAT:
1543 case TEXT:
1544 case DATA:
1545 case LIST:
1546 case ENUM:
1547 case STRUCT:
1548 case ANY_POINTER:
1549 // Unfortunately canMemcpy() doesn't work on these types due to the use of
1550 // DisallowConstCopy, but __has_trivial_destructor should detect if any of these types
1551 // become non-trivial.
1552 static_assert(__has_trivial_destructor(Text::Builder) &&
1553 __has_trivial_destructor(Data::Builder) &&
1554 __has_trivial_destructor(DynamicList::Builder) &&
1555 __has_trivial_destructor(DynamicEnum) &&
1556 __has_trivial_destructor(DynamicStruct::Builder) &&
1557 __has_trivial_destructor(AnyPointer::Builder),
1558 "Assumptions here don't hold.");
1559 break;
1560
1561 case CAPABILITY:
1562 type = CAPABILITY;
1563 kj::ctor(capabilityValue, other.capabilityValue);
1564 return;
1565 }
1566
1567 memcpy(this, &other, sizeof(*this));
1568 }
1569 DynamicValue::Builder::Builder(Builder&& other) noexcept {
1570 switch (other.type) {
1571 case UNKNOWN:
1572 case VOID:
1573 case BOOL:
1574 case INT:
1575 case UINT:
1576 case FLOAT:
1577 case TEXT:
1578 case DATA:
1579 case LIST:
1580 case ENUM:
1581 case STRUCT:
1582 case ANY_POINTER:
1583 // Unfortunately __has_trivial_copy doesn't work on these types due to the use of
1584 // DisallowConstCopy, but __has_trivial_destructor should detect if any of these types
1585 // become non-trivial.
1586 static_assert(__has_trivial_destructor(Text::Builder) &&
1587 __has_trivial_destructor(Data::Builder) &&
1588 __has_trivial_destructor(DynamicList::Builder) &&
1589 __has_trivial_destructor(DynamicEnum) &&
1590 __has_trivial_destructor(DynamicStruct::Builder) &&
1591 __has_trivial_destructor(AnyPointer::Builder),
1592 "Assumptions here don't hold.");
1593 break;
1594
1595 case CAPABILITY:
1596 type = CAPABILITY;
1597 kj::ctor(capabilityValue, kj::mv(other.capabilityValue));
1598 return;
1599 }
1600
1601 memcpy(this, &other, sizeof(*this));
1602 }
1603 DynamicValue::Builder::~Builder() noexcept(false) {
1604 if (type == CAPABILITY) {
1605 kj::dtor(capabilityValue);
1606 }
1607 }
1608
1609 DynamicValue::Builder& DynamicValue::Builder::operator=(Builder& other) {
1610 if (type == CAPABILITY) {
1611 kj::dtor(capabilityValue);
1612 }
1613 kj::ctor(*this, other);
1614 return *this;
1615 }
1616 DynamicValue::Builder& DynamicValue::Builder::operator=(Builder&& other) {
1617 if (type == CAPABILITY) {
1618 kj::dtor(capabilityValue);
1619 }
1620 kj::ctor(*this, kj::mv(other));
1621 return *this;
1622 }
1623
1624 DynamicValue::Reader DynamicValue::Builder::asReader() const {
1625 switch (type) {
1626 case UNKNOWN: return Reader();
1627 case VOID: return Reader(voidValue);
1628 case BOOL: return Reader(boolValue);
1629 case INT: return Reader(intValue);
1630 case UINT: return Reader(uintValue);
1631 case FLOAT: return Reader(floatValue);
1632 case TEXT: return Reader(textValue.asReader());
1633 case DATA: return Reader(dataValue.asReader());
1634 case LIST: return Reader(listValue.asReader());
1635 case ENUM: return Reader(enumValue);
1636 case STRUCT: return Reader(structValue.asReader());
1637 case CAPABILITY: return Reader(capabilityValue);
1638 case ANY_POINTER: return Reader(anyPointerValue.asReader());
1639 }
1640 KJ_FAIL_ASSERT("Missing switch case.");
1641 return Reader();
1642 }
1643
1644 DynamicValue::Pipeline::Pipeline(Pipeline&& other) noexcept: type(other.type) {
1645 switch (type) {
1646 case UNKNOWN: break;
1647 case STRUCT: kj::ctor(structValue, kj::mv(other.structValue)); break;
1648 case CAPABILITY: kj::ctor(capabilityValue, kj::mv(other.capabilityValue)); break;
1649 default:
1650 KJ_LOG(ERROR, "Unexpected pipeline type.", (uint)type);
1651 type = UNKNOWN;
1652 break;
1653 }
1654 }
1655 DynamicValue::Pipeline& DynamicValue::Pipeline::operator=(Pipeline&& other) {
1656 kj::dtor(*this);
1657 kj::ctor(*this, kj::mv(other));
1658 return *this;
1659 }
1660 DynamicValue::Pipeline::~Pipeline() noexcept(false) {
1661 switch (type) {
1662 case UNKNOWN: break;
1663 case STRUCT: kj::dtor(structValue); break;
1664 case CAPABILITY: kj::dtor(capabilityValue); break;
1665 default:
1666 KJ_FAIL_ASSERT("Unexpected pipeline type.", (uint)type) { type = UNKNOWN; break; }
1667 break;
1668 }
1669 }
1670
1671 namespace {
1672
1673 template <typename T>
1674 T signedToUnsigned(long long value) {
1675 KJ_REQUIRE(value >= 0 && T(value) == value, "Value out-of-range for requested type.", value) {
1676 // Use it anyway.
1677 break;
1678 }
1679 return value;
1680 }
1681
1682 template <>
1683 uint64_t signedToUnsigned<uint64_t>(long long value) {
1684 KJ_REQUIRE(value >= 0, "Value out-of-range for requested type.", value) {
1685 // Use it anyway.
1686 break;
1687 }
1688 return value;
1689 }
1690
1691 template <typename T>
1692 T unsignedToSigned(unsigned long long value) {
1693 KJ_REQUIRE(T(value) >= 0 && (unsigned long long)T(value) == value,
1694 "Value out-of-range for requested type.", value) {
1695 // Use it anyway.
1696 break;
1697 }
1698 return value;
1699 }
1700
1701 template <>
1702 int64_t unsignedToSigned<int64_t>(unsigned long long value) {
1703 KJ_REQUIRE(int64_t(value) >= 0, "Value out-of-range for requested type.", value) {
1704 // Use it anyway.
1705 break;
1706 }
1707 return value;
1708 }
1709
1710 template <typename T, typename U>
1711 T checkRoundTrip(U value) {
1712 KJ_REQUIRE(T(value) == value, "Value out-of-range for requested type.", value) {
1713 // Use it anyway.
1714 break;
1715 }
1716 return value;
1717 }
1718
1719 } // namespace
1720
1721 #define HANDLE_NUMERIC_TYPE(typeName, ifInt, ifUint, ifFloat) \
1722 typeName DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
1723 switch (reader.type) { \
1724 case INT: \
1725 return ifInt<typeName>(reader.intValue); \
1726 case UINT: \
1727 return ifUint<typeName>(reader.uintValue); \
1728 case FLOAT: \
1729 return ifFloat<typeName>(reader.floatValue); \
1730 default: \
1731 KJ_FAIL_REQUIRE("Value type mismatch.") { \
1732 return 0; \
1733 } \
1734 } \
1735 } \
1736 typeName DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
1737 switch (builder.type) { \
1738 case INT: \
1739 return ifInt<typeName>(builder.intValue); \
1740 case UINT: \
1741 return ifUint<typeName>(builder.uintValue); \
1742 case FLOAT: \
1743 return ifFloat<typeName>(builder.floatValue); \
1744 default: \
1745 KJ_FAIL_REQUIRE("Value type mismatch.") { \
1746 return 0; \
1747 } \
1748 } \
1749 }
1750
1751 HANDLE_NUMERIC_TYPE(int8_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
1752 HANDLE_NUMERIC_TYPE(int16_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
1753 HANDLE_NUMERIC_TYPE(int32_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
1754 HANDLE_NUMERIC_TYPE(int64_t, kj::implicitCast, unsignedToSigned, checkRoundTrip)
1755 HANDLE_NUMERIC_TYPE(uint8_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
1756 HANDLE_NUMERIC_TYPE(uint16_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
1757 HANDLE_NUMERIC_TYPE(uint32_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
1758 HANDLE_NUMERIC_TYPE(uint64_t, signedToUnsigned, kj::implicitCast, checkRoundTrip)
1759 HANDLE_NUMERIC_TYPE(float, kj::implicitCast, kj::implicitCast, kj::implicitCast)
1760 HANDLE_NUMERIC_TYPE(double, kj::implicitCast, kj::implicitCast, kj::implicitCast)
1761
1762 #undef HANDLE_NUMERIC_TYPE
1763
1764 #define HANDLE_TYPE(name, discrim, typeName) \
1765 ReaderFor<typeName> DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
1766 KJ_REQUIRE(reader.type == discrim, "Value type mismatch.") { \
1767 return ReaderFor<typeName>(); \
1768 } \
1769 return reader.name##Value; \
1770 } \
1771 BuilderFor<typeName> DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
1772 KJ_REQUIRE(builder.type == discrim, "Value type mismatch."); \
1773 return builder.name##Value; \
1774 }
1775
1776 //HANDLE_TYPE(void, VOID, Void)
1777 HANDLE_TYPE(bool, BOOL, bool)
1778
1779 HANDLE_TYPE(text, TEXT, Text)
1780 HANDLE_TYPE(list, LIST, DynamicList)
1781 HANDLE_TYPE(struct, STRUCT, DynamicStruct)
1782 HANDLE_TYPE(enum, ENUM, DynamicEnum)
1783 HANDLE_TYPE(anyPointer, ANY_POINTER, AnyPointer)
1784
1785 #undef HANDLE_TYPE
1786
1787 PipelineFor<DynamicStruct> DynamicValue::Pipeline::AsImpl<DynamicStruct>::apply(
1788 Pipeline& pipeline) {
1789 KJ_REQUIRE(pipeline.type == STRUCT, "Pipeline type mismatch.");
1790 return kj::mv(pipeline.structValue);
1791 }
1792
1793 ReaderFor<DynamicCapability> DynamicValue::Reader::AsImpl<DynamicCapability>::apply(
1794 const Reader& reader) {
1795 KJ_REQUIRE(reader.type == CAPABILITY, "Value type mismatch.") {
1796 return DynamicCapability::Client();
1797 }
1798 return reader.capabilityValue;
1799 }
1800 BuilderFor<DynamicCapability> DynamicValue::Builder::AsImpl<DynamicCapability>::apply(
1801 Builder& builder) {
1802 KJ_REQUIRE(builder.type == CAPABILITY, "Value type mismatch.") {
1803 return DynamicCapability::Client();
1804 }
1805 return builder.capabilityValue;
1806 }
1807 PipelineFor<DynamicCapability> DynamicValue::Pipeline::AsImpl<DynamicCapability>::apply(
1808 Pipeline& pipeline) {
1809 KJ_REQUIRE(pipeline.type == CAPABILITY, "Pipeline type mismatch.") {
1810 return DynamicCapability::Client();
1811 }
1812 return kj::mv(pipeline.capabilityValue);
1813 }
1814
1815 Data::Reader DynamicValue::Reader::AsImpl<Data>::apply(const Reader& reader) {
1816 if (reader.type == TEXT) {
1817 // Coerce text to data.
1818 return reader.textValue.asBytes();
1819 }
1820 KJ_REQUIRE(reader.type == DATA, "Value type mismatch.") {
1821 return Data::Reader();
1822 }
1823 return reader.dataValue;
1824 }
1825 Data::Builder DynamicValue::Builder::AsImpl<Data>::apply(Builder& builder) {
1826 if (builder.type == TEXT) {
1827 // Coerce text to data.
1828 return builder.textValue.asBytes();
1829 }
1830 KJ_REQUIRE(builder.type == DATA, "Value type mismatch.") {
1831 return BuilderFor<Data>();
1832 }
1833 return builder.dataValue;
1834 }
1835
1836 // As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
1837 Void DynamicValue::Reader::AsImpl<Void>::apply(const Reader& reader) {
1838 KJ_REQUIRE(reader.type == VOID, "Value type mismatch.") {
1839 return Void();
1840 }
1841 return reader.voidValue;
1842 }
1843 Void DynamicValue::Builder::AsImpl<Void>::apply(Builder& builder) {
1844 KJ_REQUIRE(builder.type == VOID, "Value type mismatch.") {
1845 return Void();
1846 }
1847 return builder.voidValue;
1848 }
1849
1850 // =======================================================================================
1851
1852 namespace _ { // private
1853
1854 DynamicStruct::Reader PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
1855 PointerReader reader, StructSchema schema) {
1856 KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
1857 "Cannot form pointer to group type.");
1858 return DynamicStruct::Reader(schema, reader.getStruct(nullptr));
1859 }
1860 DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
1861 PointerBuilder builder, StructSchema schema) {
1862 KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
1863 "Cannot form pointer to group type.");
1864 return DynamicStruct::Builder(schema, builder.getStruct(
1865 structSizeFromSchema(schema), nullptr));
1866 }
1867 void PointerHelpers<DynamicStruct, Kind::OTHER>::set(
1868 PointerBuilder builder, const DynamicStruct::Reader& value) {
1869 KJ_REQUIRE(!value.schema.getProto().getStruct().getIsGroup(),
1870 "Cannot form pointer to group type.");
1871 builder.setStruct(value.reader);
1872 }
1873 DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::init(
1874 PointerBuilder builder, StructSchema schema) {
1875 KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
1876 "Cannot form pointer to group type.");
1877 return DynamicStruct::Builder(schema,
1878 builder.initStruct(structSizeFromSchema(schema)));
1879 }
1880
1881 DynamicList::Reader PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
1882 PointerReader reader, ListSchema schema) {
1883 return DynamicList::Reader(schema,
1884 reader.getList(elementSizeFor(schema.whichElementType()), nullptr));
1885 }
1886 DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
1887 PointerBuilder builder, ListSchema schema) {
1888 if (schema.whichElementType() == schema::Type::STRUCT) {
1889 return DynamicList::Builder(schema,
1890 builder.getStructList(
1891 structSizeFromSchema(schema.getStructElementType()),
1892 nullptr));
1893 } else {
1894 return DynamicList::Builder(schema,
1895 builder.getList(elementSizeFor(schema.whichElementType()), nullptr));
1896 }
1897 }
1898 void PointerHelpers<DynamicList, Kind::OTHER>::set(
1899 PointerBuilder builder, const DynamicList::Reader& value) {
1900 builder.setList(value.reader);
1901 }
1902 DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::init(
1903 PointerBuilder builder, ListSchema schema, uint size) {
1904 if (schema.whichElementType() == schema::Type::STRUCT) {
1905 return DynamicList::Builder(schema,
1906 builder.initStructList(bounded(size) * ELEMENTS,
1907 structSizeFromSchema(schema.getStructElementType())));
1908 } else {
1909 return DynamicList::Builder(schema,
1910 builder.initList(elementSizeFor(schema.whichElementType()), bounded(size) * ELEMENTS));
1911 }
1912 }
1913
1914 DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
1915 PointerReader reader, InterfaceSchema schema) {
1916 return DynamicCapability::Client(schema, reader.getCapability());
1917 }
1918 DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
1919 PointerBuilder builder, InterfaceSchema schema) {
1920 return DynamicCapability::Client(schema, builder.getCapability());
1921 }
1922 void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
1923 PointerBuilder builder, DynamicCapability::Client& value) {
1924 builder.setCapability(value.hook->addRef());
1925 }
1926 void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
1927 PointerBuilder builder, DynamicCapability::Client&& value) {
1928 builder.setCapability(kj::mv(value.hook));
1929 }
1930
1931 } // namespace _ (private)
1932
1933 template <>
1934 void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan) {
1935 switch (orphan.getType()) {
1936 case DynamicValue::UNKNOWN:
1937 case DynamicValue::VOID:
1938 case DynamicValue::BOOL:
1939 case DynamicValue::INT:
1940 case DynamicValue::UINT:
1941 case DynamicValue::FLOAT:
1942 case DynamicValue::ENUM:
1943 KJ_FAIL_REQUIRE("AnyPointer cannot adopt primitive (non-object) value.");
1944
1945 case DynamicValue::STRUCT:
1946 case DynamicValue::LIST:
1947 case DynamicValue::TEXT:
1948 case DynamicValue::DATA:
1949 case DynamicValue::CAPABILITY:
1950 case DynamicValue::ANY_POINTER:
1951 builder.adopt(kj::mv(orphan.builder));
1952 break;
1953 }
1954 }
1955
1956 DynamicStruct::Reader::Reader(StructSchema schema, const _::OrphanBuilder& orphan)
1957 : schema(schema), reader(orphan.asStructReader(structSizeFromSchema(schema))) {}
1958 DynamicStruct::Builder::Builder(StructSchema schema, _::OrphanBuilder& orphan)
1959 : schema(schema), builder(orphan.asStruct(structSizeFromSchema(schema))) {}
1960
1961 DynamicList::Reader::Reader(ListSchema schema, const _::OrphanBuilder& orphan)
1962 : schema(schema), reader(orphan.asListReader(elementSizeFor(schema.whichElementType()))) {}
1963 DynamicList::Builder::Builder(ListSchema schema, _::OrphanBuilder& orphan)
1964 : schema(schema), builder(schema.whichElementType() == schema::Type::STRUCT
1965 ? orphan.asStructList(structSizeFromSchema(schema.getStructElementType()))
1966 : orphan.asList(elementSizeFor(schema.whichElementType()))) {}
1967
1968 // -------------------------------------------------------------------
1969
1970 Orphan<DynamicStruct> Orphanage::newOrphan(StructSchema schema) const {
1971 return Orphan<DynamicStruct>(
1972 schema, _::OrphanBuilder::initStruct(arena, capTable, structSizeFromSchema(schema)));
1973 }
1974
1975 Orphan<DynamicList> Orphanage::newOrphan(ListSchema schema, uint size) const {
1976 if (schema.whichElementType() == schema::Type::STRUCT) {
1977 return Orphan<DynamicList>(schema, _::OrphanBuilder::initStructList(
1978 arena, capTable, bounded(size) * ELEMENTS,
1979 structSizeFromSchema(schema.getStructElementType())));
1980 } else {
1981 return Orphan<DynamicList>(schema, _::OrphanBuilder::initList(
1982 arena, capTable, bounded(size) * ELEMENTS,
1983 elementSizeFor(schema.whichElementType())));
1984 }
1985 }
1986
1987 DynamicStruct::Builder Orphan<DynamicStruct>::get() {
1988 return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema)));
1989 }
1990
1991 DynamicStruct::Reader Orphan<DynamicStruct>::getReader() const {
1992 return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
1993 }
1994
1995 DynamicList::Builder Orphan<DynamicList>::get() {
1996 if (schema.whichElementType() == schema::Type::STRUCT) {
1997 return DynamicList::Builder(
1998 schema, builder.asStructList(structSizeFromSchema(schema.getStructElementType())));
1999 } else {
2000 return DynamicList::Builder(
2001 schema, builder.asList(elementSizeFor(schema.whichElementType())));
2002 }
2003 }
2004
2005 DynamicList::Reader Orphan<DynamicList>::getReader() const {
2006 return DynamicList::Reader(
2007 schema, builder.asListReader(elementSizeFor(schema.whichElementType())));
2008 }
2009
2010 DynamicCapability::Client Orphan<DynamicCapability>::get() {
2011 return DynamicCapability::Client(schema, builder.asCapability());
2012 }
2013
2014 DynamicCapability::Client Orphan<DynamicCapability>::getReader() const {
2015 return DynamicCapability::Client(schema, builder.asCapability());
2016 }
2017
2018 Orphan<DynamicValue>::Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder)
2019 : type(value.getType()), builder(kj::mv(builder)) {
2020 switch (type) {
2021 case DynamicValue::UNKNOWN: break;
2022 case DynamicValue::VOID: voidValue = value.voidValue; break;
2023 case DynamicValue::BOOL: boolValue = value.boolValue; break;
2024 case DynamicValue::INT: intValue = value.intValue; break;
2025 case DynamicValue::UINT: uintValue = value.uintValue; break;
2026 case DynamicValue::FLOAT: floatValue = value.floatValue; break;
2027 case DynamicValue::ENUM: enumValue = value.enumValue; break;
2028
2029 case DynamicValue::TEXT: break;
2030 case DynamicValue::DATA: break;
2031 case DynamicValue::LIST: listSchema = value.listValue.getSchema(); break;
2032 case DynamicValue::STRUCT: structSchema = value.structValue.getSchema(); break;
2033 case DynamicValue::CAPABILITY: interfaceSchema = value.capabilityValue.getSchema(); break;
2034 case DynamicValue::ANY_POINTER: break;
2035 }
2036 }
2037
2038 DynamicValue::Builder Orphan<DynamicValue>::get() {
2039 switch (type) {
2040 case DynamicValue::UNKNOWN: return nullptr;
2041 case DynamicValue::VOID: return voidValue;
2042 case DynamicValue::BOOL: return boolValue;
2043 case DynamicValue::INT: return intValue;
2044 case DynamicValue::UINT: return uintValue;
2045 case DynamicValue::FLOAT: return floatValue;
2046 case DynamicValue::ENUM: return enumValue;
2047
2048 case DynamicValue::TEXT: return builder.asText();
2049 case DynamicValue::DATA: return builder.asData();
2050 case DynamicValue::LIST:
2051 if (listSchema.whichElementType() == schema::Type::STRUCT) {
2052 return DynamicList::Builder(listSchema,
2053 builder.asStructList(structSizeFromSchema(listSchema.getStructElementType())));
2054 } else {
2055 return DynamicList::Builder(listSchema,
2056 builder.asList(elementSizeFor(listSchema.whichElementType())));
2057 }
2058 case DynamicValue::STRUCT:
2059 return DynamicStruct::Builder(structSchema,
2060 builder.asStruct(structSizeFromSchema(structSchema)));
2061 case DynamicValue::CAPABILITY:
2062 return DynamicCapability::Client(interfaceSchema, builder.asCapability());
2063 case DynamicValue::ANY_POINTER:
2064 KJ_FAIL_REQUIRE("Can't get() an AnyPointer orphan; there is no underlying pointer to "
2065 "wrap in an AnyPointer::Builder.");
2066 }
2067 KJ_UNREACHABLE;
2068 }
2069 DynamicValue::Reader Orphan<DynamicValue>::getReader() const {
2070 switch (type) {
2071 case DynamicValue::UNKNOWN: return nullptr;
2072 case DynamicValue::VOID: return voidValue;
2073 case DynamicValue::BOOL: return boolValue;
2074 case DynamicValue::INT: return intValue;
2075 case DynamicValue::UINT: return uintValue;
2076 case DynamicValue::FLOAT: return floatValue;
2077 case DynamicValue::ENUM: return enumValue;
2078
2079 case DynamicValue::TEXT: return builder.asTextReader();
2080 case DynamicValue::DATA: return builder.asDataReader();
2081 case DynamicValue::LIST:
2082 return DynamicList::Reader(listSchema,
2083 builder.asListReader(elementSizeFor(listSchema.whichElementType())));
2084 case DynamicValue::STRUCT:
2085 return DynamicStruct::Reader(structSchema,
2086 builder.asStructReader(structSizeFromSchema(structSchema)));
2087 case DynamicValue::CAPABILITY:
2088 return DynamicCapability::Client(interfaceSchema, builder.asCapability());
2089 case DynamicValue::ANY_POINTER:
2090 KJ_FAIL_ASSERT("Can't get() an AnyPointer orphan; there is no underlying pointer to "
2091 "wrap in an AnyPointer::Builder.");
2092 }
2093 KJ_UNREACHABLE;
2094 }
2095
2096 template <>
2097 Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>() {
2098 KJ_REQUIRE(type == DynamicValue::ANY_POINTER, "Value type mismatch.");
2099 type = DynamicValue::UNKNOWN;
2100 return Orphan<AnyPointer>(kj::mv(builder));
2101 }
2102 template <>
2103 Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>() {
2104 KJ_REQUIRE(type == DynamicValue::STRUCT, "Value type mismatch.");
2105 type = DynamicValue::UNKNOWN;
2106 return Orphan<DynamicStruct>(structSchema, kj::mv(builder));
2107 }
2108 template <>
2109 Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>() {
2110 KJ_REQUIRE(type == DynamicValue::LIST, "Value type mismatch.");
2111 type = DynamicValue::UNKNOWN;
2112 return Orphan<DynamicList>(listSchema, kj::mv(builder));
2113 }
2114
2115 template <>
2116 Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
2117 DynamicValue::Reader copyFrom) const {
2118 switch (copyFrom.getType()) {
2119 case DynamicValue::UNKNOWN: return nullptr;
2120 case DynamicValue::VOID: return copyFrom.voidValue;
2121 case DynamicValue::BOOL: return copyFrom.boolValue;
2122 case DynamicValue::INT: return copyFrom.intValue;
2123 case DynamicValue::UINT: return copyFrom.uintValue;
2124 case DynamicValue::FLOAT: return copyFrom.floatValue;
2125 case DynamicValue::ENUM: return copyFrom.enumValue;
2126
2127 case DynamicValue::TEXT: return newOrphanCopy(copyFrom.textValue);
2128 case DynamicValue::DATA: return newOrphanCopy(copyFrom.dataValue);
2129 case DynamicValue::LIST: return newOrphanCopy(copyFrom.listValue);
2130 case DynamicValue::STRUCT: return newOrphanCopy(copyFrom.structValue);
2131 case DynamicValue::CAPABILITY: return newOrphanCopy(copyFrom.capabilityValue);
2132 case DynamicValue::ANY_POINTER: return newOrphanCopy(copyFrom.anyPointerValue);
2133 }
2134 KJ_UNREACHABLE;
2135 }
2136
2137 } // namespace capnp