blob: 15ec9b9920808d5e5ac866f26560f15e7f1e0841 [file] [log] [blame]
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "dynamic.h"
#include <kj/debug.h>
namespace capnp {
namespace {
bool hasDiscriminantValue(const schema::Field::Reader& reader) {
return reader.getDiscriminantValue() != schema::Field::NO_DISCRIMINANT;
}
template <typename T, typename U>
KJ_ALWAYS_INLINE(T bitCast(U value));
template <typename T, typename U>
inline T bitCast(U value) {
static_assert(sizeof(T) == sizeof(U), "Size must match.");
return value;
}
template <>
inline float bitCast<float, uint32_t>(uint32_t value) KJ_UNUSED;
template <>
inline float bitCast<float, uint32_t>(uint32_t value) {
float result;
memcpy(&result, &value, sizeof(value));
return result;
}
template <>
inline double bitCast<double, uint64_t>(uint64_t value) KJ_UNUSED;
template <>
inline double bitCast<double, uint64_t>(uint64_t value) {
double result;
memcpy(&result, &value, sizeof(value));
return result;
}
template <>
inline uint32_t bitCast<uint32_t, float>(float value) {
uint32_t result;
memcpy(&result, &value, sizeof(value));
return result;
}
template <>
inline uint64_t bitCast<uint64_t, double>(double value) {
uint64_t result;
memcpy(&result, &value, sizeof(value));
return result;
}
ElementSize elementSizeFor(schema::Type::Which elementType) {
switch (elementType) {
case schema::Type::VOID: return ElementSize::VOID;
case schema::Type::BOOL: return ElementSize::BIT;
case schema::Type::INT8: return ElementSize::BYTE;
case schema::Type::INT16: return ElementSize::TWO_BYTES;
case schema::Type::INT32: return ElementSize::FOUR_BYTES;
case schema::Type::INT64: return ElementSize::EIGHT_BYTES;
case schema::Type::UINT8: return ElementSize::BYTE;
case schema::Type::UINT16: return ElementSize::TWO_BYTES;
case schema::Type::UINT32: return ElementSize::FOUR_BYTES;
case schema::Type::UINT64: return ElementSize::EIGHT_BYTES;
case schema::Type::FLOAT32: return ElementSize::FOUR_BYTES;
case schema::Type::FLOAT64: return ElementSize::EIGHT_BYTES;
case schema::Type::TEXT: return ElementSize::POINTER;
case schema::Type::DATA: return ElementSize::POINTER;
case schema::Type::LIST: return ElementSize::POINTER;
case schema::Type::ENUM: return ElementSize::TWO_BYTES;
case schema::Type::STRUCT: return ElementSize::INLINE_COMPOSITE;
case schema::Type::INTERFACE: return ElementSize::POINTER;
case schema::Type::ANY_POINTER: KJ_FAIL_ASSERT("List(AnyPointer) not supported."); break;
}
// Unknown type. Treat it as zero-size.
return ElementSize::VOID;
}
inline _::StructSize structSizeFromSchema(StructSchema schema) {
auto node = schema.getProto().getStruct();
return _::StructSize(
bounded(node.getDataWordCount()) * WORDS,
bounded(node.getPointerCount()) * POINTERS);
}
} // namespace
// =======================================================================================
kj::Maybe<EnumSchema::Enumerant> DynamicEnum::getEnumerant() const {
auto enumerants = schema.getEnumerants();
if (value < enumerants.size()) {
return enumerants[value];
} else {
return nullptr;
}
}
uint16_t DynamicEnum::asImpl(uint64_t requestedTypeId) const {
KJ_REQUIRE(requestedTypeId == schema.getProto().getId(),
"Type mismatch in DynamicEnum.as().") {
// use it anyway
break;
}
return value;
}
// =======================================================================================
bool DynamicStruct::Reader::isSetInUnion(StructSchema::Field field) const {
auto proto = field.getProto();
if (hasDiscriminantValue(proto)) {
uint16_t discrim = reader.getDataField<uint16_t>(
assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()));
return discrim == proto.getDiscriminantValue();
} else {
return true;
}
}
void DynamicStruct::Reader::verifySetInUnion(StructSchema::Field field) const {
KJ_REQUIRE(isSetInUnion(field),
"Tried to get() a union member which is not currently initialized.",
field.getProto().getName(), schema.getProto().getDisplayName());
}
bool DynamicStruct::Builder::isSetInUnion(StructSchema::Field field) {
auto proto = field.getProto();
if (hasDiscriminantValue(proto)) {
uint16_t discrim = builder.getDataField<uint16_t>(
assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()));
return discrim == proto.getDiscriminantValue();
} else {
return true;
}
}
void DynamicStruct::Builder::verifySetInUnion(StructSchema::Field field) {
KJ_REQUIRE(isSetInUnion(field),
"Tried to get() a union member which is not currently initialized.",
field.getProto().getName(), schema.getProto().getDisplayName());
}
void DynamicStruct::Builder::setInUnion(StructSchema::Field field) {
// If a union member, set the discriminant to match.
auto proto = field.getProto();
if (hasDiscriminantValue(proto)) {
builder.setDataField<uint16_t>(
assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()),
proto.getDiscriminantValue());
}
}
DynamicValue::Reader DynamicStruct::Reader::get(StructSchema::Field field) const {
KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
verifySetInUnion(field);
auto type = field.getType();
auto proto = field.getProto();
switch (proto.which()) {
case schema::Field::SLOT: {
auto slot = proto.getSlot();
// Note that the default value might be "anyPointer" even if the type is some pointer type
// *other than* anyPointer. This happens with generics -- the field is actually a generic
// parameter that has been bound, but the default value was of course compiled without any
// binding available.
auto dval = slot.getDefaultValue();
switch (type.which()) {
case schema::Type::VOID:
return reader.getDataField<Void>(assumeDataOffset(slot.getOffset()));
#define HANDLE_TYPE(discrim, titleCase, type) \
case schema::Type::discrim: \
return reader.getDataField<type>( \
assumeDataOffset(slot.getOffset()), \
bitCast<_::Mask<type>>(dval.get##titleCase()));
HANDLE_TYPE(BOOL, Bool, bool)
HANDLE_TYPE(INT8, Int8, int8_t)
HANDLE_TYPE(INT16, Int16, int16_t)
HANDLE_TYPE(INT32, Int32, int32_t)
HANDLE_TYPE(INT64, Int64, int64_t)
HANDLE_TYPE(UINT8, Uint8, uint8_t)
HANDLE_TYPE(UINT16, Uint16, uint16_t)
HANDLE_TYPE(UINT32, Uint32, uint32_t)
HANDLE_TYPE(UINT64, Uint64, uint64_t)
HANDLE_TYPE(FLOAT32, Float32, float)
HANDLE_TYPE(FLOAT64, Float64, double)
#undef HANDLE_TYPE
case schema::Type::ENUM: {
uint16_t typedDval = dval.getEnum();
return DynamicEnum(type.asEnum(),
reader.getDataField<uint16_t>(assumeDataOffset(slot.getOffset()), typedDval));
}
case schema::Type::TEXT: {
Text::Reader typedDval = dval.isAnyPointer() ? Text::Reader() : dval.getText();
return reader.getPointerField(assumePointerOffset(slot.getOffset()))
.getBlob<Text>(typedDval.begin(),
assumeMax<MAX_TEXT_SIZE>(typedDval.size()) * BYTES);
}
case schema::Type::DATA: {
Data::Reader typedDval = dval.isAnyPointer() ? Data::Reader() : dval.getData();
return reader.getPointerField(assumePointerOffset(slot.getOffset()))
.getBlob<Data>(typedDval.begin(),
assumeBits<BLOB_SIZE_BITS>(typedDval.size()) * BYTES);
}
case schema::Type::LIST: {
auto elementType = type.asList().getElementType();
return DynamicList::Reader(type.asList(),
reader.getPointerField(assumePointerOffset(slot.getOffset()))
.getList(elementSizeFor(elementType.which()), dval.isAnyPointer() ? nullptr :
dval.getList().getAs<_::UncheckedMessage>()));
}
case schema::Type::STRUCT:
return DynamicStruct::Reader(type.asStruct(),
reader.getPointerField(assumePointerOffset(slot.getOffset()))
.getStruct(dval.isAnyPointer() ? nullptr :
dval.getStruct().getAs<_::UncheckedMessage>()));
case schema::Type::ANY_POINTER:
return AnyPointer::Reader(reader.getPointerField(assumePointerOffset(slot.getOffset())));
case schema::Type::INTERFACE:
return DynamicCapability::Client(type.asInterface(),
reader.getPointerField(assumePointerOffset(slot.getOffset())).getCapability());
}
KJ_UNREACHABLE;
}
case schema::Field::GROUP:
return DynamicStruct::Reader(type.asStruct(), reader);
}
KJ_UNREACHABLE;
}
DynamicValue::Builder DynamicStruct::Builder::get(StructSchema::Field field) {
KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
verifySetInUnion(field);
auto proto = field.getProto();
auto type = field.getType();
switch (proto.which()) {
case schema::Field::SLOT: {
auto slot = proto.getSlot();
// Note that the default value might be "anyPointer" even if the type is some pointer type
// *other than* anyPointer. This happens with generics -- the field is actually a generic
// parameter that has been bound, but the default value was of course compiled without any
// binding available.
auto dval = slot.getDefaultValue();
switch (type.which()) {
case schema::Type::VOID:
return builder.getDataField<Void>(assumeDataOffset(slot.getOffset()));
#define HANDLE_TYPE(discrim, titleCase, type) \
case schema::Type::discrim: \
return builder.getDataField<type>( \
assumeDataOffset(slot.getOffset()), \
bitCast<_::Mask<type>>(dval.get##titleCase()));
HANDLE_TYPE(BOOL, Bool, bool)
HANDLE_TYPE(INT8, Int8, int8_t)
HANDLE_TYPE(INT16, Int16, int16_t)
HANDLE_TYPE(INT32, Int32, int32_t)
HANDLE_TYPE(INT64, Int64, int64_t)
HANDLE_TYPE(UINT8, Uint8, uint8_t)
HANDLE_TYPE(UINT16, Uint16, uint16_t)
HANDLE_TYPE(UINT32, Uint32, uint32_t)
HANDLE_TYPE(UINT64, Uint64, uint64_t)
HANDLE_TYPE(FLOAT32, Float32, float)
HANDLE_TYPE(FLOAT64, Float64, double)
#undef HANDLE_TYPE
case schema::Type::ENUM: {
uint16_t typedDval = dval.getEnum();
return DynamicEnum(type.asEnum(),
builder.getDataField<uint16_t>(assumeDataOffset(slot.getOffset()), typedDval));
}
case schema::Type::TEXT: {
Text::Reader typedDval = dval.isAnyPointer() ? Text::Reader() : dval.getText();
return builder.getPointerField(assumePointerOffset(slot.getOffset()))
.getBlob<Text>(typedDval.begin(),
assumeMax<MAX_TEXT_SIZE>(typedDval.size()) * BYTES);
}
case schema::Type::DATA: {
Data::Reader typedDval = dval.isAnyPointer() ? Data::Reader() : dval.getData();
return builder.getPointerField(assumePointerOffset(slot.getOffset()))
.getBlob<Data>(typedDval.begin(),
assumeBits<BLOB_SIZE_BITS>(typedDval.size()) * BYTES);
}
case schema::Type::LIST: {
ListSchema listType = type.asList();
if (listType.whichElementType() == schema::Type::STRUCT) {
return DynamicList::Builder(listType,
builder.getPointerField(assumePointerOffset(slot.getOffset()))
.getStructList(structSizeFromSchema(listType.getStructElementType()),
dval.isAnyPointer() ? nullptr :
dval.getList().getAs<_::UncheckedMessage>()));
} else {
return DynamicList::Builder(listType,
builder.getPointerField(assumePointerOffset(slot.getOffset()))
.getList(elementSizeFor(listType.whichElementType()),
dval.isAnyPointer() ? nullptr :
dval.getList().getAs<_::UncheckedMessage>()));
}
}
case schema::Type::STRUCT: {
auto structSchema = type.asStruct();
return DynamicStruct::Builder(structSchema,
builder.getPointerField(assumePointerOffset(slot.getOffset()))
.getStruct(structSizeFromSchema(structSchema),
dval.isAnyPointer() ? nullptr :
dval.getStruct().getAs<_::UncheckedMessage>()));
}
case schema::Type::ANY_POINTER:
return AnyPointer::Builder(
builder.getPointerField(assumePointerOffset(slot.getOffset())));
case schema::Type::INTERFACE:
return DynamicCapability::Client(type.asInterface(),
builder.getPointerField(assumePointerOffset(slot.getOffset())).getCapability());
}
KJ_UNREACHABLE;
}
case schema::Field::GROUP:
return DynamicStruct::Builder(type.asStruct(), builder);
}
KJ_UNREACHABLE;
}
DynamicValue::Pipeline DynamicStruct::Pipeline::get(StructSchema::Field field) {
KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
auto proto = field.getProto();
KJ_REQUIRE(!hasDiscriminantValue(proto), "Can't pipeline on union members.");
auto type = field.getType();
switch (proto.which()) {
case schema::Field::SLOT: {
auto slot = proto.getSlot();
switch (type.which()) {
case schema::Type::STRUCT:
return DynamicStruct::Pipeline(type.asStruct(),
typeless.getPointerField(slot.getOffset()));
case schema::Type::INTERFACE:
return DynamicCapability::Client(type.asInterface(),
typeless.getPointerField(slot.getOffset()).asCap());
case schema::Type::ANY_POINTER:
switch (type.whichAnyPointerKind()) {
case schema::Type::AnyPointer::Unconstrained::STRUCT:
return DynamicStruct::Pipeline(StructSchema(),
typeless.getPointerField(slot.getOffset()));
case schema::Type::AnyPointer::Unconstrained::CAPABILITY:
return DynamicCapability::Client(Capability::Client(
typeless.getPointerField(slot.getOffset()).asCap()));
default:
KJ_FAIL_REQUIRE("Can only pipeline on struct and interface fields.");
}
default:
KJ_FAIL_REQUIRE("Can only pipeline on struct and interface fields.");
}
KJ_UNREACHABLE;
}
case schema::Field::GROUP:
return DynamicStruct::Pipeline(type.asStruct(), typeless.noop());
}
KJ_UNREACHABLE;
}
bool DynamicStruct::Reader::has(StructSchema::Field field, HasMode mode) const {
KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
auto proto = field.getProto();
if (hasDiscriminantValue(proto)) {
uint16_t discrim = reader.getDataField<uint16_t>(
assumeDataOffset(schema.getProto().getStruct().getDiscriminantOffset()));
if (discrim != proto.getDiscriminantValue()) {
// Field is not active in the union.
return false;
}
}
switch (proto.which()) {
case schema::Field::SLOT:
// Continue to below.
break;
case schema::Field::GROUP:
return true;
}
auto slot = proto.getSlot();
auto type = field.getType();
switch (type.which()) {
case schema::Type::VOID:
// Void is always equal to the default.
return mode == HasMode::NON_NULL;
case schema::Type::BOOL:
return mode == HasMode::NON_NULL ||
reader.getDataField<bool>(assumeDataOffset(slot.getOffset()), 0) != 0;
case schema::Type::INT8:
case schema::Type::UINT8:
return mode == HasMode::NON_NULL ||
reader.getDataField<uint8_t>(assumeDataOffset(slot.getOffset()), 0) != 0;
case schema::Type::INT16:
case schema::Type::UINT16:
case schema::Type::ENUM:
return mode == HasMode::NON_NULL ||
reader.getDataField<uint16_t>(assumeDataOffset(slot.getOffset()), 0) != 0;
case schema::Type::INT32:
case schema::Type::UINT32:
case schema::Type::FLOAT32:
return mode == HasMode::NON_NULL ||
reader.getDataField<uint32_t>(assumeDataOffset(slot.getOffset()), 0) != 0;
case schema::Type::INT64:
case schema::Type::UINT64:
case schema::Type::FLOAT64:
return mode == HasMode::NON_NULL ||
reader.getDataField<uint64_t>(assumeDataOffset(slot.getOffset()), 0) != 0;
case schema::Type::TEXT:
case schema::Type::DATA:
case schema::Type::LIST:
case schema::Type::STRUCT:
case schema::Type::ANY_POINTER:
case schema::Type::INTERFACE:
return !reader.getPointerField(assumePointerOffset(slot.getOffset())).isNull();
}
// Unknown type. As far as we know, it isn't set.
return false;
}
kj::Maybe<StructSchema::Field> DynamicStruct::Reader::which() const {
auto structProto = schema.getProto().getStruct();
if (structProto.getDiscriminantCount() == 0) {
return nullptr;
}
uint16_t discrim = reader.getDataField<uint16_t>(
assumeDataOffset(structProto.getDiscriminantOffset()));
return schema.getFieldByDiscriminant(discrim);
}
kj::Maybe<StructSchema::Field> DynamicStruct::Builder::which() {
auto structProto = schema.getProto().getStruct();
if (structProto.getDiscriminantCount() == 0) {
return nullptr;
}
uint16_t discrim = builder.getDataField<uint16_t>(
assumeDataOffset(structProto.getDiscriminantOffset()));
return schema.getFieldByDiscriminant(discrim);
}
void DynamicStruct::Builder::set(StructSchema::Field field, const DynamicValue::Reader& value) {
KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
setInUnion(field);
auto proto = field.getProto();
auto type = field.getType();
switch (proto.which()) {
case schema::Field::SLOT: {
auto slot = proto.getSlot();
auto dval = slot.getDefaultValue();
switch (type.which()) {
case schema::Type::VOID:
builder.setDataField<Void>(assumeDataOffset(slot.getOffset()), value.as<Void>());
return;
#define HANDLE_TYPE(discrim, titleCase, type) \
case schema::Type::discrim: \
builder.setDataField<type>( \
assumeDataOffset(slot.getOffset()), value.as<type>(), \
bitCast<_::Mask<type> >(dval.get##titleCase())); \
return;
HANDLE_TYPE(BOOL, Bool, bool)
HANDLE_TYPE(INT8, Int8, int8_t)
HANDLE_TYPE(INT16, Int16, int16_t)
HANDLE_TYPE(INT32, Int32, int32_t)
HANDLE_TYPE(INT64, Int64, int64_t)
HANDLE_TYPE(UINT8, Uint8, uint8_t)
HANDLE_TYPE(UINT16, Uint16, uint16_t)
HANDLE_TYPE(UINT32, Uint32, uint32_t)
HANDLE_TYPE(UINT64, Uint64, uint64_t)
HANDLE_TYPE(FLOAT32, Float32, float)
HANDLE_TYPE(FLOAT64, Float64, double)
#undef HANDLE_TYPE
case schema::Type::ENUM: {
uint16_t rawValue;
auto enumSchema = type.asEnum();
if (value.getType() == DynamicValue::TEXT) {
// Convert from text.
rawValue = enumSchema.getEnumerantByName(value.as<Text>()).getOrdinal();
} else if (value.getType() == DynamicValue::INT ||
value.getType() == DynamicValue::UINT) {
rawValue = value.as<uint16_t>();
} else {
DynamicEnum enumValue = value.as<DynamicEnum>();
KJ_REQUIRE(enumValue.getSchema() == enumSchema, "Value type mismatch.") {
return;
}
rawValue = enumValue.getRaw();
}
builder.setDataField<uint16_t>(assumeDataOffset(slot.getOffset()), rawValue,
dval.getEnum());
return;
}
case schema::Type::TEXT:
builder.getPointerField(assumePointerOffset(slot.getOffset()))
.setBlob<Text>(value.as<Text>());
return;
case schema::Type::DATA:
builder.getPointerField(assumePointerOffset(slot.getOffset()))
.setBlob<Data>(value.as<Data>());
return;
case schema::Type::LIST: {
ListSchema listType = type.asList();
auto listValue = value.as<DynamicList>();
KJ_REQUIRE(listValue.getSchema() == listType, "Value type mismatch.") {
return;
}
builder.getPointerField(assumePointerOffset(slot.getOffset()))
.setList(listValue.reader);
return;
}
case schema::Type::STRUCT: {
auto structType = type.asStruct();
auto structValue = value.as<DynamicStruct>();
KJ_REQUIRE(structValue.getSchema() == structType, "Value type mismatch.") {
return;
}
builder.getPointerField(assumePointerOffset(slot.getOffset()))
.setStruct(structValue.reader);
return;
}
case schema::Type::ANY_POINTER: {
auto target = AnyPointer::Builder(
builder.getPointerField(assumePointerOffset(slot.getOffset())));
switch (value.getType()) {
case DynamicValue::Type::TEXT:
target.setAs<Text>(value.as<Text>());
return;
case DynamicValue::Type::DATA:
target.setAs<Data>(value.as<Data>());
return;
case DynamicValue::Type::LIST:
target.setAs<DynamicList>(value.as<DynamicList>());
return;
case DynamicValue::Type::STRUCT:
target.setAs<DynamicStruct>(value.as<DynamicStruct>());
return;
case DynamicValue::Type::CAPABILITY:
target.setAs<DynamicCapability>(value.as<DynamicCapability>());
return;
case DynamicValue::Type::ANY_POINTER:
target.set(value.as<AnyPointer>());
return;
case DynamicValue::Type::UNKNOWN:
case DynamicValue::Type::VOID:
case DynamicValue::Type::BOOL:
case DynamicValue::Type::INT:
case DynamicValue::Type::UINT:
case DynamicValue::Type::FLOAT:
case DynamicValue::Type::ENUM:
KJ_FAIL_ASSERT("Value type mismatch; expected AnyPointer");
}
KJ_UNREACHABLE;
}
case schema::Type::INTERFACE: {
auto interfaceType = type.asInterface();
auto capability = value.as<DynamicCapability>();
KJ_REQUIRE(capability.getSchema().extends(interfaceType), "Value type mismatch.") {
return;
}
builder.getPointerField(assumePointerOffset(slot.getOffset()))
.setCapability(kj::mv(capability.hook));
return;
}
}
KJ_UNREACHABLE;
}
case schema::Field::GROUP: {
auto src = value.as<DynamicStruct>();
auto dst = init(field).as<DynamicStruct>();
KJ_IF_MAYBE(unionField, src.which()) {
dst.set(*unionField, src.get(*unionField));
}
for (auto field: src.schema.getNonUnionFields()) {
if (src.has(field)) {
dst.set(field, src.get(field));
}
}
}
}
KJ_UNREACHABLE;
}
DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Field field) {
KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
setInUnion(field);
auto proto = field.getProto();
auto type = field.getType();
switch (proto.which()) {
case schema::Field::SLOT: {
auto slot = proto.getSlot();
switch (type.which()) {
case schema::Type::STRUCT: {
auto subSchema = type.asStruct();
return DynamicStruct::Builder(subSchema,
builder.getPointerField(assumePointerOffset(slot.getOffset()))
.initStruct(structSizeFromSchema(subSchema)));
}
case schema::Type::ANY_POINTER: {
auto pointer = builder.getPointerField(assumePointerOffset(slot.getOffset()));
pointer.clear();
return AnyPointer::Builder(pointer);
}
default:
KJ_FAIL_REQUIRE("init() without a size is only valid for struct and object fields.");
}
}
case schema::Field::GROUP: {
clear(field);
return DynamicStruct::Builder(type.asStruct(), builder);
}
}
KJ_UNREACHABLE;
}
DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Field field, uint size) {
KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
setInUnion(field);
auto proto = field.getProto();
auto type = field.getType();
switch (proto.which()) {
case schema::Field::SLOT: {
auto slot = proto.getSlot();
switch (type.which()) {
case schema::Type::LIST: {
auto listType = type.asList();
if (listType.whichElementType() == schema::Type::STRUCT) {
return DynamicList::Builder(listType,
builder.getPointerField(assumePointerOffset(slot.getOffset()))
.initStructList(bounded(size) * ELEMENTS,
structSizeFromSchema(listType.getStructElementType())));
} else {
return DynamicList::Builder(listType,
builder.getPointerField(assumePointerOffset(slot.getOffset()))
.initList(elementSizeFor(listType.whichElementType()),
bounded(size) * ELEMENTS));
}
}
case schema::Type::TEXT:
return builder.getPointerField(assumePointerOffset(slot.getOffset()))
.initBlob<Text>(bounded(size) * BYTES);
case schema::Type::DATA:
return builder.getPointerField(assumePointerOffset(slot.getOffset()))
.initBlob<Data>(bounded(size) * BYTES);
default:
KJ_FAIL_REQUIRE(
"init() with size is only valid for list, text, or data fields.",
(uint)type.which());
break;
}
KJ_UNREACHABLE;
}
case schema::Field::GROUP:
KJ_FAIL_REQUIRE("init() with size is only valid for list, text, or data fields.");
}
KJ_UNREACHABLE;
}
void DynamicStruct::Builder::adopt(StructSchema::Field field, Orphan<DynamicValue>&& orphan) {
KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
setInUnion(field);
auto proto = field.getProto();
switch (proto.which()) {
case schema::Field::SLOT: {
auto slot = proto.getSlot();
auto type = field.getType();
switch (type.which()) {
case schema::Type::VOID:
case schema::Type::BOOL:
case schema::Type::INT8:
case schema::Type::INT16:
case schema::Type::INT32:
case schema::Type::INT64:
case schema::Type::UINT8:
case schema::Type::UINT16:
case schema::Type::UINT32:
case schema::Type::UINT64:
case schema::Type::FLOAT32:
case schema::Type::FLOAT64:
case schema::Type::ENUM:
set(field, orphan.getReader());
return;
case schema::Type::TEXT:
KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch.");
break;
case schema::Type::DATA:
KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
break;
case schema::Type::LIST: {
ListSchema listType = type.asList();
KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == listType,
"Value type mismatch.") {
return;
}
break;
}
case schema::Type::STRUCT: {
auto structType = type.asStruct();
KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == structType,
"Value type mismatch.") {
return;
}
break;
}
case schema::Type::ANY_POINTER:
KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT ||
orphan.getType() == DynamicValue::LIST ||
orphan.getType() == DynamicValue::TEXT ||
orphan.getType() == DynamicValue::DATA ||
orphan.getType() == DynamicValue::CAPABILITY ||
orphan.getType() == DynamicValue::ANY_POINTER,
"Value type mismatch.") {
return;
}
break;
case schema::Type::INTERFACE: {
auto interfaceType = type.asInterface();
KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY &&
orphan.interfaceSchema.extends(interfaceType),
"Value type mismatch.") {
return;
}
break;
}
}
builder.getPointerField(assumePointerOffset(slot.getOffset())).adopt(kj::mv(orphan.builder));
return;
}
case schema::Field::GROUP:
// Have to transfer fields.
auto src = orphan.get().as<DynamicStruct>();
auto dst = init(field).as<DynamicStruct>();
KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == dst.getSchema(),
"Value type mismatch.");
KJ_IF_MAYBE(unionField, src.which()) {
dst.adopt(*unionField, src.disown(*unionField));
}
for (auto field: src.schema.getNonUnionFields()) {
if (src.has(field)) {
dst.adopt(field, src.disown(field));
}
}
return;
}
KJ_UNREACHABLE;
}
Orphan<DynamicValue> DynamicStruct::Builder::disown(StructSchema::Field field) {
// We end up calling get(field) below, so we don't need to validate `field` here.
auto proto = field.getProto();
switch (proto.which()) {
case schema::Field::SLOT: {
auto slot = proto.getSlot();
switch (field.getType().which()) {
case schema::Type::VOID:
case schema::Type::BOOL:
case schema::Type::INT8:
case schema::Type::INT16:
case schema::Type::INT32:
case schema::Type::INT64:
case schema::Type::UINT8:
case schema::Type::UINT16:
case schema::Type::UINT32:
case schema::Type::UINT64:
case schema::Type::FLOAT32:
case schema::Type::FLOAT64:
case schema::Type::ENUM: {
auto result = Orphan<DynamicValue>(get(field), _::OrphanBuilder());
clear(field);
return kj::mv(result);
}
case schema::Type::TEXT:
case schema::Type::DATA:
case schema::Type::LIST:
case schema::Type::STRUCT:
case schema::Type::ANY_POINTER:
case schema::Type::INTERFACE: {
auto value = get(field);
return Orphan<DynamicValue>(
value, builder.getPointerField(assumePointerOffset(slot.getOffset())).disown());
}
}
KJ_UNREACHABLE;
}
case schema::Field::GROUP: {
// We have to allocate new space for the group, unfortunately.
auto src = get(field).as<DynamicStruct>();
Orphan<DynamicStruct> result =
Orphanage::getForMessageContaining(*this).newOrphan(src.getSchema());
auto dst = result.get();
KJ_IF_MAYBE(unionField, src.which()) {
dst.adopt(*unionField, src.disown(*unionField));
}
// We need to explicitly reset the union to its default field.
KJ_IF_MAYBE(unionField, src.schema.getFieldByDiscriminant(0)) {
src.clear(*unionField);
}
for (auto field: src.schema.getNonUnionFields()) {
if (src.has(field)) {
dst.adopt(field, src.disown(field));
}
}
return kj::mv(result);
}
}
KJ_UNREACHABLE;
}
void DynamicStruct::Builder::clear(StructSchema::Field field) {
KJ_REQUIRE(field.getContainingStruct() == schema, "`field` is not a field of this struct.");
setInUnion(field);
auto proto = field.getProto();
auto type = field.getType();
switch (proto.which()) {
case schema::Field::SLOT: {
auto slot = proto.getSlot();
switch (type.which()) {
case schema::Type::VOID:
builder.setDataField<Void>(assumeDataOffset(slot.getOffset()), VOID);
return;
#define HANDLE_TYPE(discrim, type) \
case schema::Type::discrim: \
builder.setDataField<type>(assumeDataOffset(slot.getOffset()), 0); \
return;
HANDLE_TYPE(BOOL, bool)
HANDLE_TYPE(INT8, uint8_t)
HANDLE_TYPE(INT16, uint16_t)
HANDLE_TYPE(INT32, uint32_t)
HANDLE_TYPE(INT64, uint64_t)
HANDLE_TYPE(UINT8, uint8_t)
HANDLE_TYPE(UINT16, uint16_t)
HANDLE_TYPE(UINT32, uint32_t)
HANDLE_TYPE(UINT64, uint64_t)
HANDLE_TYPE(FLOAT32, uint32_t)
HANDLE_TYPE(FLOAT64, uint64_t)
HANDLE_TYPE(ENUM, uint16_t)
#undef HANDLE_TYPE
case schema::Type::TEXT:
case schema::Type::DATA:
case schema::Type::LIST:
case schema::Type::STRUCT:
case schema::Type::ANY_POINTER:
case schema::Type::INTERFACE:
builder.getPointerField(assumePointerOffset(slot.getOffset())).clear();
return;
}
KJ_UNREACHABLE;
}
case schema::Field::GROUP: {
DynamicStruct::Builder group(type.asStruct(), builder);
// We clear the union field with discriminant 0 rather than the one that is set because
// we want the union to end up with its default field active.
KJ_IF_MAYBE(unionField, group.schema.getFieldByDiscriminant(0)) {
group.clear(*unionField);
}
for (auto subField: group.schema.getNonUnionFields()) {
group.clear(subField);
}
return;
}
}
KJ_UNREACHABLE;
}
DynamicValue::Reader DynamicStruct::Reader::get(kj::StringPtr name) const {
return get(schema.getFieldByName(name));
}
DynamicValue::Builder DynamicStruct::Builder::get(kj::StringPtr name) {
return get(schema.getFieldByName(name));
}
DynamicValue::Pipeline DynamicStruct::Pipeline::get(kj::StringPtr name) {
return get(schema.getFieldByName(name));
}
bool DynamicStruct::Reader::has(kj::StringPtr name, HasMode mode) const {
return has(schema.getFieldByName(name), mode);
}
bool DynamicStruct::Builder::has(kj::StringPtr name, HasMode mode) {
return has(schema.getFieldByName(name), mode);
}
void DynamicStruct::Builder::set(kj::StringPtr name, const DynamicValue::Reader& value) {
set(schema.getFieldByName(name), value);
}
void DynamicStruct::Builder::set(kj::StringPtr name,
std::initializer_list<DynamicValue::Reader> value) {
auto list = init(name, value.size()).as<DynamicList>();
uint i = 0;
for (auto element: value) {
list.set(i++, element);
}
}
DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name) {
return init(schema.getFieldByName(name));
}
DynamicValue::Builder DynamicStruct::Builder::init(kj::StringPtr name, uint size) {
return init(schema.getFieldByName(name), size);
}
void DynamicStruct::Builder::adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan) {
adopt(schema.getFieldByName(name), kj::mv(orphan));
}
Orphan<DynamicValue> DynamicStruct::Builder::disown(kj::StringPtr name) {
return disown(schema.getFieldByName(name));
}
void DynamicStruct::Builder::clear(kj::StringPtr name) {
clear(schema.getFieldByName(name));
}
// =======================================================================================
DynamicValue::Reader DynamicList::Reader::operator[](uint index) const {
KJ_REQUIRE(index < size(), "List index out-of-bounds.");
switch (schema.whichElementType()) {
#define HANDLE_TYPE(name, discrim, typeName) \
case schema::Type::discrim: \
return reader.getDataElement<typeName>(bounded(index) * ELEMENTS);
HANDLE_TYPE(void, VOID, Void)
HANDLE_TYPE(bool, BOOL, bool)
HANDLE_TYPE(int8, INT8, int8_t)
HANDLE_TYPE(int16, INT16, int16_t)
HANDLE_TYPE(int32, INT32, int32_t)
HANDLE_TYPE(int64, INT64, int64_t)
HANDLE_TYPE(uint8, UINT8, uint8_t)
HANDLE_TYPE(uint16, UINT16, uint16_t)
HANDLE_TYPE(uint32, UINT32, uint32_t)
HANDLE_TYPE(uint64, UINT64, uint64_t)
HANDLE_TYPE(float32, FLOAT32, float)
HANDLE_TYPE(float64, FLOAT64, double)
#undef HANDLE_TYPE
case schema::Type::TEXT:
return reader.getPointerElement(bounded(index) * ELEMENTS)
.getBlob<Text>(nullptr, ZERO * BYTES);
case schema::Type::DATA:
return reader.getPointerElement(bounded(index) * ELEMENTS)
.getBlob<Data>(nullptr, ZERO * BYTES);
case schema::Type::LIST: {
auto elementType = schema.getListElementType();
return DynamicList::Reader(elementType,
reader.getPointerElement(bounded(index) * ELEMENTS)
.getList(elementSizeFor(elementType.whichElementType()), nullptr));
}
case schema::Type::STRUCT:
return DynamicStruct::Reader(schema.getStructElementType(),
reader.getStructElement(bounded(index) * ELEMENTS));
case schema::Type::ENUM:
return DynamicEnum(schema.getEnumElementType(),
reader.getDataElement<uint16_t>(bounded(index) * ELEMENTS));
case schema::Type::ANY_POINTER:
return AnyPointer::Reader(reader.getPointerElement(bounded(index) * ELEMENTS));
case schema::Type::INTERFACE:
return DynamicCapability::Client(schema.getInterfaceElementType(),
reader.getPointerElement(bounded(index) * ELEMENTS)
.getCapability());
}
return nullptr;
}
DynamicValue::Builder DynamicList::Builder::operator[](uint index) {
KJ_REQUIRE(index < size(), "List index out-of-bounds.");
switch (schema.whichElementType()) {
#define HANDLE_TYPE(name, discrim, typeName) \
case schema::Type::discrim: \
return builder.getDataElement<typeName>(bounded(index) * ELEMENTS);
HANDLE_TYPE(void, VOID, Void)
HANDLE_TYPE(bool, BOOL, bool)
HANDLE_TYPE(int8, INT8, int8_t)
HANDLE_TYPE(int16, INT16, int16_t)
HANDLE_TYPE(int32, INT32, int32_t)
HANDLE_TYPE(int64, INT64, int64_t)
HANDLE_TYPE(uint8, UINT8, uint8_t)
HANDLE_TYPE(uint16, UINT16, uint16_t)
HANDLE_TYPE(uint32, UINT32, uint32_t)
HANDLE_TYPE(uint64, UINT64, uint64_t)
HANDLE_TYPE(float32, FLOAT32, float)
HANDLE_TYPE(float64, FLOAT64, double)
#undef HANDLE_TYPE
case schema::Type::TEXT:
return builder.getPointerElement(bounded(index) * ELEMENTS)
.getBlob<Text>(nullptr, ZERO * BYTES);
case schema::Type::DATA:
return builder.getPointerElement(bounded(index) * ELEMENTS)
.getBlob<Data>(nullptr, ZERO * BYTES);
case schema::Type::LIST: {
ListSchema elementType = schema.getListElementType();
if (elementType.whichElementType() == schema::Type::STRUCT) {
return DynamicList::Builder(elementType,
builder.getPointerElement(bounded(index) * ELEMENTS)
.getStructList(structSizeFromSchema(elementType.getStructElementType()),
nullptr));
} else {
return DynamicList::Builder(elementType,
builder.getPointerElement(bounded(index) * ELEMENTS)
.getList(elementSizeFor(elementType.whichElementType()), nullptr));
}
}
case schema::Type::STRUCT:
return DynamicStruct::Builder(schema.getStructElementType(),
builder.getStructElement(bounded(index) * ELEMENTS));
case schema::Type::ENUM:
return DynamicEnum(schema.getEnumElementType(),
builder.getDataElement<uint16_t>(bounded(index) * ELEMENTS));
case schema::Type::ANY_POINTER:
KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
return nullptr;
case schema::Type::INTERFACE:
return DynamicCapability::Client(schema.getInterfaceElementType(),
builder.getPointerElement(bounded(index) * ELEMENTS)
.getCapability());
}
return nullptr;
}
void DynamicList::Builder::set(uint index, const DynamicValue::Reader& value) {
KJ_REQUIRE(index < size(), "List index out-of-bounds.") {
return;
}
switch (schema.whichElementType()) {
#define HANDLE_TYPE(name, discrim, typeName) \
case schema::Type::discrim: \
builder.setDataElement<typeName>(bounded(index) * ELEMENTS, value.as<typeName>()); \
return;
HANDLE_TYPE(void, VOID, Void)
HANDLE_TYPE(bool, BOOL, bool)
HANDLE_TYPE(int8, INT8, int8_t)
HANDLE_TYPE(int16, INT16, int16_t)
HANDLE_TYPE(int32, INT32, int32_t)
HANDLE_TYPE(int64, INT64, int64_t)
HANDLE_TYPE(uint8, UINT8, uint8_t)
HANDLE_TYPE(uint16, UINT16, uint16_t)
HANDLE_TYPE(uint32, UINT32, uint32_t)
HANDLE_TYPE(uint64, UINT64, uint64_t)
HANDLE_TYPE(float32, FLOAT32, float)
HANDLE_TYPE(float64, FLOAT64, double)
#undef HANDLE_TYPE
case schema::Type::TEXT:
builder.getPointerElement(bounded(index) * ELEMENTS).setBlob<Text>(value.as<Text>());
return;
case schema::Type::DATA:
builder.getPointerElement(bounded(index) * ELEMENTS).setBlob<Data>(value.as<Data>());
return;
case schema::Type::LIST: {
auto listValue = value.as<DynamicList>();
KJ_REQUIRE(listValue.getSchema() == schema.getListElementType(), "Value type mismatch.") {
return;
}
builder.getPointerElement(bounded(index) * ELEMENTS).setList(listValue.reader);
return;
}
case schema::Type::STRUCT: {
auto structValue = value.as<DynamicStruct>();
KJ_REQUIRE(structValue.getSchema() == schema.getStructElementType(), "Value type mismatch.") {
return;
}
builder.getStructElement(bounded(index) * ELEMENTS).copyContentFrom(structValue.reader);
return;
}
case schema::Type::ENUM: {
uint16_t rawValue;
if (value.getType() == DynamicValue::TEXT) {
// Convert from text.
rawValue = schema.getEnumElementType().getEnumerantByName(value.as<Text>()).getOrdinal();
} else {
DynamicEnum enumValue = value.as<DynamicEnum>();
KJ_REQUIRE(schema.getEnumElementType() == enumValue.getSchema(),
"Type mismatch when using DynamicList::Builder::set().") {
return;
}
rawValue = enumValue.getRaw();
}
builder.setDataElement<uint16_t>(bounded(index) * ELEMENTS, rawValue);
return;
}
case schema::Type::ANY_POINTER:
KJ_FAIL_ASSERT("List(AnyPointer) not supported.") {
return;
}
case schema::Type::INTERFACE: {
auto capValue = value.as<DynamicCapability>();
KJ_REQUIRE(capValue.getSchema().extends(schema.getInterfaceElementType()),
"Value type mismatch.") {
return;
}
builder.getPointerElement(bounded(index) * ELEMENTS).setCapability(kj::mv(capValue.hook));
return;
}
}
KJ_FAIL_REQUIRE("can't set element of unknown type", (uint)schema.whichElementType()) {
return;
}
}
DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) {
KJ_REQUIRE(index < this->size(), "List index out-of-bounds.");
switch (schema.whichElementType()) {
case schema::Type::VOID:
case schema::Type::BOOL:
case schema::Type::INT8:
case schema::Type::INT16:
case schema::Type::INT32:
case schema::Type::INT64:
case schema::Type::UINT8:
case schema::Type::UINT16:
case schema::Type::UINT32:
case schema::Type::UINT64:
case schema::Type::FLOAT32:
case schema::Type::FLOAT64:
case schema::Type::ENUM:
case schema::Type::STRUCT:
case schema::Type::INTERFACE:
KJ_FAIL_REQUIRE("Expected a list or blob.");
return nullptr;
case schema::Type::TEXT:
return builder.getPointerElement(bounded(index) * ELEMENTS)
.initBlob<Text>(bounded(size) * BYTES);
case schema::Type::DATA:
return builder.getPointerElement(bounded(index) * ELEMENTS)
.initBlob<Data>(bounded(size) * BYTES);
case schema::Type::LIST: {
auto elementType = schema.getListElementType();
if (elementType.whichElementType() == schema::Type::STRUCT) {
return DynamicList::Builder(elementType,
builder.getPointerElement(bounded(index) * ELEMENTS)
.initStructList(bounded(size) * ELEMENTS,
structSizeFromSchema(elementType.getStructElementType())));
} else {
return DynamicList::Builder(elementType,
builder.getPointerElement(bounded(index) * ELEMENTS)
.initList(elementSizeFor(elementType.whichElementType()),
bounded(size) * ELEMENTS));
}
}
case schema::Type::ANY_POINTER: {
KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
return nullptr;
}
}
return nullptr;
}
void DynamicList::Builder::adopt(uint index, Orphan<DynamicValue>&& orphan) {
switch (schema.whichElementType()) {
case schema::Type::VOID:
case schema::Type::BOOL:
case schema::Type::INT8:
case schema::Type::INT16:
case schema::Type::INT32:
case schema::Type::INT64:
case schema::Type::UINT8:
case schema::Type::UINT16:
case schema::Type::UINT32:
case schema::Type::UINT64:
case schema::Type::FLOAT32:
case schema::Type::FLOAT64:
case schema::Type::ENUM:
set(index, orphan.getReader());
return;
case schema::Type::TEXT:
KJ_REQUIRE(orphan.getType() == DynamicValue::TEXT, "Value type mismatch.");
builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
return;
case schema::Type::DATA:
KJ_REQUIRE(orphan.getType() == DynamicValue::DATA, "Value type mismatch.");
builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
return;
case schema::Type::LIST: {
ListSchema elementType = schema.getListElementType();
KJ_REQUIRE(orphan.getType() == DynamicValue::LIST && orphan.listSchema == elementType,
"Value type mismatch.");
builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
return;
}
case schema::Type::STRUCT: {
auto elementType = schema.getStructElementType();
KJ_REQUIRE(orphan.getType() == DynamicValue::STRUCT && orphan.structSchema == elementType,
"Value type mismatch.");
builder.getStructElement(bounded(index) * ELEMENTS).transferContentFrom(
orphan.builder.asStruct(structSizeFromSchema(elementType)));
return;
}
case schema::Type::ANY_POINTER:
KJ_FAIL_ASSERT("List(AnyPointer) not supported.");
case schema::Type::INTERFACE: {
auto elementType = schema.getInterfaceElementType();
KJ_REQUIRE(orphan.getType() == DynamicValue::CAPABILITY &&
orphan.interfaceSchema.extends(elementType),
"Value type mismatch.");
builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(orphan.builder));
return;
}
}
KJ_UNREACHABLE;
}
Orphan<DynamicValue> DynamicList::Builder::disown(uint index) {
switch (schema.whichElementType()) {
case schema::Type::VOID:
case schema::Type::BOOL:
case schema::Type::INT8:
case schema::Type::INT16:
case schema::Type::INT32:
case schema::Type::INT64:
case schema::Type::UINT8:
case schema::Type::UINT16:
case schema::Type::UINT32:
case schema::Type::UINT64:
case schema::Type::FLOAT32:
case schema::Type::FLOAT64:
case schema::Type::ENUM: {
auto result = Orphan<DynamicValue>(operator[](index), _::OrphanBuilder());
switch (elementSizeFor(schema.whichElementType())) {
case ElementSize::VOID: break;
case ElementSize::BIT: builder.setDataElement<bool>(bounded(index) * ELEMENTS, false); break;
case ElementSize::BYTE: builder.setDataElement<uint8_t>(bounded(index) * ELEMENTS, 0); break;
case ElementSize::TWO_BYTES: builder.setDataElement<uint16_t>(bounded(index) * ELEMENTS, 0); break;
case ElementSize::FOUR_BYTES: builder.setDataElement<uint32_t>(bounded(index) * ELEMENTS, 0); break;
case ElementSize::EIGHT_BYTES: builder.setDataElement<uint64_t>(bounded(index) * ELEMENTS, 0);break;
case ElementSize::POINTER:
case ElementSize::INLINE_COMPOSITE:
KJ_UNREACHABLE;
}
return kj::mv(result);
}
case schema::Type::TEXT:
case schema::Type::DATA:
case schema::Type::LIST:
case schema::Type::ANY_POINTER:
case schema::Type::INTERFACE: {
auto value = operator[](index);
return Orphan<DynamicValue>(value, builder.getPointerElement(bounded(index) * ELEMENTS).disown());
}
case schema::Type::STRUCT: {
// We have to make a copy.
Orphan<DynamicStruct> result =
Orphanage::getForMessageContaining(*this).newOrphan(schema.getStructElementType());
auto element = builder.getStructElement(bounded(index) * ELEMENTS);
result.get().builder.transferContentFrom(element);
element.clearAll();
return kj::mv(result);
}
}
KJ_UNREACHABLE;
}
void DynamicList::Builder::copyFrom(std::initializer_list<DynamicValue::Reader> value) {
KJ_REQUIRE(value.size() == size(), "DynamicList::copyFrom() argument had different size.");
uint i = 0;
for (auto element: value) {
set(i++, element);
}
}
DynamicList::Reader DynamicList::Builder::asReader() const {
return DynamicList::Reader(schema, builder.asReader());
}
// =======================================================================================
DynamicValue::Reader::Reader(ConstSchema constant): type(VOID) {
auto type = constant.getType();
auto value = constant.getProto().getConst().getValue();
switch (type.which()) {
case schema::Type::VOID: *this = capnp::VOID; break;
case schema::Type::BOOL: *this = value.getBool(); break;
case schema::Type::INT8: *this = value.getInt8(); break;
case schema::Type::INT16: *this = value.getInt16(); break;
case schema::Type::INT32: *this = value.getInt32(); break;
case schema::Type::INT64: *this = value.getInt64(); break;
case schema::Type::UINT8: *this = value.getUint8(); break;
case schema::Type::UINT16: *this = value.getUint16(); break;
case schema::Type::UINT32: *this = value.getUint32(); break;
case schema::Type::UINT64: *this = value.getUint64(); break;
case schema::Type::FLOAT32: *this = value.getFloat32(); break;
case schema::Type::FLOAT64: *this = value.getFloat64(); break;
case schema::Type::TEXT: *this = value.getText(); break;
case schema::Type::DATA: *this = value.getData(); break;
case schema::Type::ENUM:
*this = DynamicEnum(type.asEnum(), value.getEnum());
break;
case schema::Type::STRUCT:
*this = value.getStruct().getAs<DynamicStruct>(type.asStruct());
break;
case schema::Type::LIST:
*this = value.getList().getAs<DynamicList>(type.asList());
break;
case schema::Type::ANY_POINTER:
*this = value.getAnyPointer();
break;
case schema::Type::INTERFACE:
KJ_FAIL_ASSERT("Constants can't have interface type.");
}
}
#if __GNUC__ && !__clang__ && __GNUC__ >= 9
// In the copy constructors below, we use memcpy() to copy only after verifying that it is safe.
// But GCC 9 doesn't know we've checked, and whines. I suppose GCC is probably right: our checks
// probably don't technically make memcpy safe according to the standard. But it works in practice,
// and if it ever stops working, the tests will catch it.
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
DynamicValue::Reader::Reader(const Reader& other) {
switch (other.type) {
case UNKNOWN:
case VOID:
case BOOL:
case INT:
case UINT:
case FLOAT:
case TEXT:
case DATA:
case LIST:
case ENUM:
case STRUCT:
case ANY_POINTER:
KJ_ASSERT_CAN_MEMCPY(Text::Reader);
KJ_ASSERT_CAN_MEMCPY(Data::Reader);
KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader);
KJ_ASSERT_CAN_MEMCPY(DynamicEnum);
KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader);
KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader);
break;
case CAPABILITY:
type = CAPABILITY;
kj::ctor(capabilityValue, other.capabilityValue);
return;
}
memcpy(this, &other, sizeof(*this));
}
DynamicValue::Reader::Reader(Reader&& other) noexcept {
switch (other.type) {
case UNKNOWN:
case VOID:
case BOOL:
case INT:
case UINT:
case FLOAT:
case TEXT:
case DATA:
case LIST:
case ENUM:
case STRUCT:
case ANY_POINTER:
KJ_ASSERT_CAN_MEMCPY(Text::Reader);
KJ_ASSERT_CAN_MEMCPY(Data::Reader);
KJ_ASSERT_CAN_MEMCPY(DynamicList::Reader);
KJ_ASSERT_CAN_MEMCPY(DynamicEnum);
KJ_ASSERT_CAN_MEMCPY(DynamicStruct::Reader);
KJ_ASSERT_CAN_MEMCPY(AnyPointer::Reader);
break;
case CAPABILITY:
type = CAPABILITY;
kj::ctor(capabilityValue, kj::mv(other.capabilityValue));
return;
}
memcpy(this, &other, sizeof(*this));
}
DynamicValue::Reader::~Reader() noexcept(false) {
if (type == CAPABILITY) {
kj::dtor(capabilityValue);
}
}
DynamicValue::Reader& DynamicValue::Reader::operator=(const Reader& other) {
if (type == CAPABILITY) {
kj::dtor(capabilityValue);
}
kj::ctor(*this, other);
return *this;
}
DynamicValue::Reader& DynamicValue::Reader::operator=(Reader&& other) {
if (type == CAPABILITY) {
kj::dtor(capabilityValue);
}
kj::ctor(*this, kj::mv(other));
return *this;
}
DynamicValue::Builder::Builder(Builder& other) {
switch (other.type) {
case UNKNOWN:
case VOID:
case BOOL:
case INT:
case UINT:
case FLOAT:
case TEXT:
case DATA:
case LIST:
case ENUM:
case STRUCT:
case ANY_POINTER:
// Unfortunately canMemcpy() doesn't work on these types due to the use of
// DisallowConstCopy, but __has_trivial_destructor should detect if any of these types
// become non-trivial.
static_assert(__has_trivial_destructor(Text::Builder) &&
__has_trivial_destructor(Data::Builder) &&
__has_trivial_destructor(DynamicList::Builder) &&
__has_trivial_destructor(DynamicEnum) &&
__has_trivial_destructor(DynamicStruct::Builder) &&
__has_trivial_destructor(AnyPointer::Builder),
"Assumptions here don't hold.");
break;
case CAPABILITY:
type = CAPABILITY;
kj::ctor(capabilityValue, other.capabilityValue);
return;
}
memcpy(this, &other, sizeof(*this));
}
DynamicValue::Builder::Builder(Builder&& other) noexcept {
switch (other.type) {
case UNKNOWN:
case VOID:
case BOOL:
case INT:
case UINT:
case FLOAT:
case TEXT:
case DATA:
case LIST:
case ENUM:
case STRUCT:
case ANY_POINTER:
// Unfortunately __has_trivial_copy doesn't work on these types due to the use of
// DisallowConstCopy, but __has_trivial_destructor should detect if any of these types
// become non-trivial.
static_assert(__has_trivial_destructor(Text::Builder) &&
__has_trivial_destructor(Data::Builder) &&
__has_trivial_destructor(DynamicList::Builder) &&
__has_trivial_destructor(DynamicEnum) &&
__has_trivial_destructor(DynamicStruct::Builder) &&
__has_trivial_destructor(AnyPointer::Builder),
"Assumptions here don't hold.");
break;
case CAPABILITY:
type = CAPABILITY;
kj::ctor(capabilityValue, kj::mv(other.capabilityValue));
return;
}
memcpy(this, &other, sizeof(*this));
}
DynamicValue::Builder::~Builder() noexcept(false) {
if (type == CAPABILITY) {
kj::dtor(capabilityValue);
}
}
DynamicValue::Builder& DynamicValue::Builder::operator=(Builder& other) {
if (type == CAPABILITY) {
kj::dtor(capabilityValue);
}
kj::ctor(*this, other);
return *this;
}
DynamicValue::Builder& DynamicValue::Builder::operator=(Builder&& other) {
if (type == CAPABILITY) {
kj::dtor(capabilityValue);
}
kj::ctor(*this, kj::mv(other));
return *this;
}
DynamicValue::Reader DynamicValue::Builder::asReader() const {
switch (type) {
case UNKNOWN: return Reader();
case VOID: return Reader(voidValue);
case BOOL: return Reader(boolValue);
case INT: return Reader(intValue);
case UINT: return Reader(uintValue);
case FLOAT: return Reader(floatValue);
case TEXT: return Reader(textValue.asReader());
case DATA: return Reader(dataValue.asReader());
case LIST: return Reader(listValue.asReader());
case ENUM: return Reader(enumValue);
case STRUCT: return Reader(structValue.asReader());
case CAPABILITY: return Reader(capabilityValue);
case ANY_POINTER: return Reader(anyPointerValue.asReader());
}
KJ_FAIL_ASSERT("Missing switch case.");
return Reader();
}
DynamicValue::Pipeline::Pipeline(Pipeline&& other) noexcept: type(other.type) {
switch (type) {
case UNKNOWN: break;
case STRUCT: kj::ctor(structValue, kj::mv(other.structValue)); break;
case CAPABILITY: kj::ctor(capabilityValue, kj::mv(other.capabilityValue)); break;
default:
KJ_LOG(ERROR, "Unexpected pipeline type.", (uint)type);
type = UNKNOWN;
break;
}
}
DynamicValue::Pipeline& DynamicValue::Pipeline::operator=(Pipeline&& other) {
kj::dtor(*this);
kj::ctor(*this, kj::mv(other));
return *this;
}
DynamicValue::Pipeline::~Pipeline() noexcept(false) {
switch (type) {
case UNKNOWN: break;
case STRUCT: kj::dtor(structValue); break;
case CAPABILITY: kj::dtor(capabilityValue); break;
default:
KJ_FAIL_ASSERT("Unexpected pipeline type.", (uint)type) { type = UNKNOWN; break; }
break;
}
}
namespace {
template <typename T>
T signedToUnsigned(long long value) {
KJ_REQUIRE(value >= 0 && T(value) == value, "Value out-of-range for requested type.", value) {
// Use it anyway.
break;
}
return value;
}
template <>
uint64_t signedToUnsigned<uint64_t>(long long value) {
KJ_REQUIRE(value >= 0, "Value out-of-range for requested type.", value) {
// Use it anyway.
break;
}
return value;
}
template <typename T>
T unsignedToSigned(unsigned long long value) {
KJ_REQUIRE(T(value) >= 0 && (unsigned long long)T(value) == value,
"Value out-of-range for requested type.", value) {
// Use it anyway.
break;
}
return value;
}
template <>
int64_t unsignedToSigned<int64_t>(unsigned long long value) {
KJ_REQUIRE(int64_t(value) >= 0, "Value out-of-range for requested type.", value) {
// Use it anyway.
break;
}
return value;
}
template <typename T, typename U>
T checkRoundTrip(U value) {
T result = value;
KJ_REQUIRE(U(result) == value, "Value out-of-range for requested type.", value) {
// Use it anyway.
break;
}
return result;
}
template <typename T, typename U>
T checkRoundTripFromFloat(U value) {
// When `U` is `float` or `double`, we have to use a different approach, because casting an
// out-of-range float to an integer is, surprisingly, UB.
constexpr T MIN = kj::minValue;
constexpr T MAX = kj::maxValue;
KJ_REQUIRE(value >= U(MIN), "Value out-of-range for requested type.", value) {
return MIN;
}
KJ_REQUIRE(value <= U(MAX), "Value out-of-range for requested type.", value) {
return MAX;
}
T result = value;
KJ_REQUIRE(U(result) == value, "Value out-of-range for requested type.", value) {
// Use it anyway.
break;
}
return result;
}
} // namespace
#define HANDLE_NUMERIC_TYPE(typeName, ifInt, ifUint, ifFloat) \
typeName DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
switch (reader.type) { \
case INT: \
return ifInt<typeName>(reader.intValue); \
case UINT: \
return ifUint<typeName>(reader.uintValue); \
case FLOAT: \
return ifFloat<typeName>(reader.floatValue); \
default: \
KJ_FAIL_REQUIRE("Value type mismatch.") { \
return 0; \
} \
} \
} \
typeName DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
switch (builder.type) { \
case INT: \
return ifInt<typeName>(builder.intValue); \
case UINT: \
return ifUint<typeName>(builder.uintValue); \
case FLOAT: \
return ifFloat<typeName>(builder.floatValue); \
default: \
KJ_FAIL_REQUIRE("Value type mismatch.") { \
return 0; \
} \
} \
}
HANDLE_NUMERIC_TYPE(int8_t, checkRoundTrip, unsignedToSigned, checkRoundTripFromFloat)
HANDLE_NUMERIC_TYPE(int16_t, checkRoundTrip, unsignedToSigned, checkRoundTripFromFloat)
HANDLE_NUMERIC_TYPE(int32_t, checkRoundTrip, unsignedToSigned, checkRoundTripFromFloat)
HANDLE_NUMERIC_TYPE(int64_t, kj::implicitCast, unsignedToSigned, checkRoundTripFromFloat)
HANDLE_NUMERIC_TYPE(uint8_t, signedToUnsigned, checkRoundTrip, checkRoundTripFromFloat)
HANDLE_NUMERIC_TYPE(uint16_t, signedToUnsigned, checkRoundTrip, checkRoundTripFromFloat)
HANDLE_NUMERIC_TYPE(uint32_t, signedToUnsigned, checkRoundTrip, checkRoundTripFromFloat)
HANDLE_NUMERIC_TYPE(uint64_t, signedToUnsigned, kj::implicitCast, checkRoundTripFromFloat)
HANDLE_NUMERIC_TYPE(float, kj::implicitCast, kj::implicitCast, kj::implicitCast)
HANDLE_NUMERIC_TYPE(double, kj::implicitCast, kj::implicitCast, kj::implicitCast)
#undef HANDLE_NUMERIC_TYPE
#define HANDLE_TYPE(name, discrim, typeName) \
ReaderFor<typeName> DynamicValue::Reader::AsImpl<typeName>::apply(const Reader& reader) { \
KJ_REQUIRE(reader.type == discrim, "Value type mismatch.") { \
return ReaderFor<typeName>(); \
} \
return reader.name##Value; \
} \
BuilderFor<typeName> DynamicValue::Builder::AsImpl<typeName>::apply(Builder& builder) { \
KJ_REQUIRE(builder.type == discrim, "Value type mismatch."); \
return builder.name##Value; \
}
//HANDLE_TYPE(void, VOID, Void)
HANDLE_TYPE(bool, BOOL, bool)
HANDLE_TYPE(text, TEXT, Text)
HANDLE_TYPE(list, LIST, DynamicList)
HANDLE_TYPE(struct, STRUCT, DynamicStruct)
HANDLE_TYPE(enum, ENUM, DynamicEnum)
HANDLE_TYPE(anyPointer, ANY_POINTER, AnyPointer)
#undef HANDLE_TYPE
PipelineFor<DynamicStruct> DynamicValue::Pipeline::AsImpl<DynamicStruct>::apply(
Pipeline& pipeline) {
KJ_REQUIRE(pipeline.type == STRUCT, "Pipeline type mismatch.");
return kj::mv(pipeline.structValue);
}
ReaderFor<DynamicCapability> DynamicValue::Reader::AsImpl<DynamicCapability>::apply(
const Reader& reader) {
KJ_REQUIRE(reader.type == CAPABILITY, "Value type mismatch.") {
return DynamicCapability::Client();
}
return reader.capabilityValue;
}
BuilderFor<DynamicCapability> DynamicValue::Builder::AsImpl<DynamicCapability>::apply(
Builder& builder) {
KJ_REQUIRE(builder.type == CAPABILITY, "Value type mismatch.") {
return DynamicCapability::Client();
}
return builder.capabilityValue;
}
PipelineFor<DynamicCapability> DynamicValue::Pipeline::AsImpl<DynamicCapability>::apply(
Pipeline& pipeline) {
KJ_REQUIRE(pipeline.type == CAPABILITY, "Pipeline type mismatch.") {
return DynamicCapability::Client();
}
return kj::mv(pipeline.capabilityValue);
}
Data::Reader DynamicValue::Reader::AsImpl<Data>::apply(const Reader& reader) {
if (reader.type == TEXT) {
// Coerce text to data.
return reader.textValue.asBytes();
}
KJ_REQUIRE(reader.type == DATA, "Value type mismatch.") {
return Data::Reader();
}
return reader.dataValue;
}
Data::Builder DynamicValue::Builder::AsImpl<Data>::apply(Builder& builder) {
if (builder.type == TEXT) {
// Coerce text to data.
return builder.textValue.asBytes();
}
KJ_REQUIRE(builder.type == DATA, "Value type mismatch.") {
return BuilderFor<Data>();
}
return builder.dataValue;
}
// As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
Void DynamicValue::Reader::AsImpl<Void>::apply(const Reader& reader) {
KJ_REQUIRE(reader.type == VOID, "Value type mismatch.") {
return Void();
}
return reader.voidValue;
}
Void DynamicValue::Builder::AsImpl<Void>::apply(Builder& builder) {
KJ_REQUIRE(builder.type == VOID, "Value type mismatch.") {
return Void();
}
return builder.voidValue;
}
// =======================================================================================
namespace _ { // private
DynamicStruct::Reader PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
PointerReader reader, StructSchema schema) {
KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
"Cannot form pointer to group type.");
return DynamicStruct::Reader(schema, reader.getStruct(nullptr));
}
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::getDynamic(
PointerBuilder builder, StructSchema schema) {
KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
"Cannot form pointer to group type.");
return DynamicStruct::Builder(schema, builder.getStruct(
structSizeFromSchema(schema), nullptr));
}
void PointerHelpers<DynamicStruct, Kind::OTHER>::set(
PointerBuilder builder, const DynamicStruct::Reader& value) {
KJ_REQUIRE(!value.schema.getProto().getStruct().getIsGroup(),
"Cannot form pointer to group type.");
builder.setStruct(value.reader);
}
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::OTHER>::init(
PointerBuilder builder, StructSchema schema) {
KJ_REQUIRE(!schema.getProto().getStruct().getIsGroup(),
"Cannot form pointer to group type.");
return DynamicStruct::Builder(schema,
builder.initStruct(structSizeFromSchema(schema)));
}
DynamicList::Reader PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
PointerReader reader, ListSchema schema) {
return DynamicList::Reader(schema,
reader.getList(elementSizeFor(schema.whichElementType()), nullptr));
}
DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::getDynamic(
PointerBuilder builder, ListSchema schema) {
if (schema.whichElementType() == schema::Type::STRUCT) {
return DynamicList::Builder(schema,
builder.getStructList(
structSizeFromSchema(schema.getStructElementType()),
nullptr));
} else {
return DynamicList::Builder(schema,
builder.getList(elementSizeFor(schema.whichElementType()), nullptr));
}
}
void PointerHelpers<DynamicList, Kind::OTHER>::set(
PointerBuilder builder, const DynamicList::Reader& value) {
builder.setList(value.reader);
}
DynamicList::Builder PointerHelpers<DynamicList, Kind::OTHER>::init(
PointerBuilder builder, ListSchema schema, uint size) {
if (schema.whichElementType() == schema::Type::STRUCT) {
return DynamicList::Builder(schema,
builder.initStructList(bounded(size) * ELEMENTS,
structSizeFromSchema(schema.getStructElementType())));
} else {
return DynamicList::Builder(schema,
builder.initList(elementSizeFor(schema.whichElementType()), bounded(size) * ELEMENTS));
}
}
DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
PointerReader reader, InterfaceSchema schema) {
return DynamicCapability::Client(schema, reader.getCapability());
}
DynamicCapability::Client PointerHelpers<DynamicCapability, Kind::OTHER>::getDynamic(
PointerBuilder builder, InterfaceSchema schema) {
return DynamicCapability::Client(schema, builder.getCapability());
}
void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
PointerBuilder builder, DynamicCapability::Client& value) {
builder.setCapability(value.hook->addRef());
}
void PointerHelpers<DynamicCapability, Kind::OTHER>::set(
PointerBuilder builder, DynamicCapability::Client&& value) {
builder.setCapability(kj::mv(value.hook));
}
} // namespace _ (private)
template <>
void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan) {
switch (orphan.getType()) {
case DynamicValue::UNKNOWN:
case DynamicValue::VOID:
case DynamicValue::BOOL:
case DynamicValue::INT:
case DynamicValue::UINT:
case DynamicValue::FLOAT:
case DynamicValue::ENUM:
KJ_FAIL_REQUIRE("AnyPointer cannot adopt primitive (non-object) value.");
case DynamicValue::STRUCT:
case DynamicValue::LIST:
case DynamicValue::TEXT:
case DynamicValue::DATA:
case DynamicValue::CAPABILITY:
case DynamicValue::ANY_POINTER:
builder.adopt(kj::mv(orphan.builder));
break;
}
}
DynamicStruct::Reader::Reader(StructSchema schema, const _::OrphanBuilder& orphan)
: schema(schema), reader(orphan.asStructReader(structSizeFromSchema(schema))) {}
DynamicStruct::Builder::Builder(StructSchema schema, _::OrphanBuilder& orphan)
: schema(schema), builder(orphan.asStruct(structSizeFromSchema(schema))) {}
DynamicList::Reader::Reader(ListSchema schema, const _::OrphanBuilder& orphan)
: schema(schema), reader(orphan.asListReader(elementSizeFor(schema.whichElementType()))) {}
DynamicList::Builder::Builder(ListSchema schema, _::OrphanBuilder& orphan)
: schema(schema), builder(schema.whichElementType() == schema::Type::STRUCT
? orphan.asStructList(structSizeFromSchema(schema.getStructElementType()))
: orphan.asList(elementSizeFor(schema.whichElementType()))) {}
// -------------------------------------------------------------------
Orphan<DynamicStruct> Orphanage::newOrphan(StructSchema schema) const {
return Orphan<DynamicStruct>(
schema, _::OrphanBuilder::initStruct(arena, capTable, structSizeFromSchema(schema)));
}
Orphan<DynamicList> Orphanage::newOrphan(ListSchema schema, uint size) const {
if (schema.whichElementType() == schema::Type::STRUCT) {
return Orphan<DynamicList>(schema, _::OrphanBuilder::initStructList(
arena, capTable, bounded(size) * ELEMENTS,
structSizeFromSchema(schema.getStructElementType())));
} else {
return Orphan<DynamicList>(schema, _::OrphanBuilder::initList(
arena, capTable, bounded(size) * ELEMENTS,
elementSizeFor(schema.whichElementType())));
}
}
DynamicStruct::Builder Orphan<DynamicStruct>::get() {
return DynamicStruct::Builder(schema, builder.asStruct(structSizeFromSchema(schema)));
}
DynamicStruct::Reader Orphan<DynamicStruct>::getReader() const {
return DynamicStruct::Reader(schema, builder.asStructReader(structSizeFromSchema(schema)));
}
DynamicList::Builder Orphan<DynamicList>::get() {
if (schema.whichElementType() == schema::Type::STRUCT) {
return DynamicList::Builder(
schema, builder.asStructList(structSizeFromSchema(schema.getStructElementType())));
} else {
return DynamicList::Builder(
schema, builder.asList(elementSizeFor(schema.whichElementType())));
}
}
DynamicList::Reader Orphan<DynamicList>::getReader() const {
return DynamicList::Reader(
schema, builder.asListReader(elementSizeFor(schema.whichElementType())));
}
DynamicCapability::Client Orphan<DynamicCapability>::get() {
return DynamicCapability::Client(schema, builder.asCapability());
}
DynamicCapability::Client Orphan<DynamicCapability>::getReader() const {
return DynamicCapability::Client(schema, builder.asCapability());
}
Orphan<DynamicValue>::Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder)
: type(value.getType()), builder(kj::mv(builder)) {
switch (type) {
case DynamicValue::UNKNOWN: break;
case DynamicValue::VOID: voidValue = value.voidValue; break;
case DynamicValue::BOOL: boolValue = value.boolValue; break;
case DynamicValue::INT: intValue = value.intValue; break;
case DynamicValue::UINT: uintValue = value.uintValue; break;
case DynamicValue::FLOAT: floatValue = value.floatValue; break;
case DynamicValue::ENUM: enumValue = value.enumValue; break;
case DynamicValue::TEXT: break;
case DynamicValue::DATA: break;
case DynamicValue::LIST: listSchema = value.listValue.getSchema(); break;
case DynamicValue::STRUCT: structSchema = value.structValue.getSchema(); break;
case DynamicValue::CAPABILITY: interfaceSchema = value.capabilityValue.getSchema(); break;
case DynamicValue::ANY_POINTER: break;
}
}
DynamicValue::Builder Orphan<DynamicValue>::get() {
switch (type) {
case DynamicValue::UNKNOWN: return nullptr;
case DynamicValue::VOID: return voidValue;
case DynamicValue::BOOL: return boolValue;
case DynamicValue::INT: return intValue;
case DynamicValue::UINT: return uintValue;
case DynamicValue::FLOAT: return floatValue;
case DynamicValue::ENUM: return enumValue;
case DynamicValue::TEXT: return builder.asText();
case DynamicValue::DATA: return builder.asData();
case DynamicValue::LIST:
if (listSchema.whichElementType() == schema::Type::STRUCT) {
return DynamicList::Builder(listSchema,
builder.asStructList(structSizeFromSchema(listSchema.getStructElementType())));
} else {
return DynamicList::Builder(listSchema,
builder.asList(elementSizeFor(listSchema.whichElementType())));
}
case DynamicValue::STRUCT:
return DynamicStruct::Builder(structSchema,
builder.asStruct(structSizeFromSchema(structSchema)));
case DynamicValue::CAPABILITY:
return DynamicCapability::Client(interfaceSchema, builder.asCapability());
case DynamicValue::ANY_POINTER:
KJ_FAIL_REQUIRE("Can't get() an AnyPointer orphan; there is no underlying pointer to "
"wrap in an AnyPointer::Builder.");
}
KJ_UNREACHABLE;
}
DynamicValue::Reader Orphan<DynamicValue>::getReader() const {
switch (type) {
case DynamicValue::UNKNOWN: return nullptr;
case DynamicValue::VOID: return voidValue;
case DynamicValue::BOOL: return boolValue;
case DynamicValue::INT: return intValue;
case DynamicValue::UINT: return uintValue;
case DynamicValue::FLOAT: return floatValue;
case DynamicValue::ENUM: return enumValue;
case DynamicValue::TEXT: return builder.asTextReader();
case DynamicValue::DATA: return builder.asDataReader();
case DynamicValue::LIST:
return DynamicList::Reader(listSchema,
builder.asListReader(elementSizeFor(listSchema.whichElementType())));
case DynamicValue::STRUCT:
return DynamicStruct::Reader(structSchema,
builder.asStructReader(structSizeFromSchema(structSchema)));
case DynamicValue::CAPABILITY:
return DynamicCapability::Client(interfaceSchema, builder.asCapability());
case DynamicValue::ANY_POINTER:
KJ_FAIL_ASSERT("Can't get() an AnyPointer orphan; there is no underlying pointer to "
"wrap in an AnyPointer::Builder.");
}
KJ_UNREACHABLE;
}
template <>
Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>() {
KJ_REQUIRE(type == DynamicValue::ANY_POINTER, "Value type mismatch.");
type = DynamicValue::UNKNOWN;
return Orphan<AnyPointer>(kj::mv(builder));
}
template <>
Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>() {
KJ_REQUIRE(type == DynamicValue::STRUCT, "Value type mismatch.");
type = DynamicValue::UNKNOWN;
return Orphan<DynamicStruct>(structSchema, kj::mv(builder));
}
template <>
Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>() {
KJ_REQUIRE(type == DynamicValue::LIST, "Value type mismatch.");
type = DynamicValue::UNKNOWN;
return Orphan<DynamicList>(listSchema, kj::mv(builder));
}
template <>
Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
DynamicValue::Reader copyFrom) const {
switch (copyFrom.getType()) {
case DynamicValue::UNKNOWN: return nullptr;
case DynamicValue::VOID: return copyFrom.voidValue;
case DynamicValue::BOOL: return copyFrom.boolValue;
case DynamicValue::INT: return copyFrom.intValue;
case DynamicValue::UINT: return copyFrom.uintValue;
case DynamicValue::FLOAT: return copyFrom.floatValue;
case DynamicValue::ENUM: return copyFrom.enumValue;
case DynamicValue::TEXT: return newOrphanCopy(copyFrom.textValue);
case DynamicValue::DATA: return newOrphanCopy(copyFrom.dataValue);
case DynamicValue::LIST: return newOrphanCopy(copyFrom.listValue);
case DynamicValue::STRUCT: return newOrphanCopy(copyFrom.structValue);
case DynamicValue::CAPABILITY: return newOrphanCopy(copyFrom.capabilityValue);
case DynamicValue::ANY_POINTER: return newOrphanCopy(copyFrom.anyPointerValue);
}
KJ_UNREACHABLE;
}
} // namespace capnp