Commit 150ce1b6 authored by Kenton Varda's avatar Kenton Varda

Allow dynamically setting enum values using text literals.

parent f4d98110
......@@ -114,9 +114,9 @@ void dynamicInitTestMessage(DynamicStruct::Builder builder) {
listBuilder[1].as<DynamicStruct>().set("textField", "x structlist 2");
listBuilder[2].as<DynamicStruct>().set("textField", "x structlist 3");
}
subBuilder.set("enumList", {TestEnum::QUX, TestEnum::BAR, TestEnum::GRAULT});
subBuilder.set("enumList", {TestEnum::QUX, "bar", "grault"});
}
builder.set("enumField", TestEnum::CORGE);
builder.set("enumField", "corge");
builder.init("voidList", 6);
builder.set("boolList", {true, false, false, true});
......
......@@ -775,11 +775,24 @@ void DynamicStruct::Builder::setImpl(
#undef HANDLE_TYPE
case schema::Type::Body::ENUM_TYPE:
builder.setDataField<uint16_t>(
field.getOffset() * ELEMENTS, value.as<DynamicEnum>().getRaw(),
dval.getEnumValue());
case schema::Type::Body::ENUM_TYPE: {
uint16_t rawValue;
auto enumSchema = member.getContainingStruct().getDependency(type.getEnumType()).asEnum();
if (value.getType() == DynamicValue::TEXT) {
// Convert from text.
rawValue = enumSchema.getEnumerantByName(value.as<Text>()).getOrdinal();
} else {
DynamicEnum enumValue = value.as<DynamicEnum>();
RECOVERABLE_PRECOND(enumValue.getSchema() == enumSchema,
"Type mismatch when using DynamicList::Builder::set().") {
return;
}
rawValue = enumValue.getRaw();
}
builder.setDataField<uint16_t>(field.getOffset() * ELEMENTS, rawValue,
dval.getEnumValue());
return;
}
case schema::Type::Body::TEXT_TYPE:
builder.setBlobField<Text>(field.getOffset() * REFERENCES, value.as<Text>());
......@@ -1066,12 +1079,19 @@ void DynamicList::Builder::set(uint index, DynamicValue::Reader value) {
break;
case schema::Type::Body::ENUM_TYPE: {
auto enumValue = value.as<DynamicEnum>();
RECOVERABLE_PRECOND(schema.getEnumElementType() == enumValue.getSchema(),
"Type mismatch when using DynamicList::Builder::set().") {
return;
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>();
RECOVERABLE_PRECOND(schema.getEnumElementType() == enumValue.getSchema(),
"Type mismatch when using DynamicList::Builder::set().") {
return;
}
rawValue = enumValue.getRaw();
}
builder.setDataElement<uint16_t>(index * ELEMENTS, value.as<DynamicEnum>().getRaw());
builder.setDataElement<uint16_t>(index * ELEMENTS, rawValue);
break;
}
......
......@@ -537,7 +537,7 @@ public:
// - DynamicEnum, DynamicObject: Returns the corresponding type.
// - DynamicStruct, DynamicList, DynamicUnion: Returns the corresponding Reader.
//
// DynamicValue allows various implicit conversions:
// DynamicValue allows various implicit conversions, mostly just to make the interface friendlier.
// - Any integer can be converted to any other integer type so long as the actual value is within
// the new type's range.
// - Floating-point types can be converted to integers as long as no information would be lost
......@@ -546,6 +546,8 @@ public:
// - Float32/Float64 can be converted between each other. Converting Float64 -> Float32 may lose
// information, but won't throw.
// - Text can be converted to Data (but not vice-versa).
// - Text can be converted to an enum, if the Text matches one of the enumerant names (but not
// vice-versa).
//
// Any other conversion attempt will throw an exception.
......
......@@ -12,6 +12,8 @@ messages backed by fast pointer arithmetic.
For the Cap'n Proto definition:
{% highlight capnp %}
@0x9eb32e19f86ee174;
struct Person {
id @0 :UInt32;
name @1 :Text;
......@@ -357,6 +359,18 @@ so:
As of this writing, the file is not automatically installed anywhere, but in the future it will
be.
## Dynamic Reflection
Sometimes you want to write generic code that operates on arbitrary types, iterating over the
fields or looking them up by name. For example, you might want to write code that encodes
arbitrary Cap'n Proto types in JSON format. This requires something like "reflection", but C++
does not offer reflection. Also, you might even want to operate on types that aren't compiled
into the binary at all, but only discovered at runtime.
The C++ API supports inspecting schemas at runtime via the interface defined in
`capnproto/schema.h`, and dynamically reading and writing instances of arbitrary types via
`capnproto/dynamic.h`. Here's the example from the beginning of this file written in
## Reference
The runtime library contains lots of useful features not described on this page. For now, the
......@@ -365,8 +379,11 @@ best reference is the header files. See:
capnproto/list.h
capnproto/blob.h
capnproto/io.h
capnproto/message.h
capnproto/serialized.h
capnproto/serialized-packed.h
capnproto/schema.h
capnproto/dynamic.h
## Lessons Learned from Protocol Buffers
......
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