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
25namespace capnp {
26
27namespace {
28
29bool hasDiscriminantValue(const schema::Field::Reader& reader) {
30 return reader.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT;
31}
32
33template <typename T, typename U>
34KJ_ALWAYS_INLINE(T bitCast(U value));
35
36template <typename T, typename U>
37inline T bitCast(U value) {
38 static_assert(sizeof(T) == sizeof(U), "Size must match.");
39 return value;
40}
41template <>
42inline float bitCast<float, uint32_t>(uint32_t value) KJ_UNUSED;
43template <>
44inline float bitCast<float, uint32_t>(uint32_t value) {
45 float result;
46 memcpy(&result, &value, sizeof(value));
47 return result;
48}
49template <>
50inline double bitCast<double, uint64_t>(uint64_t value) KJ_UNUSED;
51template <>
52inline double bitCast<double, uint64_t>(uint64_t value) {
53 double result;
54 memcpy(&result, &value, sizeof(value));
55 return result;
56}
57template <>
58inline uint32_t bitCast<uint32_t, float>(float value) {
59 uint32_t result;
60 memcpy(&result, &value, sizeof(value));
61 return result;
62}
63template <>
64inline uint64_t bitCast<uint64_t, double>(double value) {
65 uint64_t result;
66 memcpy(&result, &value, sizeof(value));
67 return result;
68}
69
70ElementSize 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
98inline _::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
109kj::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
118uint16_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
129bool 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
140void 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
146bool 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
157void 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
163void 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
173DynamicValue::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
265DynamicValue::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
370DynamicValue::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
417bool 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
487kj::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
498kj::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
509void 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
670DynamicValue::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
706DynamicValue::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
753void 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
857Orphan<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
928void 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
995DynamicValue::Reader DynamicStruct::Reader::get(kj::StringPtr name) const {
996 return get(schema.getFieldByName(name));
997}
998DynamicValue::Builder DynamicStruct::Builder::get(kj::StringPtr name) {
999 return get(schema.getFieldByName(name));
1000}
1001DynamicValue::Pipeline DynamicStruct::Pipeline::get(kj::StringPtr name) {
1002 return get(schema.getFieldByName(name));
1003}
1004bool DynamicStruct::Reader::has(kj::StringPtr name, HasMode mode) const {
1005 return has(schema.getFieldByName(name), mode);
1006}
1007bool DynamicStruct::Builder::has(kj::StringPtr name, HasMode mode) {
1008 return has(schema.getFieldByName(name), mode);
1009}
1010void DynamicStruct::Builder::set(kj::StringPtr name, const DynamicValue::Reader& value) {
1011 set(schema.getFieldByName(name), value);
1012}
1013void 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}
1021DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name) {
1022 return init(schema.getFieldByName(name));
1023}
1024DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name, uint size) {
1025 return init(schema.getFieldByName(name), size);
1026}
1027void DynamicStruct::Builder::adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan) {
1028 adopt(schema.getFieldByName(name), kj::mv(orphan));
1029}
1030Orphan<DynamicValue> DynamicStruct::Builder::disown(kj::StringPtr name) {
1031 return disown(schema.getFieldByName(name));
1032}
1033void DynamicStruct::Builder::clear(kj::StringPtr name) {
1034 clear(schema.getFieldByName(name));
1035}
1036
1037// =======================================================================================
1038
1039DynamicValue::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
1095DynamicValue::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
1159void 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
1247DynamicValue::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
1302void 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
1363Orphan<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
1416void 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
1424DynamicList::Reader DynamicList::Builder::asReader() const {
1425 return DynamicList::Reader(schema, builder.asReader());
1426}
1427
1428// =======================================================================================
1429
1430DynamicValue::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
1470DynamicValue::Reader::Reader(const Reader& other) {
1471 switch (other.type) {
1472 case UNKNOWN:
1473 case VOID:
1474 case BOOL:
1475 case INT:
1476 case UINT:
1477 case FLOAT:
1478 case TEXT:
1479 case DATA:
1480 case LIST:
1481 case ENUM:
1482 case STRUCT:
1483 case ANY_POINTER:
1484 KJ_ASSERT_CAN_MEMCPY(Text::Reader);
1485 KJ_ASSERT_CAN_MEMCPY(Data::Reader);
1486 KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader);
1487 KJ_ASSERT_CAN_MEMCPY(DynamicEnum);
1488 KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader);
1489 KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader);
1490 break;
1491
1492 case CAPABILITY:
1493 type = CAPABILITY;
1494 kj::ctor(capabilityValue, other.capabilityValue);
1495 return;
1496 }
1497
1498 memcpy(this, &other, sizeof(*this));
1499}
1500DynamicValue::Reader::Reader(Reader&& other) noexcept {
1501 switch (other.type) {
1502 case UNKNOWN:
1503 case VOID:
1504 case BOOL:
1505 case INT:
1506 case UINT:
1507 case FLOAT:
1508 case TEXT:
1509 case DATA:
1510 case LIST:
1511 case ENUM:
1512 case STRUCT:
1513 case ANY_POINTER:
1514 KJ_ASSERT_CAN_MEMCPY(Text::Reader);
1515 KJ_ASSERT_CAN_MEMCPY(Data::Reader);
1516 KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader);
1517 KJ_ASSERT_CAN_MEMCPY(DynamicEnum);
1518 KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader);
1519 KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader);
1520 break;
1521
1522 case CAPABILITY:
1523 type = CAPABILITY;
1524 kj::ctor(capabilityValue, kj::mv(other.capabilityValue));
1525 return;
1526 }
1527
1528 memcpy(this, &other, sizeof(*this));
1529}
1530DynamicValue::Reader::~Reader() noexcept(false) {
1531 if (type == CAPABILITY) {
1532 kj::dtor(capabilityValue);
1533 }
1534}
1535
1536DynamicValue::Reader& DynamicValue::Reader::operator=(const Reader& other) {
1537 if (type == CAPABILITY) {
1538 kj::dtor(capabilityValue);
1539 }
1540 kj::ctor(*this, other);
1541 return *this;
1542}
1543DynamicValue::Reader& DynamicValue::Reader::operator=(Reader&& other) {
1544 if (type == CAPABILITY) {
1545 kj::dtor(capabilityValue);
1546 }
1547 kj::ctor(*this, kj::mv(other));
1548 return *this;
1549}
1550
1551DynamicValue::Builder::Builder(Builder& other) {
1552 switch (other.type) {
1553 case UNKNOWN:
1554 case VOID:
1555 case BOOL:
1556 case INT:
1557 case UINT:
1558 case FLOAT:
1559 case TEXT:
1560 case DATA:
1561 case LIST:
1562 case ENUM:
1563 case STRUCT:
1564 case ANY_POINTER:
1565 // Unfortunately canMemcpy() doesn't work on these types due to the use of
1566 // DisallowConstCopy, but __has_trivial_destructor should detect if any of these types
1567 // become non-trivial.
1568 static_assert(__has_trivial_destructor(Text::Builder) &&
1569 __has_trivial_destructor(Data::Builder) &&
1570 __has_trivial_destructor(DynamicList::Builder) &&
1571 __has_trivial_destructor(DynamicEnum) &&
1572 __has_trivial_destructor(DynamicStruct::Builder) &&
1573 __has_trivial_destructor(AnyPointer::Builder),
1574 "Assumptions here don't hold.");
1575 break;
1576
1577 case CAPABILITY:
1578 type = CAPABILITY;
1579 kj::ctor(capabilityValue, other.capabilityValue);
1580 return;
1581 }
1582
1583 memcpy(this, &other, sizeof(*this));
1584}
1585DynamicValue::Builder::Builder(Builder&& other) noexcept {
1586 switch (other.type) {
1587 case UNKNOWN:
1588 case VOID:
1589 case BOOL:
1590 case INT:
1591 case UINT:
1592 case FLOAT:
1593 case TEXT:
1594 case DATA:
1595 case LIST:
1596 case ENUM:
1597 case STRUCT:
1598 case ANY_POINTER:
1599 // Unfortunately __has_trivial_copy doesn't work on these types due to the use of
1600 // DisallowConstCopy, but __has_trivial_destructor should detect if any of these types
1601 // become non-trivial.
1602 static_assert(__has_trivial_destructor(Text::Builder) &&
1603 __has_trivial_destructor(Data::Builder) &&
1604 __has_trivial_destructor(DynamicList::Builder) &&
1605 __has_trivial_destructor(DynamicEnum) &&
1606 __has_trivial_destructor(DynamicStruct::Builder) &&
1607 __has_trivial_destructor(AnyPointer::Builder),
1608 "Assumptions here don't hold.");
1609 break;
1610
1611 case CAPABILITY:
1612 type = CAPABILITY;
1613 kj::ctor(capabilityValue, kj::mv(other.capabilityValue));
1614 return;
1615 }
1616
1617 memcpy(this, &other, sizeof(*this));
1618}
1619DynamicValue::Builder::~Builder() noexcept(false) {
1620 if (type == CAPABILITY) {
1621 kj::dtor(capabilityValue);
1622 }
1623}
1624
1625DynamicValue::Builder& DynamicValue::Builder::operator=(Builder& other) {
1626 if (type == CAPABILITY) {
1627 kj::dtor(capabilityValue);
1628 }
1629 kj::ctor(*this, other);
1630 return *this;
1631}
1632DynamicValue::Builder& DynamicValue::Builder::operator=(Builder&& other) {
1633 if (type == CAPABILITY) {
1634 kj::dtor(capabilityValue);
1635 }
1636 kj::ctor(*this, kj::mv(other));
1637 return *this;
1638}
1639
1640DynamicValue::Reader DynamicValue::Builder::asReader() const {
1641 switch (type) {
1642 case UNKNOWN: return Reader();
1643 case VOID: return Reader(voidValue);
1644 case BOOL: return Reader(boolValue);
1645 case INT: return Reader(intValue);
1646 case UINT: return Reader(uintValue);
1647 case FLOAT: return Reader(floatValue);
1648 case TEXT: return Reader(textValue.asReader());
1649 case DATA: return Reader(dataValue.asReader());
1650 case LIST: return Reader(listValue.asReader());
1651 case ENUM: return Reader(enumValue);
1652 case STRUCT: return Reader(structValue.asReader());
1653 case CAPABILITY: return Reader(capabilityValue);
1654 case ANY_POINTER: return Reader(anyPointerValue.asReader());
1655 }
1656 KJ_FAIL_ASSERT("Missing switch case.");
1657 return Reader();
1658}
1659
1660DynamicValue::Pipeline::Pipeline(Pipeline&& other) noexcept: type(other.type) {
1661 switch (type) {
1662 case UNKNOWN: break;
1663 case STRUCT: kj::ctor(structValue, kj::mv(other.structValue)); break;
1664 case CAPABILITY: kj::ctor(capabilityValue, kj::mv(other.capabilityValue)); break;
1665 default:
1666 KJ_LOG(ERROR, "Unexpected pipeline type.", (uint)type);
1667 type = UNKNOWN;
1668 break;
1669 }
1670}
1671DynamicValue::Pipeline& DynamicValue::Pipeline::operator=(Pipeline&& other) {
1672 kj::dtor(*this);
1673 kj::ctor(*this, kj::mv(other));
1674 return *this;
1675}
1676DynamicValue::Pipeline::~Pipeline() noexcept(false) {
1677 switch (type) {
1678 case UNKNOWN: break;
1679 case STRUCT: kj::dtor(structValue); break;
1680 case CAPABILITY: kj::dtor(capabilityValue); break;
1681 default:
1682 KJ_FAIL_ASSERT("Unexpected pipeline type.", (uint)type) { type = UNKNOWN; break; }
1683 break;
1684 }
1685}
1686
1687namespace {
1688
1689template <typename T>
1690T signedToUnsigned(long long value) {
1691 KJ_REQUIRE(value >= 0 && T(value) == value, "Value out-of-range for requested type.", value) {
1692 // Use it anyway.
1693 break;
1694 }
1695 return value;
1696}
1697
1698template <>
1699uint64_t signedToUnsigned<uint64_t>(long long value) {
1700 KJ_REQUIRE(value >= 0, "Value out-of-range for requested type.", value) {
1701 // Use it anyway.
1702 break;
1703 }
1704 return value;
1705}
1706
1707template <typename T>
1708T unsignedToSigned(unsigned long long value) {
1709 KJ_REQUIRE(T(value) >= 0 && (unsigned long long)T(value) == value,
1710 "Value out-of-range for requested type.", value) {
1711 // Use it anyway.
1712 break;
1713 }
1714 return value;
1715}
1716
1717template <>
1718int64_t unsignedToSigned<int64_t>(unsigned long long value) {
1719 KJ_REQUIRE(int64_t(value) >= 0, "Value out-of-range for requested type.", value) {
1720 // Use it anyway.
1721 break;
1722 }
1723 return value;
1724}
1725
1726template <typename T, typename U>
1727T checkRoundTrip(U value) {
1728#if __aarch64__
1729 // Work around an apparently broken compiler optimization on Clang / arm64. It appears that
1730 // for T = int8_t, U = double, and value = 128, the compiler incorrectly believes that the
1731 // round-trip does not change the value, where in fact it should change to -128. Similar problems
1732 // exist for various other types and inputs -- json-test seems to exercise several problem cases.
1733 // The problem only exists when compiling with optimization. In any case, declaring the variable
1734 // `volatile` kills the optimization.
1735 volatile
1736#endif
1737 T result = value;
1738 KJ_REQUIRE(U(result) == value, "Value out-of-range for requested type.", value) {
1739 // Use it anyway.
1740 break;
1741 }
1742 return result;
1743}
1744
1745} // namespace
1746
1747#define HANDLE_NUMERIC_TYPE(typeName, ifInt, ifUint, ifFloat) \
1748typeName DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
1749 switch (reader.type) { \
1750 case INT: \
1751 return ifInt<typeName>(reader.intValue); \
1752 case UINT: \
1753 return ifUint<typeName>(reader.uintValue); \
1754 case FLOAT: \
1755 return ifFloat<typeName>(reader.floatValue); \
1756 default: \
1757 KJ_FAIL_REQUIRE("Value type mismatch.") { \
1758 return 0; \
1759 } \
1760 } \
1761} \
1762typeName DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
1763 switch (builder.type) { \
1764 case INT: \
1765 return ifInt<typeName>(builder.intValue); \
1766 case UINT: \
1767 return ifUint<typeName>(builder.uintValue); \
1768 case FLOAT: \
1769 return ifFloat<typeName>(builder.floatValue); \
1770 default: \
1771 KJ_FAIL_REQUIRE("Value type mismatch.") { \
1772 return 0; \
1773 } \
1774 } \
1775}
1776
1777HANDLE_NUMERIC_TYPE(int8_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
1778HANDLE_NUMERIC_TYPE(int16_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
1779HANDLE_NUMERIC_TYPE(int32_t, checkRoundTrip, unsignedToSigned, checkRoundTrip)
1780HANDLE_NUMERIC_TYPE(int64_t, kj::implicitCast, unsignedToSigned, checkRoundTrip)
1781HANDLE_NUMERIC_TYPE(uint8_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
1782HANDLE_NUMERIC_TYPE(uint16_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
1783HANDLE_NUMERIC_TYPE(uint32_t, signedToUnsigned, checkRoundTrip, checkRoundTrip)
1784HANDLE_NUMERIC_TYPE(uint64_t, signedToUnsigned, kj::implicitCast, checkRoundTrip)
1785HANDLE_NUMERIC_TYPE(float, kj::implicitCast, kj::implicitCast, kj::implicitCast)
1786HANDLE_NUMERIC_TYPE(double, kj::implicitCast, kj::implicitCast, kj::implicitCast)
1787
1788#undef HANDLE_NUMERIC_TYPE
1789
1790#define HANDLE_TYPE(name, discrim, typeName) \
1791ReaderFor<typeName> DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
1792 KJ_REQUIRE(reader.type == discrim, "Value type mismatch.") { \
1793 return ReaderFor<typeName>(); \
1794 } \
1795 return reader.name##Value; \
1796} \
1797BuilderFor<typeName> DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
1798 KJ_REQUIRE(builder.type == discrim, "Value type mismatch."); \
1799 return builder.name##Value; \
1800}
1801
1802//HANDLE_TYPE(void, VOID, Void)
1803HANDLE_TYPE(bool, BOOL, bool)
1804
1805HANDLE_TYPE(text, TEXT, Text)
1806HANDLE_TYPE(list, LIST, DynamicList)
1807HANDLE_TYPE(struct, STRUCT, DynamicStruct)
1808HANDLE_TYPE(enum, ENUM, DynamicEnum)
1809HANDLE_TYPE(anyPointer, ANY_POINTER, AnyPointer)
1810
1811#undef HANDLE_TYPE
1812
1813PipelineFor<DynamicStruct> DynamicValue::Pipeline::AsImpl<DynamicStruct>::apply(
1814 Pipeline& pipeline) {
1815 KJ_REQUIRE(pipeline.type == STRUCT, "Pipeline type mismatch.");
1816 return kj::mv(pipeline.structValue);
1817}
1818
1819ReaderFor<DynamicCapability> DynamicValue::Reader::AsImpl<DynamicCapability>::apply(
1820 const Reader& reader) {
1821 KJ_REQUIRE(reader.type == CAPABILITY, "Value type mismatch.") {
1822 return DynamicCapability::Client();
1823 }
1824 return reader.capabilityValue;
1825}
1826BuilderFor<DynamicCapability> DynamicValue::Builder::AsImpl<DynamicCapability>::apply(
1827 Builder& builder) {
1828 KJ_REQUIRE(builder.type == CAPABILITY, "Value type mismatch.") {
1829 return DynamicCapability::Client();
1830 }
1831 return builder.capabilityValue;
1832}
1833PipelineFor<DynamicCapability> DynamicValue::Pipeline::AsImpl<DynamicCapability>::apply(
1834 Pipeline& pipeline) {
1835 KJ_REQUIRE(pipeline.type == CAPABILITY, "Pipeline type mismatch.") {
1836 return DynamicCapability::Client();
1837 }
1838 return kj::mv(pipeline.capabilityValue);
1839}
1840
1841Data::Reader DynamicValue::Reader::AsImpl<Data>::apply(const Reader& reader) {
1842 if (reader.type == TEXT) {
1843 // Coerce text to data.
1844 return reader.textValue.asBytes();
1845 }
1846 KJ_REQUIRE(reader.type == DATA, "Value type mismatch.") {
1847 return Data::Reader();
1848 }
1849 return reader.dataValue;
1850}
1851Data::Builder DynamicValue::Builder::AsImpl<Data>::apply(Builder& builder) {
1852 if (builder.type == TEXT) {
1853 // Coerce text to data.
1854 return builder.textValue.asBytes();
1855 }
1856 KJ_REQUIRE(builder.type == DATA, "Value type mismatch.") {
1857 return BuilderFor<Data>();
1858 }
1859 return builder.dataValue;
1860}
1861
1862// As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
1863Void DynamicValue::Reader::AsImpl<Void>::apply(const Reader& reader) {
1864 KJ_REQUIRE(reader.type == VOID, "Value type mismatch.") {
1865 return Void();
1866 }
1867 return reader.voidValue;
1868}
1869Void DynamicValue::Builder::AsImpl<Void>::apply(Builder& builder) {
1870 KJ_REQUIRE(builder.type == VOID, "Value type mismatch.") {
1871 return Void();
1872 }
1873 return builder.voidValue;
1874}
1875
1876// =======================================================================================
1877
1878namespace _ { // private
1879
1880DynamicStruct::Reader PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
1881 PointerReader reader, StructSchema schema) {
1882 KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
1883 "Cannot form pointer to group type.");
1884 return DynamicStruct::Reader(schema, reader.getStruct(nullptr));
1885}
1886DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
1887 PointerBuilder builder, StructSchema schema) {
1888 KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
1889 "Cannot form pointer to group type.");
1890 return DynamicStruct::Builder(schema, builder.getStruct(
1891 structSizeFromSchema(schema), nullptr));
1892}
1893void PointerHelpers<DynamicStruct, Kind::OTHER>::set(
1894 PointerBuilder builder, const DynamicStruct::Reader& value) {
1895 KJ_REQUIRE(!value.schema.getProto().getStruct().getIsGroup(),
1896 "Cannot form pointer to group type.");
1897 builder.setStruct(value.reader);
1898}
1899DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::init(
1900 PointerBuilder builder, StructSchema schema) {
1901 KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
1902 "Cannot form pointer to group type.");
1903 return DynamicStruct::Builder(schema,
1904 builder.initStruct(structSizeFromSchema(schema)));
1905}
1906
1907DynamicList::Reader PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
1908 PointerReader reader, ListSchema schema) {
1909 return DynamicList::Reader(schema,
1910 reader.getList(elementSizeFor(schema.whichElementType()), nullptr));
1911}
1912DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
1913 PointerBuilder builder, ListSchema schema) {
1914 if (schema.whichElementType() == schema::Type::STRUCT) {
1915 return DynamicList::Builder(schema,
1916 builder.getStructList(
1917 structSizeFromSchema(schema.getStructElementType()),
1918 nullptr));
1919 } else {
1920 return DynamicList::Builder(schema,
1921 builder.getList(elementSizeFor(schema.whichElementType()), nullptr));
1922 }
1923}
1924void PointerHelpers<DynamicList, Kind::OTHER>::set(
1925 PointerBuilder builder, const DynamicList::Reader& value) {
1926 builder.setList(value.reader);
1927}
1928DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::init(
1929 PointerBuilder builder, ListSchema schema, uint size) {
1930 if (schema.whichElementType() == schema::Type::STRUCT) {
1931 return DynamicList::Builder(schema,
1932 builder.initStructList(bounded(size) * ELEMENTS,
1933 structSizeFromSchema(schema.getStructElementType())));
1934 } else {
1935 return DynamicList::Builder(schema,
1936 builder.initList(elementSizeFor(schema.whichElementType()), bounded(size) * ELEMENTS));
1937 }
1938}
1939
1940DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
1941 PointerReader reader, InterfaceSchema schema) {
1942 return DynamicCapability::Client(schema, reader.getCapability());
1943}
1944DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
1945 PointerBuilder builder, InterfaceSchema schema) {
1946 return DynamicCapability::Client(schema, builder.getCapability());
1947}
1948void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
1949 PointerBuilder builder, DynamicCapability::Client& value) {
1950 builder.setCapability(value.hook->addRef());
1951}
1952void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
1953 PointerBuilder builder, DynamicCapability::Client&& value) {
1954 builder.setCapability(kj::mv(value.hook));
1955}
1956
1957} // namespace _ (private)
1958
1959template <>
1960void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan) {
1961 switch (orphan.getType()) {
1962 case DynamicValue::UNKNOWN:
1963 case DynamicValue::VOID:
1964 case DynamicValue::BOOL:
1965 case DynamicValue::INT:
1966 case DynamicValue::UINT:
1967 case DynamicValue::FLOAT:
1968 case DynamicValue::ENUM:
1969 KJ_FAIL_REQUIRE("AnyPointer cannot adopt primitive (non-object) value.");
1970
1971 case DynamicValue::STRUCT:
1972 case DynamicValue::LIST:
1973 case DynamicValue::TEXT:
1974 case DynamicValue::DATA:
1975 case DynamicValue::CAPABILITY:
1976 case DynamicValue::ANY_POINTER:
1977 builder.adopt(kj::mv(orphan.builder));
1978 break;
1979 }
1980}
1981
1982DynamicStruct::Reader::Reader(StructSchema schema, const _::OrphanBuilder& orphan)
1983 : schema(schema), reader(orphan.asStructReader(structSizeFromSchema(schema))) {}
1984DynamicStruct::Builder::Builder(StructSchema schema, _::OrphanBuilder& orphan)
1985 : schema(schema), builder(orphan.asStruct(structSizeFromSchema(schema))) {}
1986
1987DynamicList::Reader::Reader(ListSchema schema, const _::OrphanBuilder& orphan)
1988 : schema(schema), reader(orphan.asListReader(elementSizeFor(schema.whichElementType()))) {}
1989DynamicList::Builder::Builder(ListSchema schema, _::OrphanBuilder& orphan)
1990 : schema(schema), builder(schema.whichElementType() == schema::Type::STRUCT
1991 ? orphan.asStructList(structSizeFromSchema(schema.getStructElementType()))
1992 : orphan.asList(elementSizeFor(schema.whichElementType()))) {}
1993
1994// -------------------------------------------------------------------
1995
1996Orphan<DynamicStruct> Orphanage::newOrphan(StructSchema schema) const {
1997 return Orphan<DynamicStruct>(
1998 schema, _::OrphanBuilder::initStruct(arena, capTable, structSizeFromSchema(schema)));
1999}
2000
2001Orphan<DynamicList> Orphanage::newOrphan(ListSchema schema, uint size) const {
2002 if (schema.whichElementType() == schema::Type::STRUCT) {
2003 return Orphan<DynamicList>(schema, _::OrphanBuilder::initStructList(
2004 arena, capTable, bounded(size) * ELEMENTS,
2005 structSizeFromSchema(schema.getStructElementType())));
2006 } else {
2007 return Orphan<DynamicList>(schema, _::OrphanBuilder::initList(
2008 arena, capTable, bounded(size) * ELEMENTS,
2009 elementSizeFor(schema.whichElementType())));
2010 }
2011}
2012
2013DynamicStruct::Builder Orphan<DynamicStruct>::get() {
2014 return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema)));
2015}
2016
2017DynamicStruct::Reader Orphan<DynamicStruct>::getReader() const {
2018 return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
2019}
2020
2021DynamicList::Builder Orphan<DynamicList>::get() {
2022 if (schema.whichElementType() == schema::Type::STRUCT) {
2023 return DynamicList::Builder(
2024 schema, builder.asStructList(structSizeFromSchema(schema.getStructElementType())));
2025 } else {
2026 return DynamicList::Builder(
2027 schema, builder.asList(elementSizeFor(schema.whichElementType())));
2028 }
2029}
2030
2031DynamicList::Reader Orphan<DynamicList>::getReader() const {
2032 return DynamicList::Reader(
2033 schema, builder.asListReader(elementSizeFor(schema.whichElementType())));
2034}
2035
2036DynamicCapability::Client Orphan<DynamicCapability>::get() {
2037 return DynamicCapability::Client(schema, builder.asCapability());
2038}
2039
2040DynamicCapability::Client Orphan<DynamicCapability>::getReader() const {
2041 return DynamicCapability::Client(schema, builder.asCapability());
2042}
2043
2044Orphan<DynamicValue>::Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder)
2045 : type(value.getType()), builder(kj::mv(builder)) {
2046 switch (type) {
2047 case DynamicValue::UNKNOWN: break;
2048 case DynamicValue::VOID: voidValue = value.voidValue; break;
2049 case DynamicValue::BOOL: boolValue = value.boolValue; break;
2050 case DynamicValue::INT: intValue = value.intValue; break;
2051 case DynamicValue::UINT: uintValue = value.uintValue; break;
2052 case DynamicValue::FLOAT: floatValue = value.floatValue; break;
2053 case DynamicValue::ENUM: enumValue = value.enumValue; break;
2054
2055 case DynamicValue::TEXT: break;
2056 case DynamicValue::DATA: break;
2057 case DynamicValue::LIST: listSchema = value.listValue.getSchema(); break;
2058 case DynamicValue::STRUCT: structSchema = value.structValue.getSchema(); break;
2059 case DynamicValue::CAPABILITY: interfaceSchema = value.capabilityValue.getSchema(); break;
2060 case DynamicValue::ANY_POINTER: break;
2061 }
2062}
2063
2064DynamicValue::Builder Orphan<DynamicValue>::get() {
2065 switch (type) {
2066 case DynamicValue::UNKNOWN: return nullptr;
2067 case DynamicValue::VOID: return voidValue;
2068 case DynamicValue::BOOL: return boolValue;
2069 case DynamicValue::INT: return intValue;
2070 case DynamicValue::UINT: return uintValue;
2071 case DynamicValue::FLOAT: return floatValue;
2072 case DynamicValue::ENUM: return enumValue;
2073
2074 case DynamicValue::TEXT: return builder.asText();
2075 case DynamicValue::DATA: return builder.asData();
2076 case DynamicValue::LIST:
2077 if (listSchema.whichElementType() == schema::Type::STRUCT) {
2078 return DynamicList::Builder(listSchema,
2079 builder.asStructList(structSizeFromSchema(listSchema.getStructElementType())));
2080 } else {
2081 return DynamicList::Builder(listSchema,
2082 builder.asList(elementSizeFor(listSchema.whichElementType())));
2083 }
2084 case DynamicValue::STRUCT:
2085 return DynamicStruct::Builder(structSchema,
2086 builder.asStruct(structSizeFromSchema(structSchema)));
2087 case DynamicValue::CAPABILITY:
2088 return DynamicCapability::Client(interfaceSchema, builder.asCapability());
2089 case DynamicValue::ANY_POINTER:
2090 KJ_FAIL_REQUIRE("Can't get() an AnyPointer orphan; there is no underlying pointer to "
2091 "wrap in an AnyPointer::Builder.");
2092 }
2093 KJ_UNREACHABLE;
2094}
2095DynamicValue::Reader Orphan<DynamicValue>::getReader() const {
2096 switch (type) {
2097 case DynamicValue::UNKNOWN: return nullptr;
2098 case DynamicValue::VOID: return voidValue;
2099 case DynamicValue::BOOL: return boolValue;
2100 case DynamicValue::INT: return intValue;
2101 case DynamicValue::UINT: return uintValue;
2102 case DynamicValue::FLOAT: return floatValue;
2103 case DynamicValue::ENUM: return enumValue;
2104
2105 case DynamicValue::TEXT: return builder.asTextReader();
2106 case DynamicValue::DATA: return builder.asDataReader();
2107 case DynamicValue::LIST:
2108 return DynamicList::Reader(listSchema,
2109 builder.asListReader(elementSizeFor(listSchema.whichElementType())));
2110 case DynamicValue::STRUCT:
2111 return DynamicStruct::Reader(structSchema,
2112 builder.asStructReader(structSizeFromSchema(structSchema)));
2113 case DynamicValue::CAPABILITY:
2114 return DynamicCapability::Client(interfaceSchema, builder.asCapability());
2115 case DynamicValue::ANY_POINTER:
2116 KJ_FAIL_ASSERT("Can't get() an AnyPointer orphan; there is no underlying pointer to "
2117 "wrap in an AnyPointer::Builder.");
2118 }
2119 KJ_UNREACHABLE;
2120}
2121
2122template <>
2123Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>() {
2124 KJ_REQUIRE(type == DynamicValue::ANY_POINTER, "Value type mismatch.");
2125 type = DynamicValue::UNKNOWN;
2126 return Orphan<AnyPointer>(kj::mv(builder));
2127}
2128template <>
2129Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>() {
2130 KJ_REQUIRE(type == DynamicValue::STRUCT, "Value type mismatch.");
2131 type = DynamicValue::UNKNOWN;
2132 return Orphan<DynamicStruct>(structSchema, kj::mv(builder));
2133}
2134template <>
2135Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>() {
2136 KJ_REQUIRE(type == DynamicValue::LIST, "Value type mismatch.");
2137 type = DynamicValue::UNKNOWN;
2138 return Orphan<DynamicList>(listSchema, kj::mv(builder));
2139}
2140
2141template <>
2142Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
2143 DynamicValue::Reader copyFrom) const {
2144 switch (copyFrom.getType()) {
2145 case DynamicValue::UNKNOWN: return nullptr;
2146 case DynamicValue::VOID: return copyFrom.voidValue;
2147 case DynamicValue::BOOL: return copyFrom.boolValue;
2148 case DynamicValue::INT: return copyFrom.intValue;
2149 case DynamicValue::UINT: return copyFrom.uintValue;
2150 case DynamicValue::FLOAT: return copyFrom.floatValue;
2151 case DynamicValue::ENUM: return copyFrom.enumValue;
2152
2153 case DynamicValue::TEXT: return newOrphanCopy(copyFrom.textValue);
2154 case DynamicValue::DATA: return newOrphanCopy(copyFrom.dataValue);
2155 case DynamicValue::LIST: return newOrphanCopy(copyFrom.listValue);
2156 case DynamicValue::STRUCT: return newOrphanCopy(copyFrom.structValue);
2157 case DynamicValue::CAPABILITY: return newOrphanCopy(copyFrom.capabilityValue);
2158 case DynamicValue::ANY_POINTER: return newOrphanCopy(copyFrom.anyPointerValue);
2159 }
2160 KJ_UNREACHABLE;
2161}
2162
2163} // namespace capnp
2164