Commit b2edb433 authored by Kenton Varda's avatar Kenton Varda

More dynamic API WIP.

parent 18cfa132
......@@ -45,6 +45,9 @@ class ReaderArena;
class BuilderArena;
class ReadLimiter;
class Segment;
typedef Id<uint32_t, Segment> SegmentId;
class ReadLimiter {
// Used to keep track of how much data has been processed from a message, and cut off further
// processing if and when a particular limit is reached. This is primarily intended to guard
......
......@@ -30,7 +30,7 @@
namespace capnproto {
struct IdTextHash {
static size_t hash(std::pair<uint64_t, Text::Reader> p) {
size_t operator()(std::pair<uint64_t, Text::Reader> p) const {
// djb2a hash, but seeded with ID.
size_t result = p.first;
int c;
......@@ -46,10 +46,10 @@ struct IdTextHash {
struct SchemaPool::Impl {
std::unordered_map<uint64_t, schema::Node::Reader> nodeMap;
std::unordered_map<std::pair<uint64_t, std::string>, schema::StructNode::Member::Reader,
std::unordered_map<std::pair<uint64_t, Text::Reader>, schema::StructNode::Member::Reader,
IdTextHash>
memberMap;
std::unordered_map<std::pair<uint64_t, std::string>, schema::EnumNode::Enumerant::Reader,
std::unordered_map<std::pair<uint64_t, Text::Reader>, schema::EnumNode::Enumerant::Reader,
IdTextHash>
enumerantMap;
};
......@@ -58,9 +58,10 @@ SchemaPool::~SchemaPool() {
delete impl;
}
// TODO(soon): Implement this. Need to copy, ick.
//void add(schema::Node::Reader node) {
//}
// TODO(now): Implement this. Need to copy, ick.
void add(schema::Node::Reader node) {
FAIL_CHECK("Not implemented: copying/validating schemas.");
}
void SchemaPool::addNoCopy(schema::Node::Reader node) {
if (impl == nullptr) {
......@@ -82,14 +83,6 @@ bool SchemaPool::has(uint64_t id) const {
return (impl != nullptr && impl->nodeMap.count(id) != 0) || (base != nullptr && base->has(id));
}
DynamicStruct::Reader SchemaPool::getRoot(MessageReader& message, uint64_t typeId) const {
}
DynamicStruct::Builder SchemaPool::getRoot(MessageBuilder& message, uint64_t typeId) const {
}
// =======================================================================================
namespace {
......@@ -127,8 +120,8 @@ inline uint64_t bitCast<uint64_t, double>(double value) {
return result;
}
internal::FieldSize elementSizeFor(schema::Type::Reader elementType) {
switch (elementType.getBody().which()) {
internal::FieldSize elementSizeFor(schema::Type::Body::Which elementType) {
switch (elementType) {
case schema::Type::Body::VOID_TYPE: return internal::FieldSize::VOID;
case schema::Type::Body::BOOL_TYPE: return internal::FieldSize::BIT;
case schema::Type::Body::INT8_TYPE: return internal::FieldSize::BYTE;
......@@ -154,6 +147,13 @@ internal::FieldSize elementSizeFor(schema::Type::Reader elementType) {
return internal::FieldSize::VOID;
}
inline internal::StructSize structSizeFromSchema(schema::StructNode::Reader schema) {
return internal::StructSize(
schema.getDataSectionWordSize() * WORDS,
schema.getPointerSectionSize() * REFERENCES,
static_cast<internal::FieldSize>(schema.getPreferredListEncoding()));
}
} // namespace
// =======================================================================================
......@@ -180,8 +180,8 @@ Maybe<schema::EnumNode::Enumerant::Reader> DynamicEnum::findEnumerantByName(Text
}
}
uint16_t DynamicEnum::toImpl(uint64_t requestedTypeId) {
VALIDATE_INPUT(requestedTypeId == schema.getId(), "Type mismatch in DynamicEnum.to().") {
uint16_t DynamicEnum::asImpl(uint64_t requestedTypeId) {
VALIDATE_INPUT(requestedTypeId == schema.getId(), "Type mismatch in DynamicEnum.as().") {
// Go on with value.
}
return value;
......@@ -247,17 +247,9 @@ DynamicList::Builder DynamicObject::Builder::toList(internal::ListSchema schema)
// =======================================================================================
schema::StructNode::Union::Reader DynamicUnion::Reader::getSchema() {
return schema.getBody().getUnionMember();
}
schema::StructNode::Union::Reader DynamicUnion::Builder::getSchema() {
return schema.getBody().getUnionMember();
}
Maybe<schema::StructNode::Member::Reader> DynamicUnion::Reader::which() {
auto uschema = getSchema();
auto members = uschema.getMembers();
uint16_t discrim = reader.getDataField<uint32_t>(uschema.getDiscriminantOffset() * ELEMENTS);
auto members = schema.getMembers();
uint16_t discrim = reader.getDataField<uint32_t>(schema.getDiscriminantOffset() * ELEMENTS);
if (discrim < members.size()) {
return members[discrim];
......@@ -266,9 +258,8 @@ Maybe<schema::StructNode::Member::Reader> DynamicUnion::Reader::which() {
}
}
Maybe<schema::StructNode::Member::Reader> DynamicUnion::Builder::which() {
auto uschema = getSchema();
auto members = uschema.getMembers();
uint16_t discrim = builder.getDataField<uint32_t>(uschema.getDiscriminantOffset() * ELEMENTS);
auto members = schema.getMembers();
uint16_t discrim = builder.getDataField<uint32_t>(schema.getDiscriminantOffset() * ELEMENTS);
if (discrim < members.size()) {
return members[discrim];
......@@ -280,7 +271,7 @@ Maybe<schema::StructNode::Member::Reader> DynamicUnion::Builder::which() {
DynamicValue::Reader DynamicUnion::Reader::get() {
auto w = which();
RECOVERABLE_PRECOND(w != nullptr, "Can't get() unknown union value.") {
return DynamicValue::Reader(Void::VOID);
return DynamicValue::Reader();
}
auto body = w->getBody();
CHECK(body.which() == schema::StructNode::Member::Body::FIELD_MEMBER,
......@@ -292,7 +283,7 @@ DynamicValue::Reader DynamicUnion::Reader::get() {
DynamicValue::Builder DynamicUnion::Builder::get() {
auto w = which();
RECOVERABLE_PRECOND(w != nullptr, "Can't get() unknown union value.") {
return DynamicValue::Builder(Void::VOID);
return DynamicValue::Builder();
}
auto body = w->getBody();
CHECK(body.which() == schema::StructNode::Member::Body::FIELD_MEMBER,
......@@ -303,13 +294,94 @@ DynamicValue::Builder DynamicUnion::Builder::get() {
void DynamicUnion::Builder::set(
schema::StructNode::Field::Reader field, DynamicValue::Reader value) {
auto uschema = getSchema();
builder.setDataField<uint16_t>(uschema.getTagOffset(), field.getIndex());
builder.setDataField<uint16_t>(schema.getDiscriminantOffset() * ELEMENTS, field.getIndex());
DynamicStruct::Builder::setFieldImpl(pool, builder, field, value);
}
DynamicValue::Builder DynamicUnion::Builder::init(schema::StructNode::Field::Reader field) {
builder.setDataField<uint16_t>(schema.getDiscriminantOffset() * ELEMENTS, field.getIndex());
return DynamicStruct::Builder::initFieldImpl(pool, builder, field);
}
DynamicValue::Builder DynamicUnion::Builder::init(schema::StructNode::Field::Reader field,
uint size) {
builder.setDataField<uint16_t>(schema.getDiscriminantOffset() * ELEMENTS, field.getIndex());
return DynamicStruct::Builder::initFieldImpl(pool, builder, field, size);
}
// =======================================================================================
void DynamicStruct::Reader::verifyTypeId(uint64_t id) {
VALIDATE_INPUT(id == schema.getId(),
"Type mismatch when using DynamicStruct::Reader::as().") {
// Go on with bad type ID.
}
}
void DynamicStruct::Builder::verifyTypeId(uint64_t id) {
VALIDATE_INPUT(id == schema.getId(),
"Type mismatch when using DynamicStruct::Builder::as().") {
// Go on with bad type ID.
}
}
schema::StructNode::Reader DynamicStruct::Reader::getSchema() {
return schema.getBody().getStructNode();
}
schema::StructNode::Reader DynamicStruct::Builder::getSchema() {
return schema.getBody().getStructNode();
}
Maybe<schema::StructNode::Member::Reader> DynamicStruct::Reader::findMemberByName(
Text::Reader name) {
auto iter = pool->impl->memberMap.find(std::make_pair(schema.getId(), name));
if (iter == pool->impl->memberMap.end()) {
return nullptr;
} else {
return iter->second;
}
}
Maybe<schema::StructNode::Member::Reader> DynamicStruct::Builder::findMemberByName(
Text::Reader name) {
auto iter = pool->impl->memberMap.find(std::make_pair(schema.getId(), name));
if (iter == pool->impl->memberMap.end()) {
return nullptr;
} else {
return iter->second;
}
}
DynamicValue::Builder DynamicStruct::Builder::initObjectField(
schema::StructNode::Field::Reader field, schema::Type::Reader type) {
VALIDATE_INPUT(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
"Expected an Object. (To dynamically initialize a non-Object field, do not "
"pass an element type to initObjectField().)") {
return initFieldImpl(pool, builder, field);
}
return initFieldImpl(pool, builder, field, type);
}
DynamicValue::Builder DynamicStruct::Builder::initObjectField(
schema::StructNode::Field::Reader field, schema::Type::Reader type, uint size) {
VALIDATE_INPUT(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
"Expected an Object. (To dynamically initialize a non-Object field, do not "
"pass a struct schema to initObjectField().)") {
return initFieldImpl(pool, builder, field, size);
}
return initFieldImpl(pool, builder, field, type, size);
}
DynamicUnion::Reader DynamicStruct::Reader::getUnion(schema::StructNode::Union::Reader un) {
return DynamicUnion::Reader(pool, un, reader);
}
DynamicUnion::Builder DynamicStruct::Builder::getUnion(schema::StructNode::Union::Reader un) {
return DynamicUnion::Builder(pool, un, builder);
}
void DynamicStruct::Builder::copyFrom(Reader other) {
// TODO(now): copyFrom on StructBuilder.
// TODO(now): don't forget to check types match.
FAIL_CHECK("Unimplemented: copyFrom()");
}
DynamicValue::Reader DynamicStruct::Reader::getFieldImpl(
const SchemaPool* pool, internal::StructReader reader,
schema::StructNode::Field::Reader field) {
......@@ -367,7 +439,7 @@ DynamicValue::Reader DynamicStruct::Reader::getFieldImpl(
return DynamicValue::Reader(DynamicList::Reader(
pool, elementType,
reader.getListField(field.getOffset() * REFERENCES,
elementSizeFor(elementType),
elementSizeFor(elementType.getBody().which()),
dval.getListValue<internal::TrustedMessage>())));
}
......@@ -389,7 +461,7 @@ DynamicValue::Reader DynamicStruct::Reader::getFieldImpl(
break;
}
FAIL_CHECK("Can't get here.");
FAIL_CHECK("switch() missing case.", type.which());
return DynamicValue::Reader();
}
......@@ -478,7 +550,7 @@ DynamicValue::Builder DynamicStruct::Builder::getFieldImpl(
break;
}
FAIL_CHECK("Can't get here.");
FAIL_CHECK("switch() missing case.", type.which());
return DynamicValue::Builder();
}
......@@ -490,13 +562,13 @@ void DynamicStruct::Builder::setFieldImpl(
switch (type.which()) {
case schema::Type::Body::VOID_TYPE:
builder.setDataField<Void>(field.getOffset() * ELEMENTS, value.to<Void>());
builder.setDataField<Void>(field.getOffset() * ELEMENTS, value.as<Void>());
break;
#define HANDLE_TYPE(discrim, titleCase, type) \
case schema::Type::Body::discrim##_TYPE: \
builder.setDataField<type>( \
field.getOffset() * ELEMENTS, value.to<type>(), \
field.getOffset() * ELEMENTS, value.as<type>(), \
bitCast<internal::Mask<type> >(dval.get##titleCase##Value()));
break;
......@@ -516,35 +588,35 @@ void DynamicStruct::Builder::setFieldImpl(
case schema::Type::Body::ENUM_TYPE:
builder.setDataField<uint16_t>(
field.getOffset() * ELEMENTS, value.to<DynamicEnum>().getRaw(),
field.getOffset() * ELEMENTS, value.as<DynamicEnum>().getRaw(),
dval.getEnumValue());
break;
case schema::Type::Body::TEXT_TYPE:
builder.setBlobField<Text>(field.getOffset() * REFERENCES, value.to<Text>());
builder.setBlobField<Text>(field.getOffset() * REFERENCES, value.as<Text>());
break;
case schema::Type::Body::DATA_TYPE:
builder.setBlobField<Data>(field.getOffset() * REFERENCES, value.to<Data>());
builder.setBlobField<Data>(field.getOffset() * REFERENCES, value.as<Data>());
break;
case schema::Type::Body::LIST_TYPE: {
// TODO(soon): We need to do a schemaless copy to avoid losing information if the values are
// TODO(now): We need to do a schemaless copy to avoid losing information if the values are
// larger than what the schema defines.
auto listValue = value.to<DynamicList>();
initListFieldImpl(pool, builder, field, listValue.size()).copyFrom(listValue);
auto listValue = value.as<DynamicList>();
initFieldImpl(pool, builder, field, listValue.size()).as<DynamicList>().copyFrom(listValue);
break;
}
case schema::Type::Body::STRUCT_TYPE: {
// TODO(soon): We need to do a schemaless copy to avoid losing information if the values are
// TODO(now): We need to do a schemaless copy to avoid losing information if the values are
// larger than what the schema defines.
initStructFieldImpl(pool, builder, field).copyFrom(value.to<DynamicStruct>());
initFieldImpl(pool, builder, field).as<DynamicStruct>().copyFrom(value.as<DynamicStruct>());
break;
}
case schema::Type::Body::OBJECT_TYPE: {
// TODO(soon): Perform schemaless copy.
// TODO(now): Perform schemaless copy.
FAIL_CHECK("TODO");
break;
}
......@@ -555,21 +627,447 @@ void DynamicStruct::Builder::setFieldImpl(
}
}
DynamicValue::Builder DynamicStruct::Builder::initFieldImpl(
const SchemaPool* pool, internal::StructBuilder builder,
schema::StructNode::Field::Reader field, uint size) {
return initFieldImpl(pool, builder, field, field.getType(), size);
}
DynamicValue::Builder DynamicStruct::Builder::initFieldImpl(
const SchemaPool* pool, internal::StructBuilder builder,
schema::StructNode::Field::Reader field) {
return initFieldImpl(pool, builder, field, field.getType());
}
DynamicValue::Builder DynamicStruct::Builder::initFieldImpl(
const SchemaPool* pool, internal::StructBuilder builder,
schema::StructNode::Field::Reader field,
schema::Type::Reader type, uint size) {
switch (type.getBody().which()) {
case schema::Type::Body::VOID_TYPE:
case schema::Type::Body::BOOL_TYPE:
case schema::Type::Body::INT8_TYPE:
case schema::Type::Body::INT16_TYPE:
case schema::Type::Body::INT32_TYPE:
case schema::Type::Body::INT64_TYPE:
case schema::Type::Body::UINT8_TYPE:
case schema::Type::Body::UINT16_TYPE:
case schema::Type::Body::UINT32_TYPE:
case schema::Type::Body::UINT64_TYPE:
case schema::Type::Body::FLOAT32_TYPE:
case schema::Type::Body::FLOAT64_TYPE:
case schema::Type::Body::ENUM_TYPE:
case schema::Type::Body::STRUCT_TYPE:
case schema::Type::Body::INTERFACE_TYPE:
FAIL_VALIDATE_INPUT("Expected a list or blob.");
return getFieldImpl(pool, builder, field);
case schema::Type::Body::TEXT_TYPE:
return DynamicValue::Builder(
builder.initBlobField<Text>(field.getOffset() * REFERENCES, size * BYTES));
case schema::Type::Body::DATA_TYPE:
return DynamicValue::Builder(
builder.initBlobField<Data>(field.getOffset() * REFERENCES, size * BYTES));
case schema::Type::Body::LIST_TYPE: {
auto elementType = type.getBody().getListType();
if (elementType.getBody().which() == schema::Type::Body::STRUCT_TYPE) {
auto structType = pool->getStruct(elementType.getBody().getStructType());
return DynamicValue::Builder(DynamicList::Builder(
pool, schema::Type::Body::STRUCT_TYPE, 0, structType, builder.initStructListField(
field.getOffset() * REFERENCES, size * ELEMENTS,
structSizeFromSchema(structType.getBody().getStructNode()))));
} else {
return DynamicValue::Builder(DynamicList::Builder(
pool, elementType, builder.initListField(
field.getOffset() * REFERENCES,
elementSizeFor(elementType.getBody().which()),
size * ELEMENTS)));
}
}
case schema::Type::Body::OBJECT_TYPE: {
FAIL_VALIDATE_INPUT(
"Expected a list or blob, but found Object. (To dynamically initialize an object "
"field, you must pass an element type to initField().)");
return DynamicValue::Builder();
}
}
FAIL_CHECK("switch() missing case.", type.getBody().which());
return DynamicValue::Builder();
}
DynamicValue::Builder DynamicStruct::Builder::initFieldImpl(
const SchemaPool* pool, internal::StructBuilder builder,
schema::StructNode::Field::Reader field,
schema::Type::Reader type) {
switch (type.getBody().which()) {
case schema::Type::Body::VOID_TYPE:
case schema::Type::Body::BOOL_TYPE:
case schema::Type::Body::INT8_TYPE:
case schema::Type::Body::INT16_TYPE:
case schema::Type::Body::INT32_TYPE:
case schema::Type::Body::INT64_TYPE:
case schema::Type::Body::UINT8_TYPE:
case schema::Type::Body::UINT16_TYPE:
case schema::Type::Body::UINT32_TYPE:
case schema::Type::Body::UINT64_TYPE:
case schema::Type::Body::FLOAT32_TYPE:
case schema::Type::Body::FLOAT64_TYPE:
case schema::Type::Body::ENUM_TYPE:
case schema::Type::Body::TEXT_TYPE:
case schema::Type::Body::DATA_TYPE:
case schema::Type::Body::LIST_TYPE:
case schema::Type::Body::INTERFACE_TYPE:
FAIL_VALIDATE_INPUT("Expected a list or blob.");
return getFieldImpl(pool, builder, field);
case schema::Type::Body::STRUCT_TYPE: {
auto structType = pool->getStruct(type.getBody().getStructType());
return DynamicValue::Builder(DynamicStruct::Builder(
pool, structType, builder.initStructField(
field.getOffset() * REFERENCES,
structSizeFromSchema(structType.getBody().getStructNode()))));
}
case schema::Type::Body::OBJECT_TYPE: {
FAIL_VALIDATE_INPUT(
"Expected a struct, but found Object. (To dynamically initialize an object "
"field, you must pass an element type to initField().)");
return DynamicValue::Builder();
}
}
FAIL_CHECK("switch() missing case.", type.getBody().which());
return DynamicValue::Builder();
}
// =======================================================================================
DynamicValue::Reader DynamicList::Reader::operator[](uint index) {
PRECOND(index < size(), "List index out-of-bounds.");
if (depth == 0) {
switch (elementType) {
#define HANDLE_TYPE(name, discrim, typeName) \
case schema::Type::Body::discrim##_TYPE: \
return DynamicValue::Reader(reader.getDataElement<typeName>(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::Body::TEXT_TYPE:
return DynamicValue::Reader(reader.getBlobElement<Text>(index * ELEMENTS));
case schema::Type::Body::DATA_TYPE:
return DynamicValue::Reader(reader.getBlobElement<Data>(index * ELEMENTS));
case schema::Type::Body::LIST_TYPE:
FAIL_CHECK("elementType should not be LIST_TYPE when depth == 0.");
case schema::Type::Body::STRUCT_TYPE:
return DynamicValue::Reader(DynamicStruct::Reader(
pool, elementSchema, reader.getStructElement(index * ELEMENTS)));
case schema::Type::Body::ENUM_TYPE:
return DynamicValue::Reader(DynamicEnum(
pool, elementSchema, reader.getDataElement<uint16_t>(index * ELEMENTS)));
case schema::Type::Body::OBJECT_TYPE:
return DynamicValue::Reader(DynamicObject::Reader(
pool, reader.getObjectElement(index * ELEMENTS)));
case schema::Type::Body::INTERFACE_TYPE:
FAIL_RECOVERABLE_CHECK("Interfaces not implemented.") {}
return DynamicValue::Reader();
}
FAIL_CHECK("switch() missing case.", elementType);
return DynamicValue::Reader();
} else {
// List of lists.
return DynamicValue::Reader(DynamicList::Reader(
pool, elementType, depth - 1, elementSchema,
reader.getListElement(index * ELEMENTS,
depth == 1 ? elementSizeFor(elementType) : internal::FieldSize::REFERENCE)));
}
}
DynamicValue::Builder DynamicList::Builder::operator[](uint index) {
PRECOND(index < size(), "List index out-of-bounds.");
if (depth == 0) {
switch (elementType) {
#define HANDLE_TYPE(name, discrim, typeName) \
case schema::Type::Body::discrim##_TYPE: \
return DynamicValue::Builder(builder.getDataElement<typeName>(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::Body::TEXT_TYPE:
return DynamicValue::Builder(builder.getBlobElement<Text>(index * ELEMENTS));
case schema::Type::Body::DATA_TYPE:
return DynamicValue::Builder(builder.getBlobElement<Data>(index * ELEMENTS));
case schema::Type::Body::LIST_TYPE:
FAIL_CHECK("elementType should not be LIST_TYPE when depth == 0.");
return DynamicValue::Builder();
case schema::Type::Body::STRUCT_TYPE:
return DynamicValue::Builder(DynamicStruct::Builder(
pool, elementSchema, builder.getStructElement(index * ELEMENTS)));
case schema::Type::Body::ENUM_TYPE:
return DynamicValue::Builder(DynamicEnum(
pool, elementSchema, builder.getDataElement<uint16_t>(index * ELEMENTS)));
case schema::Type::Body::OBJECT_TYPE:
FAIL_CHECK("List(Object) not supported.");
break;
case schema::Type::Body::INTERFACE_TYPE:
FAIL_RECOVERABLE_CHECK("Interfaces not implemented.") {}
return DynamicValue::Builder();
}
FAIL_CHECK("switch() missing case.", elementType);
return DynamicValue::Builder();
} else {
// List of lists.
return DynamicValue::Builder(DynamicList::Builder(
pool, elementType, depth - 1, elementSchema,
builder.getListElement(index * ELEMENTS)));
}
}
void DynamicList::Builder::set(uint index, DynamicValue::Reader value) {
PRECOND(index < size(), "List index out-of-bounds.");
if (depth == 0) {
switch (elementType) {
#define HANDLE_TYPE(name, discrim, typeName) \
case schema::Type::Body::discrim##_TYPE: \
builder.setDataElement<typeName>(index * ELEMENTS, value.as<typeName>()); \
break;
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::Body::TEXT_TYPE:
builder.setBlobElement<Text>(index * ELEMENTS, value.as<Text>());
break;
case schema::Type::Body::DATA_TYPE:
builder.setBlobElement<Data>(index * ELEMENTS, value.as<Data>());
break;
case schema::Type::Body::LIST_TYPE:
FAIL_CHECK("elementType should not be LIST_TYPE when depth == 0.");
break;
case schema::Type::Body::STRUCT_TYPE:
// Note we can't do a schemaless copy here because the space is already allocated.
DynamicStruct::Builder(pool, elementSchema, builder.getStructElement(index * ELEMENTS))
.copyFrom(value.as<DynamicStruct>());
break;
case schema::Type::Body::ENUM_TYPE: {
auto enumValue = value.as<DynamicEnum>();
VALIDATE_INPUT(elementSchema.getId() == enumValue.getSchemaNode().getId(),
"Type mismatch when using DynamicList::Builder::set().");
builder.setDataElement<uint16_t>(index * ELEMENTS, value.as<DynamicEnum>().getRaw());
break;
}
case schema::Type::Body::OBJECT_TYPE:
FAIL_CHECK("List(Object) not supported.");
break;
case schema::Type::Body::INTERFACE_TYPE:
FAIL_RECOVERABLE_CHECK("Interfaces not implemented.") {}
break;
}
} else {
// List of lists.
// TODO(now): Perform schemaless copy.
auto listValue = value.as<DynamicList>();
init(index, listValue.size()).as<DynamicList>().copyFrom(listValue);
}
}
DynamicValue::Builder DynamicList::Builder::init(uint index, uint size) {
PRECOND(index < this->size(), "List index out-of-bounds.");
if (depth == 0) {
switch (elementType) {
case schema::Type::Body::VOID_TYPE:
case schema::Type::Body::BOOL_TYPE:
case schema::Type::Body::INT8_TYPE:
case schema::Type::Body::INT16_TYPE:
case schema::Type::Body::INT32_TYPE:
case schema::Type::Body::INT64_TYPE:
case schema::Type::Body::UINT8_TYPE:
case schema::Type::Body::UINT16_TYPE:
case schema::Type::Body::UINT32_TYPE:
case schema::Type::Body::UINT64_TYPE:
case schema::Type::Body::FLOAT32_TYPE:
case schema::Type::Body::FLOAT64_TYPE:
case schema::Type::Body::ENUM_TYPE:
case schema::Type::Body::STRUCT_TYPE:
case schema::Type::Body::INTERFACE_TYPE:
FAIL_VALIDATE_INPUT("Expected a list or blob.");
return DynamicValue::Builder();
case schema::Type::Body::TEXT_TYPE:
return DynamicValue::Builder(builder.initBlobElement<Text>(index * ELEMENTS, size * BYTES));
case schema::Type::Body::DATA_TYPE:
return DynamicValue::Builder(builder.initBlobElement<Data>(index * ELEMENTS, size * BYTES));
case schema::Type::Body::LIST_TYPE:
FAIL_CHECK("elementType should not be LIST_TYPE when depth == 0.");
return DynamicValue::Builder();
case schema::Type::Body::OBJECT_TYPE: {
FAIL_CHECK("List(Object) not supported.");
return DynamicValue::Builder();
}
}
FAIL_CHECK("switch() missing case.", elementType);
return DynamicValue::Builder();
} else {
// List of lists.
internal::FieldSize elementSize = depth == 1 ?
elementSizeFor(elementType) : internal::FieldSize::REFERENCE;
if (elementSize == internal::FieldSize::INLINE_COMPOSITE) {
return DynamicValue::Builder(DynamicList::Builder(
pool, elementType, depth - 1, elementSchema, builder.initStructListElement(
index * ELEMENTS, size * ELEMENTS,
structSizeFromSchema(elementSchema.getBody().getStructNode()))));
} else {
return DynamicValue::Builder(DynamicList::Builder(
pool, elementType, depth - 1, elementSchema, builder.initListElement(
index * ELEMENTS, elementSizeFor(elementType), size * ELEMENTS)));
}
}
}
void DynamicList::Builder::copyFrom(Reader other) {
// TODO(now): copyFrom on ListBuilder.
// TODO(now): don't forget to check types match.
FAIL_CHECK("Unimplemented: copyFrom()");
}
DynamicList::Reader DynamicList::Builder::asReader() {
return DynamicList::Reader(pool, elementType, depth, elementSchema, builder.asReader());
}
DynamicList::Reader::Reader(const SchemaPool* pool, schema::Type::Reader elementType,
internal::ListReader reader)
: Reader(pool, internal::ListSchema(elementType), reader) {}
DynamicList::Reader::Reader(const SchemaPool* pool, internal::ListSchema schema,
internal::ListReader reader)
: pool(pool), elementType(schema.elementType), depth(schema.nestingDepth), reader(reader) {
switch (elementType) {
case schema::Type::Body::ENUM_TYPE:
elementSchema = pool->getEnum(schema.elementTypeId);
break;
case schema::Type::Body::STRUCT_TYPE:
elementSchema = pool->getStruct(schema.elementTypeId);
break;
case schema::Type::Body::INTERFACE_TYPE:
elementSchema = pool->getInterface(schema.elementTypeId);
break;
default:
// Leave schema default-initialized.
break;
}
}
DynamicList::Builder::Builder(const SchemaPool* pool, schema::Type::Reader elementType,
internal::ListBuilder builder)
: Builder(pool, internal::ListSchema(elementType), builder) {}
DynamicList::Builder::Builder(const SchemaPool* pool, internal::ListSchema schema,
internal::ListBuilder builder)
: pool(pool), elementType(schema.elementType), depth(schema.nestingDepth), builder(builder) {
switch (elementType) {
case schema::Type::Body::ENUM_TYPE:
elementSchema = pool->getEnum(schema.elementTypeId);
break;
case schema::Type::Body::STRUCT_TYPE:
elementSchema = pool->getStruct(schema.elementTypeId);
break;
case schema::Type::Body::INTERFACE_TYPE:
elementSchema = pool->getInterface(schema.elementTypeId);
break;
default:
// Leave schema default-initialized.
break;
}
}
void DynamicList::Reader::verifySchema(internal::ListSchema schema) {
VALIDATE_INPUT(schema.elementType == elementType &&
schema.nestingDepth == depth &&
schema.elementTypeId == elementSchema.getId(),
"Type mismatch when using DynamicList::Reader::as().");
}
void DynamicList::Builder::verifySchema(internal::ListSchema schema) {
VALIDATE_INPUT(schema.elementType == elementType &&
schema.nestingDepth == depth &&
schema.elementTypeId == elementSchema.getId(),
"Type mismatch when using DynamicList::Reader::as().");
}
// =======================================================================================
#if 0
#define HANDLE_TYPE(name, discrim, typeName) \
ReaderFor<typeName> DynamicValue::Reader::ToImpl<typeName>::apply(Reader reader) { \
ReaderFor<typeName> DynamicValue::Reader::asImpl<typeName>::apply(Reader reader) { \
VALIDATE_INPUT(reader.type == schema::Type::Body::discrim##_TYPE, \
"Type mismatch when using DynamicValue::to().") { \
return typeName(); \
"Type mismatch when using DynamicValue::Reader::as().") { \
return ReaderFor<typeName>(); \
} \
return reader.name##Value; \
} \
BuilderFor<typeName> DynamicValue::Builder::ToImpl<typeName>::apply(Builder builder) { \
BuilderFor<typeName> DynamicValue::Builder::asImpl<typeName>::apply(Builder builder) { \
VALIDATE_INPUT(builder.type == schema::Type::Body::discrim##_TYPE, \
"Type mismatch when using DynamicValue::to().") { \
return typeName(); \
"Type mismatch when using DynamicValue::Builder::as().") { \
return BuilderFor<typeName>(); \
} \
return builder.name##Value; \
}
......@@ -595,22 +1093,103 @@ HANDLE_TYPE(enum, ENUM, DynamicEnum)
HANDLE_TYPE(object, OBJECT, DynamicObject)
#undef HANDLE_TYPE
#endif
// As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
Void DynamicValue::Reader::ToImpl<Void>::apply(Reader reader) {
Void DynamicValue::Reader::asImpl<Void>::apply(Reader reader) {
VALIDATE_INPUT(reader.type == schema::Type::Body::VOID_TYPE,
"Type mismatch when using DynamicValue::to().") {
"Type mismatch when using DynamicValue::Reader::as().") {
return Void();
}
return reader.voidValue;
}
Void DynamicValue::Builder::ToImpl<Void>::apply(Builder builder) {
Void DynamicValue::Builder::asImpl<Void>::apply(Builder builder) {
VALIDATE_INPUT(builder.type == schema::Type::Body::VOID_TYPE,
"Type mismatch when using DynamicValue::to().") {
"Type mismatch when using DynamicValue::Builder::as().") {
return Void();
}
return builder.voidValue;
}
// =======================================================================================
template <>
DynamicStruct::Reader MessageReader::getRoot<DynamicStruct>(
const SchemaPool& pool, uint64_t typeId) {
return DynamicStruct::Reader(&pool, pool.getStruct(typeId), getRootInternal());
}
template <>
DynamicStruct::Builder MessageBuilder::initRoot<DynamicStruct>(
const SchemaPool& pool, uint64_t typeId) {
auto schema = pool.getStruct(typeId);
return DynamicStruct::Builder(&pool, schema,
initRoot(structSizeFromSchema(schema.getBody().getStructNode())));
}
template <>
DynamicStruct::Builder MessageBuilder::getRoot<DynamicStruct>(
const SchemaPool& pool, uint64_t typeId) {
auto schema = pool.getStruct(typeId);
return DynamicStruct::Builder(&pool, schema,
getRoot(structSizeFromSchema(schema.getBody().getStructNode())));
}
namespace internal {
DynamicStruct::Reader PointerHelpers<DynamicStruct, Kind::UNKNOWN>::get(
StructReader reader, WireReferenceCount index, const SchemaPool& pool, uint64_t typeId) {
return DynamicStruct::Reader(&pool, pool.getStruct(typeId),
reader.getStructField(index, nullptr));
}
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::UNKNOWN>::get(
StructBuilder builder, WireReferenceCount index, const SchemaPool& pool, uint64_t typeId) {
auto schema = pool.getStruct(typeId);
return DynamicStruct::Builder(&pool, schema, builder.getStructField(
index, structSizeFromSchema(schema.getBody().getStructNode()), nullptr));
}
void PointerHelpers<DynamicStruct, Kind::UNKNOWN>::set(
StructBuilder builder, WireReferenceCount index, DynamicStruct::Reader value) {
// TODO(now): schemaless copy
FAIL_CHECK("Unimplemented: copyFrom()");
}
DynamicStruct::Builder PointerHelpers<DynamicStruct, Kind::UNKNOWN>::init(
StructBuilder builder, WireReferenceCount index, const SchemaPool& pool, uint64_t typeId) {
auto schema = pool.getStruct(typeId);
return DynamicStruct::Builder(&pool, schema, builder.initStructField(
index, structSizeFromSchema(schema.getBody().getStructNode())));
}
DynamicList::Reader PointerHelpers<DynamicList, Kind::UNKNOWN>::get(
StructReader reader, WireReferenceCount index, const SchemaPool& pool,
schema::Type::Reader elementType) {
return DynamicList::Reader(&pool, elementType,
reader.getListField(index, elementSizeFor(elementType.getBody().which()), nullptr));
}
DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::get(
StructBuilder builder, WireReferenceCount index, const SchemaPool& pool,
schema::Type::Reader elementType) {
return DynamicList::Builder(&pool, elementType, builder.getListField(index, nullptr));
}
void PointerHelpers<DynamicList, Kind::UNKNOWN>::set(
StructBuilder builder, WireReferenceCount index, DynamicList::Reader value) {
// TODO(now): schemaless copy
FAIL_CHECK("Unimplemented: copyFrom()");
}
DynamicList::Builder PointerHelpers<DynamicList, Kind::UNKNOWN>::init(
StructBuilder builder, WireReferenceCount index,
const SchemaPool& pool, schema::Type::Reader elementType, uint size) {
auto elementSize = elementSizeFor(elementType.getBody().which());
if (elementSize == FieldSize::INLINE_COMPOSITE) {
auto elementSchema = pool.getStruct(elementType.getBody().getStructType());
return DynamicList::Builder(&pool, schema::Type::Body::STRUCT_TYPE, 0, elementSchema,
builder.initStructListField(index, size * ELEMENTS,
structSizeFromSchema(elementSchema.getBody().getStructNode())));
} else {
return DynamicList::Builder(&pool, elementType,
builder.initListField(index, elementSize, size * ELEMENTS));
}
}
} // namespace internal
} // namespace capnproto
......@@ -37,6 +37,7 @@
#include "schema.capnp.h"
#include "layout.h"
#include "message.h"
namespace capnproto {
......@@ -111,8 +112,13 @@ public:
template <typename T> DynamicList::Reader fromListReader(T&& reader);
template <typename T> DynamicList::Builder fromListBuilder(T&& builder);
DynamicStruct::Reader getRoot(MessageReader& message, uint64_t typeId) const;
DynamicStruct::Builder getRoot(MessageBuilder& message, uint64_t typeId) const;
schema::Node::Reader getNode(uint64_t id) const;
// Look up the node with the given ID, throwing an exception if not found.
schema::Node::Reader getStruct(uint64_t id) const;
schema::Node::Reader getEnum(uint64_t id) const;
schema::Node::Reader getInterface(uint64_t id) const;
// Like getNode() but also throws if the kind is not as requested.
private:
struct Impl;
......@@ -124,14 +130,10 @@ private:
void addNoCopy(schema::Node::Reader node);
schema::Node::Reader getStruct(uint64_t id) const;
schema::Node::Reader getEnum(uint64_t id) const;
schema::Node::Reader getInterface(uint64_t id) const;
friend class DynamicEnum;
friend class DynamicStruct;
friend class DynamicList;
friend class DynamicObject;
friend struct DynamicStruct;
friend struct DynamicList;
friend struct DynamicObject;
};
// -------------------------------------------------------------------
......@@ -163,11 +165,11 @@ struct ListSchema {
};
template <typename ElementType, Kind kind = kind<ElementType>()>
struct ListSchemaFor;
struct ListSchemaForElement;
#define CAPNPROTO_DECLARE_TYPE(discrim, typeName) \
template <> \
struct ListSchemaFor<List<typeName>> { \
struct ListSchemaForElement<List<typeName>> { \
static constexpr ListSchema type = ListSchema(schema::Type::Body::discrim##_TYPE); \
};
......@@ -191,23 +193,28 @@ CAPNPROTO_DECLARE_TYPE(LIST, DynamicList)
#undef CAPNPROTO_DECLARE_TYPE
template <typename T>
struct ListSchemaFor<T, Kind::ENUM> {
struct ListSchemaForElement<T, Kind::ENUM> {
static constexpr ListSchema type = ListSchema(schema::Type::Body::ENUM_TYPE, typeId<T>());
};
template <typename T>
struct ListSchemaFor<T, Kind::STRUCT> {
struct ListSchemaForElement<T, Kind::STRUCT> {
static constexpr ListSchema type = ListSchema(schema::Type::Body::STRUCT_TYPE, typeId<T>());
};
template <typename T>
struct ListSchemaFor<T, Kind::INTERFACE> {
struct ListSchemaForElement<T, Kind::INTERFACE> {
static constexpr ListSchema type = ListSchema(schema::Type::Body::INTERFACE_TYPE, typeId<T>());
};
template <typename T>
struct ListSchemaFor<List<T>, Kind::LIST> {
static constexpr ListSchema type = ListSchemaFor<T>::schema.deeper();
struct ListSchemaForElement<List<T>, Kind::LIST> {
static constexpr ListSchema type = ListSchemaForElement<T>::schema.deeper();
};
template <typename T>
struct ListSchemaFor;
template <typename T>
struct ListSchemaFor<List<T>>: public ListSchemaForElement<T> {};
} // namespace internal
// -------------------------------------------------------------------
......@@ -217,7 +224,7 @@ public:
DynamicEnum() = default;
template <typename T>
inline T to() { return static_cast<T>(toImpl(typeId<T>())); }
inline T as() { return static_cast<T>(asImpl(typeId<T>())); }
// Cast to a native enum type.
schema::Node::Reader getSchemaNode() { return schema; }
......@@ -242,9 +249,10 @@ private:
inline DynamicEnum(const SchemaPool* pool, schema::Node::Reader schema, uint16_t value)
: pool(pool), schema(schema), value(value) {}
uint16_t toImpl(uint64_t requestedTypeId);
uint16_t asImpl(uint64_t requestedTypeId);
friend struct DynamicStruct;
friend struct DynamicList;
};
// -------------------------------------------------------------------
......@@ -254,7 +262,7 @@ public:
Reader() = default;
template <typename T>
inline typename T::Reader to() { return ToImpl<T>::apply(*this); }
inline typename T::Reader as() { return asImpl<T>::apply(*this); }
// Convert the object to the given struct, list, or blob type.
DynamicStruct::Reader toStruct(schema::Node::Reader schema);
......@@ -267,14 +275,15 @@ private:
inline Reader(const SchemaPool* pool, internal::ObjectReader reader)
: pool(pool), reader(reader) {}
template <typename T, Kind kind = kind<T>()> struct ToImpl;
// Implementation backing the to() method. Needs to be a struct to allow partial
template <typename T, Kind kind = kind<T>()> struct asImpl;
// Implementation backing the as() method. Needs to be a struct to allow partial
// specialization. Has a method apply() which does the work.
DynamicStruct::Reader toStruct(uint64_t typeId);
DynamicList::Reader toList(internal::ListSchema schema);
friend struct DynamicStruct;
friend struct DynamicList;
};
class DynamicObject::Builder {
......@@ -282,7 +291,7 @@ public:
Builder() = default;
template <typename T>
inline typename T::Builder to() { return ToImpl<T>::apply(*this); }
inline typename T::Builder as() { return asImpl<T>::apply(*this); }
// Convert the object to the given struct, list, or blob type.
DynamicStruct::Builder toStruct(schema::Node::Reader schema);
......@@ -295,14 +304,15 @@ private:
inline Builder(const SchemaPool* pool, internal::ObjectBuilder builder)
: pool(pool), builder(builder) {}
template <typename T, Kind kind = kind<T>()> struct ToImpl;
// Implementation backing the to() method. Needs to be a struct to allow partial
template <typename T, Kind kind = kind<T>()> struct asImpl;
// Implementation backing the as() method. Needs to be a struct to allow partial
// specialization. Has a method apply() which does the work.
DynamicStruct::Builder toStruct(uint64_t typeId);
DynamicList::Builder toList(internal::ListSchema schema);
friend struct DynamicStruct;
friend struct DynamicList;
};
// -------------------------------------------------------------------
......@@ -311,8 +321,7 @@ class DynamicUnion::Reader {
public:
Reader() = default;
schema::StructNode::Member::Reader getMemberSchema() { return schema; }
schema::StructNode::Union::Reader getSchema();
schema::StructNode::Union::Reader getSchema() { return schema; }
Maybe<schema::StructNode::Member::Reader> which();
// Returns which field is set, or nullptr if an unknown field is set (i.e. the schema is old, and
......@@ -323,20 +332,21 @@ public:
private:
const SchemaPool* pool;
schema::StructNode::Member::Reader schema;
schema::StructNode::Union::Reader schema;
internal::StructReader reader;
inline Reader(const SchemaPool* pool, schema::StructNode::Member::Reader schema,
inline Reader(const SchemaPool* pool, schema::StructNode::Union::Reader schema,
internal::StructReader reader)
: pool(pool), schema(schema), reader(reader) {}
friend struct DynamicStruct;
};
class DynamicUnion::Builder {
public:
Builder() = default;
schema::StructNode::Member::Reader getMemberSchema() { return schema; }
schema::StructNode::Union::Reader getSchema();
schema::StructNode::Union::Reader getSchema() { return schema; }
Maybe<schema::StructNode::Member::Reader> which();
// Returns which field is set, or nullptr if an unknown field is set (i.e. the schema is old, and
......@@ -345,15 +355,18 @@ public:
DynamicValue::Builder get();
void set(schema::StructNode::Field::Reader field, DynamicValue::Reader value);
DynamicValue::Builder init(schema::StructNode::Field::Reader field);
DynamicValue::Builder init(schema::StructNode::Field::Reader field, uint size);
private:
const SchemaPool* pool;
schema::StructNode::Member::Reader schema;
schema::StructNode::Union::Reader schema;
internal::StructBuilder builder;
inline Builder(const SchemaPool* pool, schema::StructNode::Member::Reader schema,
inline Builder(const SchemaPool* pool, schema::StructNode::Union::Reader schema,
internal::StructBuilder builder)
: pool(pool), schema(schema), builder(builder) {}
friend struct DynamicStruct;
};
// -------------------------------------------------------------------
......@@ -363,10 +376,10 @@ public:
Reader() = default;
template <typename T>
typename T::Reader to();
typename T::Reader as();
// Convert the dynamic struct to its compiled-in type.
schema::Node::Reader getSchemaNode();
schema::Node::Reader getSchemaNode() { return schema; }
schema::StructNode::Reader getSchema();
Maybe<schema::StructNode::Member::Reader> findMemberByName(Text::Reader name);
......@@ -386,6 +399,8 @@ private:
inline Reader(const SchemaPool* pool, schema::Node::Reader schema, internal::StructReader reader)
: pool(pool), schema(schema), reader(reader) {}
void verifyTypeId(uint64_t id);
static DynamicValue::Reader getFieldImpl(
const SchemaPool* pool, internal::StructReader reader,
schema::StructNode::Field::Reader field);
......@@ -393,7 +408,11 @@ private:
template <typename T>
friend struct internal::PointerHelpers;
friend class DynamicUnion::Reader;
friend class DynamicObject;
friend struct DynamicObject;
friend class DynamicStruct::Builder;
friend struct DynamicList;
friend class MessageReader;
friend class MessageBuilder;
};
class DynamicStruct::Builder {
......@@ -401,10 +420,10 @@ public:
Builder() = default;
template <typename T>
typename T::Builder to();
typename T::Builder as();
// Cast to a particular struct type.
schema::Node::Reader getSchemaNode();
schema::Node::Reader getSchemaNode() { return schema; }
schema::StructNode::Reader getSchema();
Maybe<schema::StructNode::Member::Reader> findMemberByName(Text::Reader name);
......@@ -416,10 +435,16 @@ public:
void setField(schema::StructNode::Field::Reader field, DynamicValue::Reader value);
// Sets the value of the given field.
DynamicStruct::Builder initField(schema::StructNode::Field::Reader field);
DynamicList::Builder initField(schema::StructNode::Field::Reader field, uint size);
DynamicValue::Builder initField(schema::StructNode::Field::Reader field);
DynamicValue::Builder initField(schema::StructNode::Field::Reader field, uint size);
// Initialize a struct or list field by field schema.
DynamicValue::Builder initObjectField(schema::StructNode::Field::Reader field,
schema::Type::Reader type);
DynamicValue::Builder initObjectField(schema::StructNode::Field::Reader field,
schema::Type::Reader type, uint size);
// Initialize an Object-typed field. You must specify the type to initialize as.
DynamicUnion::Builder getUnion(schema::StructNode::Union::Reader un);
// Returns the value of the given union.
......@@ -436,23 +461,36 @@ private:
internal::StructBuilder builder)
: pool(pool), schema(schema), builder(builder) {}
void verifyTypeId(uint64_t id);
static DynamicValue::Builder getFieldImpl(
const SchemaPool* pool, internal::StructBuilder builder,
schema::StructNode::Field::Reader field);
static void setFieldImpl(
const SchemaPool* pool, internal::StructBuilder builder,
schema::StructNode::Field::Reader field, DynamicValue::Reader value);
static DynamicList::Builder initListFieldImpl(
static DynamicValue::Builder initFieldImpl(
const SchemaPool* pool, internal::StructBuilder builder,
schema::StructNode::Field::Reader field, uint length);
static DynamicStruct::Builder initStructFieldImpl(
schema::StructNode::Field::Reader field, uint size);
static DynamicValue::Builder initFieldImpl(
const SchemaPool* pool, internal::StructBuilder builder,
schema::StructNode::Field::Reader field);
static DynamicValue::Builder initFieldImpl(
const SchemaPool* pool, internal::StructBuilder builder,
schema::StructNode::Field::Reader field,
schema::Type::Reader type, uint size);
static DynamicValue::Builder initFieldImpl(
const SchemaPool* pool, internal::StructBuilder builder,
schema::StructNode::Field::Reader field,
schema::Type::Reader type);
template <typename T>
friend struct internal::PointerHelpers;
friend class DynamicUnion::Builder;
friend class DynamicObject;
friend struct DynamicObject;
friend struct DynamicList;
friend class MessageReader;
friend class MessageBuilder;
};
// -------------------------------------------------------------------
......@@ -463,7 +501,7 @@ public:
inline explicit Reader(internal::ListReader reader): reader(reader) {}
template <typename T>
typename T::Reader to();
typename T::Reader as();
// Try to convert to any List<T>, Data, or Text. Throws an exception if the underlying data
// can't possibly represent the requested type.
......@@ -486,14 +524,24 @@ private:
// Number of types elementType must be wrapped in List() to get the actual element type, e.g.
// List(List(List(Bool))) has depth = 2.
schema::Node::Body::Reader elementSchema; // if elementType is struct/enum/interface
schema::Node::Reader elementSchema; // if elementType is struct/enum/interface
internal::ListReader reader;
Reader(const SchemaPool* pool, schema::Type::Reader elementType, internal::ListReader reader);
Reader(const SchemaPool* pool, internal::ListSchema schema, internal::ListReader reader);
friend class DynamicStruct;
friend class DynamicObject;
Reader(const SchemaPool* pool, schema::Type::Body::Which elementType, uint depth,
schema::Node::Reader elementSchema, internal::ListReader reader)
: pool(pool), elementType(elementType), depth(depth), elementSchema(elementSchema),
reader(reader) {}
void verifySchema(internal::ListSchema schema);
template <typename T>
friend struct internal::PointerHelpers;
friend struct DynamicStruct;
friend struct DynamicObject;
friend class DynamicList::Builder;
};
class DynamicList::Builder {
......@@ -502,12 +550,14 @@ public:
inline explicit Builder(internal::ListBuilder builder): builder(builder) {}
template <typename T>
typename T::Builder to();
typename T::Builder as();
// Try to convert to any List<T>, Data, or Text. Throws an exception if the underlying data
// can't possibly represent the requested type.
inline uint size() { return builder.size() / ELEMENTS; }
DynamicStruct::Builder operator[](uint index);
DynamicValue::Builder operator[](uint index);
void set(uint index, DynamicValue::Reader value);
DynamicValue::Builder init(uint index, uint size);
typedef internal::IndexingIterator<Builder, DynamicStruct::Builder> iterator;
inline iterator begin() { return iterator(this, 0); }
......@@ -521,13 +571,22 @@ private:
const SchemaPool* pool;
schema::Type::Body::Which elementType;
uint depth;
schema::Node::Body::Reader elementSchema;
schema::Node::Reader elementSchema;
internal::ListBuilder builder;
Builder(const SchemaPool* pool, schema::Type::Reader elementType, internal::ListBuilder builder);
Builder(const SchemaPool* pool, internal::ListSchema schema, internal::ListBuilder builder);
friend class DynamicStruct;
friend class DynamicObject;
Builder(const SchemaPool* pool, schema::Type::Body::Which elementType, uint depth,
schema::Node::Reader elementSchema, internal::ListBuilder builder)
: pool(pool), elementType(elementType), depth(depth), elementSchema(elementSchema),
builder(builder) {}
void verifySchema(internal::ListSchema schema);
template <typename T>
friend struct internal::PointerHelpers;
friend struct DynamicStruct;
friend struct DynamicObject;
};
// -------------------------------------------------------------------
......@@ -535,7 +594,7 @@ private:
namespace internal {
// Make sure ReaderFor<T> and BuilderFor<T> work for DynamicEnum, DynamicObject, DynamicStruct, and
// DynamicList, so that we can define DynamicValue::to().
// DynamicList, so that we can define DynamicValue::as().
template <>
struct MaybeReaderBuilder<DynamicEnum, Kind::UNKNOWN> {
......@@ -565,8 +624,7 @@ struct MaybeReaderBuilder<DynamicList, Kind::UNKNOWN> {
class DynamicValue::Reader {
public:
inline Reader() {}
inline Reader(Void voidValue);
inline Reader(Void voidValue = Void::VOID);
inline Reader(bool boolValue);
inline Reader(int8_t int8Value);
inline Reader(int16_t int16Value);
......@@ -586,7 +644,7 @@ public:
inline Reader(DynamicObject::Reader objectValue);
template <typename T>
inline ReaderFor<T> to() { return ToImpl<T>::apply(*this); }
inline ReaderFor<T> as() { return asImpl<T>::apply(*this); }
// Use to interpret the value as some type. Allowed types are:
// - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum: Returns the raw value.
// - Text, Data, any struct type: Returns the corresponding Reader.
......@@ -625,15 +683,14 @@ private:
DynamicObject::Reader objectValue;
};
template <typename T, Kind kind = kind<T>()> struct ToImpl;
// Implementation backing the to() method. Needs to be a struct to allow partial
template <typename T, Kind kind = kind<T>()> struct asImpl;
// Implementation backing the as() method. Needs to be a struct to allow partial
// specialization. Has a method apply() which does the work.
};
class DynamicValue::Builder {
public:
inline Builder() {}
inline Builder(Void voidValue);
inline Builder(Void voidValue = Void::VOID);
inline Builder(bool boolValue);
inline Builder(int8_t int8Value);
inline Builder(int16_t int16Value);
......@@ -653,8 +710,8 @@ public:
inline Builder(DynamicObject::Builder objectValue);
template <typename T>
inline BuilderFor<T> to() { return ToImpl<T>::apply(*this); }
// See DynamicValue::Reader::to().
inline BuilderFor<T> as() { return asImpl<T>::apply(*this); }
// See DynamicValue::Reader::as().
inline schema::Type::Body::Which getType() { return type; }
// Get the type of this value.
......@@ -685,13 +742,54 @@ private:
DynamicObject::Builder objectValue;
};
template <typename T, Kind kind = kind<T>()> struct ToImpl;
// Implementation backing the to() method. Needs to be a struct to allow partial
template <typename T, Kind kind = kind<T>()> struct asImpl;
// Implementation backing the as() method. Needs to be a struct to allow partial
// specialization. Has a method apply() which does the work.
};
// -------------------------------------------------------------------
// Inject the ability to use DynamicStruct for message roots and Dynamic{Struct,List} for
// generated Object accessors.
template <>
DynamicStruct::Reader MessageReader::getRoot<DynamicStruct>(
const SchemaPool& pool, uint64_t typeId);
template <>
DynamicStruct::Builder MessageBuilder::initRoot<DynamicStruct>(
const SchemaPool& pool, uint64_t typeId);
template <>
DynamicStruct::Builder MessageBuilder::getRoot<DynamicStruct>(
const SchemaPool& pool, uint64_t typeId);
namespace internal {
template <>
struct PointerHelpers<DynamicStruct, Kind::UNKNOWN> {
static DynamicStruct::Reader get(StructReader reader, WireReferenceCount index,
const SchemaPool& pool, uint64_t typeId);
static DynamicStruct::Builder get(StructBuilder builder, WireReferenceCount index,
const SchemaPool& pool, uint64_t typeId);
static void set(StructBuilder builder, WireReferenceCount index, DynamicStruct::Reader value);
static DynamicStruct::Builder init(StructBuilder builder, WireReferenceCount index,
const SchemaPool& pool, uint64_t typeId);
};
template <>
struct PointerHelpers<DynamicList, Kind::UNKNOWN> {
static DynamicList::Reader get(StructReader reader, WireReferenceCount index,
const SchemaPool& pool, schema::Type::Reader elementType);
static DynamicList::Builder get(StructBuilder builder, WireReferenceCount index,
const SchemaPool& pool, schema::Type::Reader elementType);
static void set(StructBuilder builder, WireReferenceCount index, DynamicList::Reader value);
static DynamicList::Builder init(StructBuilder builder, WireReferenceCount index,
const SchemaPool& pool, schema::Type::Reader elementType,
uint size);
};
} // namespace internal
// =======================================================================================
// Implementation details.
// Inline implementation details.
#define CAPNPROTO_DECLARE_TYPE(name, discrim, typeName) \
inline DynamicValue::Reader::Reader(ReaderFor<typeName> name##Value) \
......@@ -699,11 +797,11 @@ inline DynamicValue::Reader::Reader(ReaderFor<typeName> name##Value) \
inline DynamicValue::Builder::Builder(BuilderFor<typeName> name##Value) \
: type(schema::Type::Body::discrim##_TYPE), name##Value(name##Value) {} \
template <> \
struct DynamicValue::Reader::ToImpl<typeName> { \
struct DynamicValue::Reader::asImpl<typeName> { \
static ReaderFor<typeName> apply(Reader reader); \
}; \
template <> \
struct DynamicValue::Builder::ToImpl<typeName> { \
struct DynamicValue::Builder::asImpl<typeName> { \
static BuilderFor<typeName> apply(Builder builder); \
};
......@@ -735,81 +833,140 @@ inline DynamicValue::Reader::Reader(Void voidValue) \
inline DynamicValue::Builder::Builder(Void voidValue) \
: type(schema::Type::Body::VOID_TYPE), voidValue(voidValue) {} \
template <>
struct DynamicValue::Reader::ToImpl<Void> {
struct DynamicValue::Reader::asImpl<Void> {
static Void apply(Reader reader);
};
template <>
struct DynamicValue::Builder::ToImpl<Void> {
struct DynamicValue::Builder::asImpl<Void> {
static Void apply(Builder builder);
};
template <typename T>
struct DynamicValue::Reader::ToImpl<T, Kind::ENUM> {
struct DynamicValue::Reader::asImpl<T, Kind::ENUM> {
static T apply(Reader reader) {
return reader.to<DynamicEnum>().to<T>();
return reader.as<DynamicEnum>().as<T>();
}
};
template <typename T>
struct DynamicValue::Builder::ToImpl<T, Kind::ENUM> {
struct DynamicValue::Builder::asImpl<T, Kind::ENUM> {
static T apply(Builder builder) {
return builder.to<DynamicEnum>().to<T>();
return builder.as<DynamicEnum>().as<T>();
}
};
template <typename T>
struct DynamicValue::Reader::ToImpl<T, Kind::STRUCT> {
struct DynamicValue::Reader::asImpl<T, Kind::STRUCT> {
static T apply(Reader reader) {
return reader.to<DynamicStruct>().to<T>();
return reader.as<DynamicStruct>().as<T>();
}
};
template <typename T>
struct DynamicValue::Builder::ToImpl<T, Kind::STRUCT> {
struct DynamicValue::Builder::asImpl<T, Kind::STRUCT> {
static T apply(Builder builder) {
return builder.to<DynamicStruct>().to<T>();
return builder.as<DynamicStruct>().as<T>();
}
};
template <typename T>
struct DynamicValue::Reader::ToImpl<T, Kind::LIST> {
struct DynamicValue::Reader::asImpl<T, Kind::LIST> {
static T apply(Reader reader) {
return reader.to<DynamicList>().to<T>();
return reader.as<DynamicList>().as<T>();
}
};
template <typename T>
struct DynamicValue::Builder::ToImpl<T, Kind::LIST> {
struct DynamicValue::Builder::asImpl<T, Kind::LIST> {
static T apply(Builder builder) {
return builder.to<DynamicList>().to<T>();
return builder.as<DynamicList>().as<T>();
}
};
// -------------------------------------------------------------------
template <typename T>
struct DynamicObject::Reader::ToImpl<T, Kind::STRUCT> {
struct DynamicObject::Reader::asImpl<T, Kind::STRUCT> {
static T apply(Reader reader) {
return reader.toStruct(typeId<T>()).to<T>();
return reader.toStruct(typeId<T>()).as<T>();
}
};
template <typename T>
struct DynamicObject::Builder::ToImpl<T, Kind::STRUCT> {
struct DynamicObject::Builder::asImpl<T, Kind::STRUCT> {
static T apply(Builder builder) {
return builder.toStruct(typeId<T>()).to<T>();
return builder.toStruct(typeId<T>()).as<T>();
}
};
template <typename T>
struct DynamicObject::Reader::ToImpl<List<T>, Kind::LIST> {
struct DynamicObject::Reader::asImpl<List<T>, Kind::LIST> {
static T apply(Reader reader) {
return reader.toList(internal::ListSchemaFor<T>::schema).to<T>();
return reader.toList(internal::ListSchemaForElement<T>::schema).as<T>();
}
};
template <typename T>
struct DynamicObject::Builder::ToImpl<List<T>, Kind::LIST> {
struct DynamicObject::Builder::asImpl<List<T>, Kind::LIST> {
static T apply(Builder builder) {
return builder.toList(internal::ListSchemaFor<T>::schema).to<T>();
return builder.toList(internal::ListSchemaForElement<T>::schema).as<T>();
}
};
// -------------------------------------------------------------------
template <typename T>
typename T::Reader DynamicStruct::Reader::as() {
static_assert(kind<T>() == Kind::STRUCT,
"DynamicStruct::Reader::as<T>() can only convert to struct types.");
verifyTypeId(typeId<T>());
return typename T::Reader(reader);
}
template <typename T>
typename T::Builder DynamicStruct::Builder::as() {
static_assert(kind<T>() == Kind::STRUCT,
"DynamicStruct::Builder::as<T>() can only convert to struct types.");
verifyTypeId(typeId<T>());
return typename T::Builder(builder);
}
inline DynamicValue::Reader DynamicStruct::Reader::getField(
schema::StructNode::Field::Reader field) {
return getFieldImpl(pool, reader, field);
}
inline DynamicValue::Builder DynamicStruct::Builder::getField(
schema::StructNode::Field::Reader field) {
return getFieldImpl(pool, builder, field);
}
inline void DynamicStruct::Builder::setField(
schema::StructNode::Field::Reader field, DynamicValue::Reader value) {
return setFieldImpl(pool, builder, field, value);
}
inline DynamicValue::Builder DynamicStruct::Builder::initField(
schema::StructNode::Field::Reader field) {
return initFieldImpl(pool, builder, field);
}
inline DynamicValue::Builder DynamicStruct::Builder::initField(
schema::StructNode::Field::Reader field, uint size) {
return initFieldImpl(pool, builder, field, size);
}
inline DynamicStruct::Reader DynamicStruct::Builder::asReader() {
return DynamicStruct::Reader(pool, schema, builder.asReader());
}
// -------------------------------------------------------------------
template <typename T>
typename T::Reader DynamicList::Reader::as() {
static_assert(kind<T>() == Kind::LIST,
"DynamicStruct::Reader::as<T>() can only convert to list types.");
verifySchema(internal::ListSchemaFor<T>::schema);
return typename T::Reader(reader);
}
template <typename T>
typename T::Builder DynamicList::Builder::as() {
static_assert(kind<T>() == Kind::LIST,
"DynamicStruct::Builder::as<T>() can only convert to list types.");
verifySchema(internal::ListSchemaFor<T>::schema);
return typename T::Builder(builder);
}
} // namespace capnproto
#endif // CAPNPROTO_DYNAMIC_H_
......@@ -31,6 +31,8 @@
namespace capnproto {
class SchemaPool; // Needs to be declared for dynamic Object accessors.
class DynamicStruct; // So that it can be declared a friend.
template <typename T>
......@@ -52,7 +54,7 @@ struct PointerHelpers<T, Kind::STRUCT> {
}
static inline void set(StructBuilder builder, WireReferenceCount index,
typename T::Reader value) {
// TODO(soon)
// TODO(now): schemaless copy
CAPNPROTO_INLINE_PRECOND(false, "Not implemented: set() for struct fields.");
}
static inline typename T::Builder init(StructBuilder builder, WireReferenceCount index) {
......
......@@ -138,7 +138,7 @@ static void setupStruct(StructBuilder builder) {
2 * REFERENCES, 4 * ELEMENTS, STRUCTLIST_ELEMENT_SIZE);
EXPECT_EQ(4 * ELEMENTS, list.size());
for (int i = 0; i < 4; i++) {
StructBuilder element = list.getStructElement(i * ELEMENTS, STRUCTLIST_ELEMENT_SIZE);
StructBuilder element = list.getStructElement(i * ELEMENTS);
element.setDataField<int32_t>(0 * ELEMENTS, 300 + i);
element.initStructField(0 * REFERENCES,
StructSize(1 * WORDS, 0 * REFERENCES, FieldSize::EIGHT_BYTES))
......@@ -193,7 +193,7 @@ static void checkStruct(StructBuilder builder) {
ListBuilder list = builder.getListField(2 * REFERENCES, nullptr);
ASSERT_EQ(4 * ELEMENTS, list.size());
for (int i = 0; i < 4; i++) {
StructBuilder element = list.getStructElement(i * ELEMENTS, STRUCTLIST_ELEMENT_SIZE);
StructBuilder element = list.getStructElement(i * ELEMENTS);
EXPECT_EQ(300 + i, element.getDataField<int32_t>(0 * ELEMENTS));
EXPECT_EQ(400 + i,
element.getStructField(0 * REFERENCES,
......
......@@ -1250,11 +1250,11 @@ Data::Builder ListBuilder::asData() {
return Data::Builder(reinterpret_cast<char*>(ptr), elementCount / ELEMENTS);
}
StructBuilder ListBuilder::getStructElement(ElementCount index, StructSize elementSize) const {
StructBuilder ListBuilder::getStructElement(ElementCount index) const {
BitCount64 indexBit = ElementCount64(index) * step;
byte* structData = ptr + indexBit / BITS_PER_BYTE;
return StructBuilder(segment, structData,
reinterpret_cast<WireReference*>(structData) + elementSize.data / WORDS_PER_REFERENCE,
reinterpret_cast<WireReference*>(structData + structDataSize / BITS_PER_BYTE),
structDataSize, structReferenceCount, indexBit % BITS_PER_BYTE);
}
......@@ -1310,9 +1310,9 @@ Data::Builder ListBuilder::getBlobElement<Data>(ElementCount index) const {
0 * BYTES);
}
ObjectBuilder ListBuilder::getObjectElement(ElementCount index, const word* defaultValue) const {
ObjectBuilder ListBuilder::getObjectElement(ElementCount index) const {
return WireHelpers::getWritableObjectReference(
segment, reinterpret_cast<WireReference*>(ptr + index * step / BITS_PER_BYTE), defaultValue);
segment, reinterpret_cast<WireReference*>(ptr + index * step / BITS_PER_BYTE), nullptr);
}
ListReader ListBuilder::asReader() const {
......@@ -1403,9 +1403,9 @@ Data::Reader ListReader::getBlobElement<Data>(ElementCount index) const {
nullptr, 0 * BYTES);
}
ObjectReader ListReader::getObjectElement(ElementCount index, const word* defaultValue) const {
ObjectReader ListReader::getObjectElement(ElementCount index) const {
return WireHelpers::readObjectReference(
segment, checkAlignment(ptr + index * step / BITS_PER_BYTE), defaultValue, nestingLimit);
segment, checkAlignment(ptr + index * step / BITS_PER_BYTE), nullptr, nestingLimit);
}
} // namespace internal
......
......@@ -502,7 +502,7 @@ public:
ElementCount index, typename NoInfer<T>::Type value) const);
// Set the element at the given index.
StructBuilder getStructElement(ElementCount index, StructSize elementSize) const;
StructBuilder getStructElement(ElementCount index) const;
// Get the struct element at the given index.
ListBuilder initListElement(
......@@ -532,7 +532,7 @@ public:
typename T::Builder getBlobElement(ElementCount index) const;
// Get the blob element. If it is not initialized, return an empty blob builder.
ObjectBuilder getObjectElement(ElementCount index, const word* defaultValue) const;
ObjectBuilder getObjectElement(ElementCount index) const;
// Gets a pointer element of arbitrary type.
ListReader asReader() const;
......@@ -591,7 +591,7 @@ public:
typename T::Reader getBlobElement(ElementCount index) const;
// Gets the text or data field. If it is not initialized, returns an empty blob reader.
ObjectReader getObjectElement(ElementCount index, const word* defaultValue) const;
ObjectReader getObjectElement(ElementCount index) const;
// Gets a pointer element of arbitrary type.
private:
......
......@@ -297,8 +297,7 @@ struct List<T, Kind::STRUCT> {
inline uint size() const { return builder.size() / ELEMENTS; }
inline typename T::Builder operator[](uint index) const {
return typename T::Builder(builder.getStructElement(
index * ELEMENTS, internal::structSize<T>()));
return typename T::Builder(builder.getStructElement(index * ELEMENTS));
}
typedef internal::IndexingIterator<Builder, typename T::Builder> iterator;
......
......@@ -49,7 +49,7 @@ internal::StructReader MessageReader::getRootInternal() {
allocatedArena = true;
}
internal::SegmentReader* segment = arena()->tryGetSegment(SegmentId(0));
internal::SegmentReader* segment = arena()->tryGetSegment(internal::SegmentId(0));
VALIDATE_INPUT(segment != nullptr &&
segment->containsInterval(segment->getStartPtr(), segment->getStartPtr() + 1),
"Message did not contain a root pointer.") {
......@@ -70,7 +70,7 @@ MessageBuilder::~MessageBuilder() {
internal::SegmentBuilder* MessageBuilder::getRootSegment() {
if (allocatedArena) {
return arena()->getSegment(SegmentId(0));
return arena()->getSegment(internal::SegmentId(0));
} else {
static_assert(sizeof(internal::BuilderArena) <= sizeof(arenaSpace),
"arenaSpace is too small to hold a BuilderArena. Please increase it. This will break "
......@@ -80,7 +80,7 @@ internal::SegmentBuilder* MessageBuilder::getRootSegment() {
WordCount refSize = 1 * REFERENCES * WORDS_PER_REFERENCE;
internal::SegmentBuilder* segment = arena()->getSegmentWithAvailable(refSize);
CHECK(segment->getSegmentId() == SegmentId(0),
CHECK(segment->getSegmentId() == internal::SegmentId(0),
"First allocated word of new arena was not in segment ID 0.");
word* location = segment->allocate(refSize);
CHECK(location == segment->getPtrUnchecked(0 * WORDS),
......
......@@ -37,8 +37,7 @@ namespace internal {
class BuilderArena;
}
class Segment;
typedef Id<uint32_t, Segment> SegmentId;
class SchemaPool;
// =======================================================================================
......@@ -97,6 +96,13 @@ public:
template <typename RootType>
typename RootType::Reader getRoot();
// Get the root struct of the message, interpreting it as the given struct type.
template <typename RootType>
typename RootType::Reader getRoot(const SchemaPool& pool, uint64_t typeId);
// Dynamically interpret the root struct of the message using the type with the given ID.
// RootType in this case must be DynamicStruct, and you must #include <capnproto/dynamic.h> to
// use this.
private:
ReaderOptions options;
......@@ -125,8 +131,23 @@ public:
template <typename RootType>
typename RootType::Builder initRoot();
// Initialize the root struct of the message as the given struct type.
template <typename RootType>
typename RootType::Builder getRoot();
// Get the root struct of the message, interpreting it as the given struct type.
template <typename RootType>
typename RootType::Builder getRoot(const SchemaPool& pool, uint64_t typeId);
// Dynamically interpret the root struct of the message using the type with the given ID.
// RootType in this case must be DynamicStruct, and you must #include <capnproto/dynamic.h> to
// use this.
template <typename RootType>
typename RootType::Builder initRoot(const SchemaPool& pool, uint64_t typeId);
// Dynamically init the root struct of the message using the type with the given ID.
// RootType in this case must be DynamicStruct, and you must #include <capnproto/dynamic.h> to
// use this.
ArrayPtr<const ArrayPtr<const word>> getSegmentsForOutput();
......@@ -270,16 +291,19 @@ inline const ReaderOptions& MessageReader::getOptions() {
template <typename RootType>
inline typename RootType::Reader MessageReader::getRoot() {
static_assert(kind<RootType>() == Kind::STRUCT, "Root type must be a Cap'n Proto struct type.");
return typename RootType::Reader(getRootInternal());
}
template <typename RootType>
inline typename RootType::Builder MessageBuilder::initRoot() {
static_assert(kind<RootType>() == Kind::STRUCT, "Root type must be a Cap'n Proto struct type.");
return typename RootType::Builder(initRoot(internal::structSize<RootType>()));
}
template <typename RootType>
inline typename RootType::Builder MessageBuilder::getRoot() {
static_assert(kind<RootType>() == Kind::STRUCT, "Root type must be a Cap'n Proto struct type.");
return typename RootType::Builder(getRoot(internal::structSize<RootType>()));
}
......
......@@ -219,6 +219,11 @@ struct StructNode {
}
struct Field {
index @3 :UInt16;
# The index of this field within the containing struct or union's member list. This is
# redundant information, but it can be useful for the dynamic API which uses Field pointers as
# identifiers.
offset @0 :UInt32;
# Offset, in units of the field's size, from the beginning of the section in which the field
# resides. E.g. for a UInt32 field, multiply this by 4 to get the byte offset from the
......
......@@ -575,7 +575,7 @@ encodeSchema requestedFiles allFiles = encRoot where
, (16, encUInt16 $ structPointerCount desc)
, (32, encUInt16 (fieldSizeEnum preferredListEncoding::Word16))
]
ptrValues = [ (0, encStructList memberSize $ map encMember $
ptrValues = [ (0, encStructList memberSize $ zipWith encMember [0::Word16 ..] $
sortMembers $ structMembers desc) ]
preferredListEncoding = case (structDataSize desc, structPointerCount desc) of
......@@ -597,7 +597,7 @@ encodeSchema requestedFiles allFiles = encRoot where
selectFieldOrUnion _ = Nothing
memberSize = (DataSectionWords 1, 3)
encMember (codeOrder, (_, DescField field)) = (dataValues2, ptrValues2) where
encMember index (codeOrder, (_, DescField field)) = (dataValues2, ptrValues2) where
dataValues2 = [ (0, encUInt16 $ fieldNumber field)
, (16, encUInt16 codeOrder)
, (32, encUInt16 (0::Word16)) -- discriminant
......@@ -608,7 +608,8 @@ encodeSchema requestedFiles allFiles = encRoot where
]
-- StructNode.Field
dataValues3 = [ (0, encUInt32 $ offsetToInt $ fieldOffset field) ]
dataValues3 = [ (0, encUInt32 $ offsetToInt $ fieldOffset field)
, (32, encUInt16 index) ]
ptrValues3 = [ (0, encStruct typeSize $ encType $ fieldType field)
, (1, encStruct valueSize $ encValue (fieldType field) $
fieldDefaultValue field)
......@@ -620,7 +621,7 @@ encodeSchema requestedFiles allFiles = encRoot where
offsetToInt (InlineCompositeOffset {}) =
error "Inline types not currently supported by codegen plugins."
encMember (codeOrder, (_, DescUnion union)) = (dataValues2, ptrValues2) where
encMember _ (codeOrder, (_, DescUnion union)) = (dataValues2, ptrValues2) where
dataValues2 = [ (0, encUInt16 $ unionNumber union)
, (16, encUInt16 codeOrder)
, (32, encUInt16 (1::Word16)) -- discriminant
......@@ -632,9 +633,9 @@ encodeSchema requestedFiles allFiles = encRoot where
-- StructNode.Union
dataValues3 = [ (0, encUInt32 $ unionTagOffset union) ]
ptrValues3 = [ (0, encStructList memberSize $ map encMember $ sortMembers $
ptrValues3 = [ (0, encStructList memberSize $ zipWith encMember [0..] $ sortMembers $
unionMembers union) ]
encMember _ = error "Not a field or union?"
encMember _ _ = error "Not a field or union?"
enumNodeSize = (DataSectionWords 0, 1)
encEnumNode desc = (dataValues, ptrValues) where
......
......@@ -157,6 +157,8 @@ public:
{{/fieldIsPrimitive}}
{{#fieldIsGenericObject}}
template <typename T> inline typename T::Reader get{{fieldTitleCase}}();
template <typename T, typename... Params> inline typename T::Reader get{{fieldTitleCase}}(
const ::capnproto::SchemaPool& pool, Params&&... params);
{{/fieldIsGenericObject}}
{{/typeFields}}
private:
......@@ -209,6 +211,11 @@ public:
template <typename T> inline void set{{fieldTitleCase}}(typename T::Reader value);
template <typename T> inline typename T::Builder init{{fieldTitleCase}}();
template <typename T> inline typename T::Builder init{{fieldTitleCase}}(unsigned int size);
template <typename T, typename... Params> inline typename T::Builder get{{fieldTitleCase}}(
const ::capnproto::SchemaPool& pool, Params&&... params);
template <typename T, typename... Params> inline typename T::Builder init{{fieldTitleCase}}(
const ::capnproto::SchemaPool& pool, Params&&... params);
{{/fieldIsGenericObject}}
{{/typeFields}}
private:
......@@ -394,6 +401,42 @@ inline typename T::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}(uns
_builder, {{fieldOffset}} * ::capnproto::REFERENCES, size);
}
template <typename T, typename... Params>
inline typename T::Reader {{typeFullName}}::Reader::get{{fieldTitleCase}}(
const ::capnproto::SchemaPool& pool, Params&&... params) {
{{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
"Must check which() before get()ing a union member.");
{{/fieldUnion}}
return ::capnproto::internal::PointerHelpers<T>::get(
_reader, {{fieldOffset}} * ::capnproto::REFERENCES,
pool, ::capnproto::forward<Params>(params)...);
}
template <typename T, typename... Params>
inline typename T::Builder {{typeFullName}}::Builder::get{{fieldTitleCase}}(
const ::capnproto::SchemaPool& pool, Params&&... params) {
{{#fieldUnion}}
CAPNPROTO_INLINE_DPRECOND(which() == {{unionTitleCase}}::{{fieldUpperCase}},
"Must check which() before get()ing a union member.");
{{/fieldUnion}}
return ::capnproto::internal::PointerHelpers<T>::get(
_builder, {{fieldOffset}} * ::capnproto::REFERENCES,
pool, ::capnproto::forward<Params>(params)...);
}
template <typename T, typename... Params>
inline typename T::Builder {{typeFullName}}::Builder::init{{fieldTitleCase}}(
const ::capnproto::SchemaPool& pool, Params&&... params) {
{{#fieldUnion}}
_builder.setDataField<{{unionTitleCase}}::Which>(
{{unionTagOffset}} * ::capnproto::ELEMENTS, {{unionTitleCase}}::{{fieldUpperCase}});
{{/fieldUnion}}
return ::capnproto::internal::PointerHelpers<T>::init(
_builder, {{fieldOffset}} * ::capnproto::REFERENCES,
pool, ::capnproto::forward<Params>(params)...);
}
{{/fieldIsGenericObject}}
{{/typeFields}}
{{/typeStructOrUnion}}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment