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) { ...@@ -114,9 +114,9 @@ void dynamicInitTestMessage(DynamicStruct::Builder builder) {
listBuilder[1].as<DynamicStruct>().set("textField", "x structlist 2"); listBuilder[1].as<DynamicStruct>().set("textField", "x structlist 2");
listBuilder[2].as<DynamicStruct>().set("textField", "x structlist 3"); 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.init("voidList", 6);
builder.set("boolList", {true, false, false, true}); builder.set("boolList", {true, false, false, true});
......
...@@ -775,11 +775,24 @@ void DynamicStruct::Builder::setImpl( ...@@ -775,11 +775,24 @@ void DynamicStruct::Builder::setImpl(
#undef HANDLE_TYPE #undef HANDLE_TYPE
case schema::Type::Body::ENUM_TYPE: case schema::Type::Body::ENUM_TYPE: {
builder.setDataField<uint16_t>( uint16_t rawValue;
field.getOffset() * ELEMENTS, value.as<DynamicEnum>().getRaw(), auto enumSchema = member.getContainingStruct().getDependency(type.getEnumType()).asEnum();
dval.getEnumValue()); 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; return;
}
case schema::Type::Body::TEXT_TYPE: case schema::Type::Body::TEXT_TYPE:
builder.setBlobField<Text>(field.getOffset() * REFERENCES, value.as<Text>()); builder.setBlobField<Text>(field.getOffset() * REFERENCES, value.as<Text>());
...@@ -1066,12 +1079,19 @@ void DynamicList::Builder::set(uint index, DynamicValue::Reader value) { ...@@ -1066,12 +1079,19 @@ void DynamicList::Builder::set(uint index, DynamicValue::Reader value) {
break; break;
case schema::Type::Body::ENUM_TYPE: { case schema::Type::Body::ENUM_TYPE: {
auto enumValue = value.as<DynamicEnum>(); uint16_t rawValue;
RECOVERABLE_PRECOND(schema.getEnumElementType() == enumValue.getSchema(), if (value.getType() == DynamicValue::TEXT) {
"Type mismatch when using DynamicList::Builder::set().") { // Convert from text.
return; 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; break;
} }
......
...@@ -537,7 +537,7 @@ public: ...@@ -537,7 +537,7 @@ public:
// - DynamicEnum, DynamicObject: Returns the corresponding type. // - DynamicEnum, DynamicObject: Returns the corresponding type.
// - DynamicStruct, DynamicList, DynamicUnion: Returns the corresponding Reader. // - 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 // - Any integer can be converted to any other integer type so long as the actual value is within
// the new type's range. // the new type's range.
// - Floating-point types can be converted to integers as long as no information would be lost // - Floating-point types can be converted to integers as long as no information would be lost
...@@ -546,6 +546,8 @@ public: ...@@ -546,6 +546,8 @@ public:
// - Float32/Float64 can be converted between each other. Converting Float64 -> Float32 may lose // - Float32/Float64 can be converted between each other. Converting Float64 -> Float32 may lose
// information, but won't throw. // information, but won't throw.
// - Text can be converted to Data (but not vice-versa). // - 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. // Any other conversion attempt will throw an exception.
......
...@@ -12,6 +12,8 @@ messages backed by fast pointer arithmetic. ...@@ -12,6 +12,8 @@ messages backed by fast pointer arithmetic.
For the Cap'n Proto definition: For the Cap'n Proto definition:
{% highlight capnp %} {% highlight capnp %}
@0x9eb32e19f86ee174;
struct Person { struct Person {
id @0 :UInt32; id @0 :UInt32;
name @1 :Text; name @1 :Text;
...@@ -357,6 +359,18 @@ so: ...@@ -357,6 +359,18 @@ so:
As of this writing, the file is not automatically installed anywhere, but in the future it will As of this writing, the file is not automatically installed anywhere, but in the future it will
be. 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 ## Reference
The runtime library contains lots of useful features not described on this page. For now, the 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: ...@@ -365,8 +379,11 @@ best reference is the header files. See:
capnproto/list.h capnproto/list.h
capnproto/blob.h capnproto/blob.h
capnproto/io.h capnproto/io.h
capnproto/message.h
capnproto/serialized.h capnproto/serialized.h
capnproto/serialized-packed.h capnproto/serialized-packed.h
capnproto/schema.h
capnproto/dynamic.h
## Lessons Learned from Protocol Buffers ## 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