comparison src/capnproto-git-20161025/c++/src/capnp/dynamic.c++ @ 48:9530b331f8c1

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