Commit 07b979a3 authored by Kenton Varda's avatar Kenton Varda

Test Dynamic API.

parent 08d73bef
......@@ -49,6 +49,8 @@ includecapnp_HEADERS = \
src/capnproto/layout.h \
src/capnproto/list.h \
src/capnproto/message.h \
src/capnproto/schema.h \
src/capnproto/dynamic.h \
src/capnproto/io.h \
src/capnproto/serialize.h \
src/capnproto/serialize-packed.h \
......@@ -73,6 +75,8 @@ libcapnproto_a_SOURCES= \
src/capnproto/layout.c++ \
src/capnproto/list.c++ \
src/capnproto/message.c++ \
src/capnproto/schema.c++ \
src/capnproto/dynamic.c++ \
src/capnproto/io.c++ \
src/capnproto/serialize.c++ \
src/capnproto/serialize-packed.c++
......@@ -117,6 +121,8 @@ capnproto_test_SOURCES = \
src/capnproto/logging-test.c++ \
src/capnproto/layout-test.c++ \
src/capnproto/message-test.c++ \
src/capnproto/schema-test.c++ \
src/capnproto/dynamic-test.c++ \
src/capnproto/encoding-test.c++ \
src/capnproto/serialize-test.c++ \
src/capnproto/serialize-packed-test.c++ \
......
......@@ -55,7 +55,7 @@ namespace capnproto {
namespace internal {
namespace {
void dynamicInitTestmessage(DynamicStruct::Builder builder) {
void dynamicInitTestMessage(DynamicStruct::Builder builder) {
builder.set("voidField", Void::VOID);
builder.set("boolField", true);
builder.set("int8Field", -123);
......@@ -68,8 +68,8 @@ void dynamicInitTestmessage(DynamicStruct::Builder builder) {
builder.set("uInt64Field", 12345678901234567890ull);
builder.set("float32Field", 1234.5);
builder.set("float64Field", -123e45);
builder.set("textField", Text::Reader("foo"));
builder.set("dataField", Data::Reader("bar"));
builder.set("textField", "foo");
builder.set("dataField", "bar");
{
auto subBuilder = builder.init("structField").as<DynamicStruct>();
subBuilder.set("voidField", Void::VOID);
......@@ -84,14 +84,14 @@ void dynamicInitTestmessage(DynamicStruct::Builder builder) {
subBuilder.set("uInt64Field", 345678901234567890ull);
subBuilder.set("float32Field", -1.25e-10);
subBuilder.set("float64Field", 345);
subBuilder.set("textField", Text::Reader("baz"));
subBuilder.set("dataField", Data::Reader("qux"));
subBuilder.set("textField", "baz");
subBuilder.set("dataField", "qux");
{
auto subSubBuilder = subBuilder.init("structField").as<DynamicStruct>();
subSubBuilder.set("textField", Text::Reader("nested"));
subSubBuilder.init("structField").as<DynamicStruct>().set("textField", Text::Reader("really nested"));
subSubBuilder.set("textField", "nested");
subSubBuilder.init("structField").as<DynamicStruct>().set("textField", "really nested");
}
subBuilder.set("enumField", toDynamic(TestEnum::BAZ));
subBuilder.set("enumField", TestEnum::BAZ);
subBuilder.set("voidList", {Void::VOID, Void::VOID, Void::VOID});
subBuilder.set("boolList", {false, true, false, true, true});
......@@ -106,19 +106,17 @@ void dynamicInitTestmessage(DynamicStruct::Builder builder) {
subBuilder.set("uInt64List", {123456789012345ull, 678901234567890ull, 0ull, 0xffffffffffffffffull});
subBuilder.set("float32List", {0, 1234567, 1e37, -1e37, 1e-37, -1e-37});
subBuilder.set("float64List", {0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306});
subBuilder.set("textList", {Text::Reader("quux"), Text::Reader("corge"), Text::Reader("grault")});
subBuilder.set("dataList", {Data::Reader("garply"), Data::Reader("waldo"), Data::Reader("fred")});
subBuilder.set("textList", {"quux", "corge", "grault"});
subBuilder.set("dataList", {"garply", "waldo", "fred"});
{
auto listBuilder = subBuilder.init("structList", 3).as<DynamicList>();
listBuilder[0].as<DynamicStruct>().set("textField", Text::Reader("x structlist 1"));
listBuilder[1].as<DynamicStruct>().set("textField", Text::Reader("x structlist 2"));
listBuilder[2].as<DynamicStruct>().set("textField", Text::Reader("x structlist 3"));
listBuilder[0].as<DynamicStruct>().set("textField", "x structlist 1");
listBuilder[1].as<DynamicStruct>().set("textField", "x structlist 2");
listBuilder[2].as<DynamicStruct>().set("textField", "x structlist 3");
}
subBuilder.set("enumList", {toDynamic(TestEnum::QUX),
toDynamic(TestEnum::BAR),
toDynamic(TestEnum::GRAULT)});
subBuilder.set("enumList", {TestEnum::QUX, TestEnum::BAR, TestEnum::GRAULT});
}
builder.set("enumField", toDynamic(TestEnum::CORGE));
builder.set("enumField", TestEnum::CORGE);
builder.init("voidList", 6);
builder.set("boolList", {true, false, false, true});
......@@ -138,23 +136,584 @@ void dynamicInitTestmessage(DynamicStruct::Builder builder) {
std::numeric_limits<double>::infinity(),
-std::numeric_limits<double>::infinity(),
std::numeric_limits<double>::quiet_NaN()});
builder.set("textList", {Text::Reader("plugh"), Text::Reader("xyzzy"), Text::Reader("thud")});
builder.set("dataList", {Data::Reader("oops"), Data::Reader("exhausted"), Data::Reader("rfc3092")});
builder.set("textList", {"plugh", "xyzzy", "thud"});
builder.set("dataList", {"oops", "exhausted", "rfc3092"});
{
auto listBuilder = builder.init("structList", 3).as<DynamicList>();
listBuilder[0].as<DynamicStruct>().set("textField", Text::Reader("structlist 1"));
listBuilder[1].as<DynamicStruct>().set("textField", Text::Reader("structlist 2"));
listBuilder[2].as<DynamicStruct>().set("textField", Text::Reader("structlist 3"));
listBuilder[0].as<DynamicStruct>().set("textField", "structlist 1");
listBuilder[1].as<DynamicStruct>().set("textField", "structlist 2");
listBuilder[2].as<DynamicStruct>().set("textField", "structlist 3");
}
builder.set("enumList", {toDynamic(TestEnum::FOO), toDynamic(TestEnum::GARPLY)});
builder.set("enumList", {TestEnum::FOO, TestEnum::GARPLY});
}
TEST(DynamicApi, Struct) {
template <typename T> void expectPrimitiveEq(T a, T b) { EXPECT_EQ(a, b); }
void expectPrimitiveEq(float a, float b) { EXPECT_FLOAT_EQ(a, b); }
void expectPrimitiveEq(double a, double b) { EXPECT_DOUBLE_EQ(a, b); }
void expectPrimitiveEq(Text::Reader a, Text::Builder b) { EXPECT_EQ(a, b); }
void expectPrimitiveEq(Data::Reader a, Data::Builder b) { EXPECT_EQ(a, b); }
// Hack because as<>() is a template-parameter-dependent lookup everywhere below...
#define as template as
template <typename Element, typename T>
void checkList(T reader, std::initializer_list<ReaderFor<Element>> expected) {
auto list = reader.as<DynamicList>();
ASSERT_EQ(expected.size(), list.size());
for (uint i = 0; i < expected.size(); i++) {
expectPrimitiveEq(expected.begin()[i], list[i].as<Element>());
}
auto typed = reader.as<List<Element>>();
ASSERT_EQ(expected.size(), typed.size());
for (uint i = 0; i < expected.size(); i++) {
expectPrimitiveEq(expected.begin()[i], typed[i]);
}
}
inline bool isNaN(float f) { return f != f; }
inline bool isNaN(double f) { return f != f; }
template <typename Reader>
void dynamicCheckTestMessage(Reader reader) {
EXPECT_EQ(Void::VOID, reader.get("voidField").as<Void>());
EXPECT_EQ(true, reader.get("boolField").as<bool>());
EXPECT_EQ(-123, reader.get("int8Field").as<int8_t>());
EXPECT_EQ(-12345, reader.get("int16Field").as<int16_t>());
EXPECT_EQ(-12345678, reader.get("int32Field").as<int32_t>());
EXPECT_EQ(-123456789012345ll, reader.get("int64Field").as<int64_t>());
EXPECT_EQ(234u, reader.get("uInt8Field").as<uint8_t>());
EXPECT_EQ(45678u, reader.get("uInt16Field").as<uint16_t>());
EXPECT_EQ(3456789012u, reader.get("uInt32Field").as<uint32_t>());
EXPECT_EQ(12345678901234567890ull, reader.get("uInt64Field").as<uint64_t>());
EXPECT_FLOAT_EQ(1234.5f, reader.get("float32Field").as<float>());
EXPECT_DOUBLE_EQ(-123e45, reader.get("float64Field").as<double>());
EXPECT_EQ("foo", reader.get("textField").as<Text>());
EXPECT_EQ("bar", reader.get("dataField").as<Data>());
{
auto subReader = reader.get("structField").as<DynamicStruct>();
EXPECT_EQ(Void::VOID, subReader.get("voidField").as<Void>());
EXPECT_EQ(true, subReader.get("boolField").as<bool>());
EXPECT_EQ(-12, subReader.get("int8Field").as<int8_t>());
EXPECT_EQ(3456, subReader.get("int16Field").as<int16_t>());
EXPECT_EQ(-78901234, subReader.get("int32Field").as<int32_t>());
EXPECT_EQ(56789012345678ll, subReader.get("int64Field").as<int64_t>());
EXPECT_EQ(90u, subReader.get("uInt8Field").as<uint8_t>());
EXPECT_EQ(1234u, subReader.get("uInt16Field").as<uint16_t>());
EXPECT_EQ(56789012u, subReader.get("uInt32Field").as<uint32_t>());
EXPECT_EQ(345678901234567890ull, subReader.get("uInt64Field").as<uint64_t>());
EXPECT_FLOAT_EQ(-1.25e-10f, subReader.get("float32Field").as<float>());
EXPECT_DOUBLE_EQ(345, subReader.get("float64Field").as<double>());
EXPECT_EQ("baz", subReader.get("textField").as<Text>());
EXPECT_EQ("qux", subReader.get("dataField").as<Data>());
{
auto subSubReader = subReader.get("structField").as<DynamicStruct>();
EXPECT_EQ("nested", subSubReader.get("textField").as<Text>());
EXPECT_EQ("really nested", subSubReader.get("structField").as<DynamicStruct>()
.get("textField").as<Text>());
}
EXPECT_EQ(TestEnum::BAZ, subReader.get("enumField").as<TestEnum>());
checkList<Void>(subReader.get("voidList"), {Void::VOID, Void::VOID, Void::VOID});
checkList<bool>(subReader.get("boolList"), {false, true, false, true, true});
checkList<int8_t>(subReader.get("int8List"), {12, -34, -0x80, 0x7f});
checkList<int16_t>(subReader.get("int16List"), {1234, -5678, -0x8000, 0x7fff});
checkList<int32_t>(subReader.get("int32List"), {12345678, -90123456, -0x8000000, 0x7ffffff});
// gcc warns on -0x800...ll and the only work-around I could find was to do -0x7ff...ll-1.
checkList<int64_t>(subReader.get("int64List"), {123456789012345ll, -678901234567890ll, -0x7fffffffffffffffll-1, 0x7fffffffffffffffll});
checkList<uint8_t>(subReader.get("uInt8List"), {12u, 34u, 0u, 0xffu});
checkList<uint16_t>(subReader.get("uInt16List"), {1234u, 5678u, 0u, 0xffffu});
checkList<uint32_t>(subReader.get("uInt32List"), {12345678u, 90123456u, 0u, 0xffffffffu});
checkList<uint64_t>(subReader.get("uInt64List"), {123456789012345ull, 678901234567890ull, 0ull, 0xffffffffffffffffull});
checkList<float>(subReader.get("float32List"), {0.0f, 1234567.0f, 1e37f, -1e37f, 1e-37f, -1e-37f});
checkList<double>(subReader.get("float64List"), {0.0, 123456789012345.0, 1e306, -1e306, 1e-306, -1e-306});
checkList<Text>(subReader.get("textList"), {"quux", "corge", "grault"});
checkList<Data>(subReader.get("dataList"), {"garply", "waldo", "fred"});
{
auto listReader = subReader.get("structList").as<DynamicList>();
ASSERT_EQ(3u, listReader.size());
EXPECT_EQ("x structlist 1", listReader[0].as<DynamicStruct>().get("textField").as<Text>());
EXPECT_EQ("x structlist 2", listReader[1].as<DynamicStruct>().get("textField").as<Text>());
EXPECT_EQ("x structlist 3", listReader[2].as<DynamicStruct>().get("textField").as<Text>());
}
checkList<TestEnum>(subReader.get("enumList"), {TestEnum::QUX, TestEnum::BAR, TestEnum::GRAULT});
}
EXPECT_EQ(TestEnum::CORGE, reader.get("enumField").as<TestEnum>());
EXPECT_EQ(6u, reader.get("voidList").as<DynamicList>().size());
checkList<bool>(reader.get("boolList"), {true, false, false, true});
checkList<int8_t>(reader.get("int8List"), {111, -111});
checkList<int16_t>(reader.get("int16List"), {11111, -11111});
checkList<int32_t>(reader.get("int32List"), {111111111, -111111111});
checkList<int64_t>(reader.get("int64List"), {1111111111111111111ll, -1111111111111111111ll});
checkList<uint8_t>(reader.get("uInt8List"), {111u, 222u});
checkList<uint16_t>(reader.get("uInt16List"), {33333u, 44444u});
checkList<uint32_t>(reader.get("uInt32List"), {3333333333u});
checkList<uint64_t>(reader.get("uInt64List"), {11111111111111111111ull});
{
auto listReader = reader.get("float32List").as<DynamicList>();
ASSERT_EQ(4u, listReader.size());
EXPECT_EQ(5555.5f, listReader[0].as<float>());
EXPECT_EQ(std::numeric_limits<float>::infinity(), listReader[1].as<float>());
EXPECT_EQ(-std::numeric_limits<float>::infinity(), listReader[2].as<float>());
EXPECT_TRUE(isNaN(listReader[3].as<float>()));
}
{
auto listReader = reader.get("float64List").as<DynamicList>();
ASSERT_EQ(4u, listReader.size());
EXPECT_EQ(7777.75, listReader[0].as<double>());
EXPECT_EQ(std::numeric_limits<double>::infinity(), listReader[1].as<double>());
EXPECT_EQ(-std::numeric_limits<double>::infinity(), listReader[2].as<double>());
EXPECT_TRUE(isNaN(listReader[3].as<double>()));
}
checkList<Text>(reader.get("textList"), {"plugh", "xyzzy", "thud"});
checkList<Data>(reader.get("dataList"), {"oops", "exhausted", "rfc3092"});
{
auto listReader = reader.get("structList").as<DynamicList>();
ASSERT_EQ(3u, listReader.size());
EXPECT_EQ("structlist 1", listReader[0].as<DynamicStruct>().get("textField").as<Text>());
EXPECT_EQ("structlist 2", listReader[1].as<DynamicStruct>().get("textField").as<Text>());
EXPECT_EQ("structlist 3", listReader[2].as<DynamicStruct>().get("textField").as<Text>());
}
checkList<TestEnum>(reader.get("enumList"), {TestEnum::FOO, TestEnum::GARPLY});
}
template <typename Reader>
void dynamicCheckTestMessageAllZero(Reader reader) {
EXPECT_EQ(Void::VOID, reader.get("voidField").as<Void>());
EXPECT_EQ(false, reader.get("boolField").as<bool>());
EXPECT_EQ(0, reader.get("int8Field").as<int8_t>());
EXPECT_EQ(0, reader.get("int16Field").as<int16_t>());
EXPECT_EQ(0, reader.get("int32Field").as<int32_t>());
EXPECT_EQ(0, reader.get("int64Field").as<int64_t>());
EXPECT_EQ(0u, reader.get("uInt8Field").as<uint8_t>());
EXPECT_EQ(0u, reader.get("uInt16Field").as<uint16_t>());
EXPECT_EQ(0u, reader.get("uInt32Field").as<uint32_t>());
EXPECT_EQ(0u, reader.get("uInt64Field").as<uint64_t>());
EXPECT_FLOAT_EQ(0, reader.get("float32Field").as<float>());
EXPECT_DOUBLE_EQ(0, reader.get("float64Field").as<double>());
EXPECT_EQ("", reader.get("textField").as<Text>());
EXPECT_EQ("", reader.get("dataField").as<Data>());
{
auto subReader = reader.get("structField").as<DynamicStruct>();
EXPECT_EQ(Void::VOID, subReader.get("voidField").as<Void>());
EXPECT_EQ(false, subReader.get("boolField").as<bool>());
EXPECT_EQ(0, subReader.get("int8Field").as<int8_t>());
EXPECT_EQ(0, subReader.get("int16Field").as<int16_t>());
EXPECT_EQ(0, subReader.get("int32Field").as<int32_t>());
EXPECT_EQ(0, subReader.get("int64Field").as<int64_t>());
EXPECT_EQ(0u, subReader.get("uInt8Field").as<uint8_t>());
EXPECT_EQ(0u, subReader.get("uInt16Field").as<uint16_t>());
EXPECT_EQ(0u, subReader.get("uInt32Field").as<uint32_t>());
EXPECT_EQ(0u, subReader.get("uInt64Field").as<uint64_t>());
EXPECT_FLOAT_EQ(0, subReader.get("float32Field").as<float>());
EXPECT_DOUBLE_EQ(0, subReader.get("float64Field").as<double>());
EXPECT_EQ("", subReader.get("textField").as<Text>());
EXPECT_EQ("", subReader.get("dataField").as<Data>());
{
auto subSubReader = subReader.get("structField").as<DynamicStruct>();
EXPECT_EQ("", subSubReader.get("textField").as<Text>());
EXPECT_EQ("", subSubReader.get("structField").as<DynamicStruct>()
.get("textField").as<Text>());
}
EXPECT_EQ(0u, subReader.get("voidList").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("boolList").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("int8List").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("int16List").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("int32List").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("int64List").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("uInt8List").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("uInt16List").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("uInt32List").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("uInt64List").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("float32List").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("float64List").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("textList").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("dataList").as<DynamicList>().size());
EXPECT_EQ(0u, subReader.get("structList").as<DynamicList>().size());
}
EXPECT_EQ(0u, reader.get("voidList").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("boolList").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("int8List").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("int16List").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("int32List").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("int64List").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("uInt8List").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("uInt16List").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("uInt32List").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("uInt64List").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("float32List").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("float64List").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("textList").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("dataList").as<DynamicList>().size());
EXPECT_EQ(0u, reader.get("structList").as<DynamicList>().size());
}
#undef as
void dynamicInitListDefaults(DynamicStruct::Builder builder) {
auto lists = builder.init("lists").as<DynamicStruct>();
lists.init("list0", 2);
lists.init("list1", 4);
lists.init("list8", 2);
lists.init("list16", 2);
lists.init("list32", 2);
lists.init("list64", 2);
lists.init("listP", 2);
lists.get("list0").as<DynamicList>()[0].as<DynamicStruct>().set("f", Void::VOID);
lists.get("list0").as<DynamicList>()[1].as<DynamicStruct>().set("f", Void::VOID);
lists.get("list1").as<DynamicList>()[0].as<DynamicStruct>().set("f", true);
lists.get("list1").as<DynamicList>()[1].as<DynamicStruct>().set("f", false);
lists.get("list1").as<DynamicList>()[2].as<DynamicStruct>().set("f", true);
lists.get("list1").as<DynamicList>()[3].as<DynamicStruct>().set("f", true);
lists.get("list8").as<DynamicList>()[0].as<DynamicStruct>().set("f", 123u);
lists.get("list8").as<DynamicList>()[1].as<DynamicStruct>().set("f", 45u);
lists.get("list16").as<DynamicList>()[0].as<DynamicStruct>().set("f", 12345u);
lists.get("list16").as<DynamicList>()[1].as<DynamicStruct>().set("f", 6789u);
lists.get("list32").as<DynamicList>()[0].as<DynamicStruct>().set("f", 123456789u);
lists.get("list32").as<DynamicList>()[1].as<DynamicStruct>().set("f", 234567890u);
lists.get("list64").as<DynamicList>()[0].as<DynamicStruct>().set("f", 1234567890123456u);
lists.get("list64").as<DynamicList>()[1].as<DynamicStruct>().set("f", 2345678901234567u);
lists.get("listP").as<DynamicList>()[0].as<DynamicStruct>().set("f", "foo");
lists.get("listP").as<DynamicList>()[1].as<DynamicStruct>().set("f", "bar");
{
auto l = lists.init("int32ListList", 3).as<DynamicList>();
l.init(0, 3).as<DynamicList>().copyFrom({1, 2, 3});
l.init(1, 2).as<DynamicList>().copyFrom({4, 5});
l.init(2, 1).as<DynamicList>().copyFrom({12341234});
}
{
auto l = lists.init("textListList", 3).as<DynamicList>();
l.init(0, 2).as<DynamicList>().copyFrom({"foo", "bar"});
l.init(1, 1).as<DynamicList>().copyFrom({"baz"});
l.init(2, 2).as<DynamicList>().copyFrom({"qux", "corge"});
}
{
auto l = lists.init("structListList", 2).as<DynamicList>();
auto e = l.init(0, 2).as<DynamicList>();
e[0].as<TestAllTypes>().setInt32Field(123);
e[1].as<TestAllTypes>().setInt32Field(456);
e = l.init(1, 1).as<DynamicList>();
e[0].as<TestAllTypes>().setInt32Field(789);
}
}
// Hack because as<>() is a template-parameter-dependent lookup everywhere below...
#define as template as
template <typename Reader>
void dynamicCheckListDefaults(Reader reader) {
auto lists = reader.get("lists").as<DynamicStruct>();
ASSERT_EQ(2u, lists.get("list0").as<DynamicList>().size());
ASSERT_EQ(4u, lists.get("list1").as<DynamicList>().size());
ASSERT_EQ(2u, lists.get("list8").as<DynamicList>().size());
ASSERT_EQ(2u, lists.get("list16").as<DynamicList>().size());
ASSERT_EQ(2u, lists.get("list32").as<DynamicList>().size());
ASSERT_EQ(2u, lists.get("list64").as<DynamicList>().size());
ASSERT_EQ(2u, lists.get("listP").as<DynamicList>().size());
EXPECT_EQ(Void::VOID, lists.get("list0").as<DynamicList>()[0].as<DynamicStruct>().get("f").as<Void>());
EXPECT_EQ(Void::VOID, lists.get("list0").as<DynamicList>()[1].as<DynamicStruct>().get("f").as<Void>());
EXPECT_TRUE(lists.get("list1").as<DynamicList>()[0].as<DynamicStruct>().get("f").as<bool>());
EXPECT_FALSE(lists.get("list1").as<DynamicList>()[1].as<DynamicStruct>().get("f").as<bool>());
EXPECT_TRUE(lists.get("list1").as<DynamicList>()[2].as<DynamicStruct>().get("f").as<bool>());
EXPECT_TRUE(lists.get("list1").as<DynamicList>()[3].as<DynamicStruct>().get("f").as<bool>());
EXPECT_EQ(123u, lists.get("list8").as<DynamicList>()[0].as<DynamicStruct>().get("f").as<uint8_t>());
EXPECT_EQ(45u, lists.get("list8").as<DynamicList>()[1].as<DynamicStruct>().get("f").as<uint8_t>());
EXPECT_EQ(12345u, lists.get("list16").as<DynamicList>()[0].as<DynamicStruct>().get("f").as<uint16_t>());
EXPECT_EQ(6789u, lists.get("list16").as<DynamicList>()[1].as<DynamicStruct>().get("f").as<uint16_t>());
EXPECT_EQ(123456789u, lists.get("list32").as<DynamicList>()[0].as<DynamicStruct>().get("f").as<uint32_t>());
EXPECT_EQ(234567890u, lists.get("list32").as<DynamicList>()[1].as<DynamicStruct>().get("f").as<uint32_t>());
EXPECT_EQ(1234567890123456u, lists.get("list64").as<DynamicList>()[0].as<DynamicStruct>().get("f").as<uint64_t>());
EXPECT_EQ(2345678901234567u, lists.get("list64").as<DynamicList>()[1].as<DynamicStruct>().get("f").as<uint64_t>());
EXPECT_EQ("foo", lists.get("listP").as<DynamicList>()[0].as<DynamicStruct>().get("f").as<Text>());
EXPECT_EQ("bar", lists.get("listP").as<DynamicList>()[1].as<DynamicStruct>().get("f").as<Text>());
{
auto l = lists.get("int32ListList").as<DynamicList>();
ASSERT_EQ(3u, l.size());
checkList<int32_t>(l[0], {1, 2, 3});
checkList<int32_t>(l[1], {4, 5});
checkList<int32_t>(l[2], {12341234});
}
{
auto l = lists.get("textListList").as<DynamicList>();
ASSERT_EQ(3u, l.size());
checkList<Text>(l[0], {"foo", "bar"});
checkList<Text>(l[1], {"baz"});
checkList<Text>(l[2], {"qux", "corge"});
}
{
auto l = lists.get("structListList").as<DynamicList>();
ASSERT_EQ(2u, l.size());
auto e = l[0].as<DynamicList>();
ASSERT_EQ(2u, e.size());
EXPECT_EQ(123, e[0].as<TestAllTypes>().getInt32Field());
EXPECT_EQ(456, e[1].as<TestAllTypes>().getInt32Field());
e = l[1].as<DynamicList>();
ASSERT_EQ(1u, e.size());
EXPECT_EQ(789, e[0].as<TestAllTypes>().getInt32Field());
}
}
#undef as
TEST(DynamicApi, Build) {
MallocMessageBuilder builder;
auto root = builder.initRoot<DynamicStruct>(Schema::from<TestAllTypes>());
dynamicInitTestMessage(root);
checkTestMessage(root.asReader().as<TestAllTypes>());
dynamicCheckTestMessage(root.asReader());
dynamicCheckTestMessage(root);
}
TEST(DynamicApi, Read) {
MallocMessageBuilder builder;
auto root = builder.initRoot<TestAllTypes>();
dynamicInitTestmessage(toDynamic(root));
checkTestMessage(root);
initTestMessage(root);
dynamicCheckTestMessage(toDynamic(root.asReader()));
dynamicCheckTestMessage(toDynamic(root).asReader());
dynamicCheckTestMessage(toDynamic(root));
}
TEST(DynamicApi, Defaults) {
AlignedData<1> nullRoot = {{0, 0, 0, 0, 0, 0, 0, 0}};
ArrayPtr<const word> segments[1] = {arrayPtr(nullRoot.words, 1)};
SegmentArrayMessageReader reader(arrayPtr(segments, 1));
auto root = reader.getRoot<DynamicStruct>(Schema::from<TestDefaults>());
dynamicCheckTestMessage(root);
}
TEST(DynamicApi, DefaultsBuilder) {
MallocMessageBuilder builder;
auto root = builder.initRoot<DynamicStruct>(Schema::from<TestDefaults>());
checkTestMessage(root.asReader().as<TestDefaults>());
dynamicCheckTestMessage(root.asReader());
// This will initialize the whole message, replacing null pointers with copies of defaults.
dynamicCheckTestMessage(root);
// Check again now that the message is initialized.
checkTestMessage(root.asReader().as<TestDefaults>());
dynamicCheckTestMessage(root.asReader());
dynamicCheckTestMessage(root);
}
TEST(DynamicApi, Zero) {
MallocMessageBuilder builder;
auto root = builder.initRoot<DynamicStruct>(Schema::from<TestAllTypes>());
dynamicCheckTestMessageAllZero(root.asReader());
checkTestMessageAllZero(root.asReader().as<TestAllTypes>());
dynamicCheckTestMessageAllZero(root);
checkTestMessageAllZero(root.asReader().as<TestAllTypes>());
}
TEST(DynamicApi, ListListsBuild) {
MallocMessageBuilder builder;
auto root = builder.initRoot<DynamicStruct>(Schema::from<TestListDefaults>());
dynamicInitListDefaults(root);
checkTestMessage(root.asReader().as<TestListDefaults>());
dynamicCheckListDefaults(root.asReader());
dynamicCheckListDefaults(root);
}
TEST(DynamicApi, ListListsRead) {
MallocMessageBuilder builder;
auto root = builder.initRoot<TestListDefaults>();
initTestMessage(root);
dynamicCheckListDefaults(toDynamic(root.asReader()));
dynamicCheckListDefaults(toDynamic(root).asReader());
dynamicCheckListDefaults(toDynamic(root));
}
TEST(DynamicApi, GenericObjects) {
MallocMessageBuilder builder;
auto root = builder.getRoot<test::TestObject>();
dynamicInitTestMessage(root.initObjectField<DynamicStruct>(Schema::from<TestAllTypes>()));
checkTestMessage(root.asReader().getObjectField<TestAllTypes>());
dynamicCheckTestMessage(
root.asReader().getObjectField<DynamicStruct>(Schema::from<TestAllTypes>()));
dynamicCheckTestMessage(root.getObjectField<DynamicStruct>(Schema::from<TestAllTypes>()));
{
{
auto list = root.initObjectField<DynamicList>(Schema::from<List<uint32_t>>(), 4);
list.set(0, 123);
list.set(1, 456);
list.set(2, 789);
list.set(3, 123456789);
}
{
auto list = root.asReader().getObjectField<List<uint32_t>>();
ASSERT_EQ(4u, list.size());
EXPECT_EQ(123u, list[0]);
EXPECT_EQ(456u, list[1]);
EXPECT_EQ(789u, list[2]);
EXPECT_EQ(123456789u, list[3]);
}
checkList<uint32_t>(root.asReader().getObjectField<DynamicList>(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
checkList<uint32_t>(root.getObjectField<DynamicList>(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
}
}
TEST(DynamicApi, DynamicGenericObjects) {
MallocMessageBuilder builder;
auto root = builder.getRoot<DynamicStruct>(Schema::from<test::TestObject>());
dynamicInitTestMessage(root.initObject("objectField", Schema::from<TestAllTypes>()));
checkTestMessage(root.asReader().as<test::TestObject>().getObjectField<TestAllTypes>());
dynamicCheckTestMessage(
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<TestAllTypes>()));
dynamicCheckTestMessage(
root.get("objectField").as<DynamicObject>().as(Schema::from<TestAllTypes>()));
dynamicCheckTestMessage(
root.getObject("objectField", Schema::from<TestAllTypes>()));
{
{
auto list = root.initObject("objectField", Schema::from<List<uint32_t>>(), 4);
list.set(0, 123);
list.set(1, 456);
list.set(2, 789);
list.set(3, 123456789);
}
{
auto list = root.asReader().as<test::TestObject>().getObjectField<List<uint32_t>>();
ASSERT_EQ(4u, list.size());
EXPECT_EQ(123u, list[0]);
EXPECT_EQ(456u, list[1]);
EXPECT_EQ(789u, list[2]);
EXPECT_EQ(123456789u, list[3]);
}
checkList<uint32_t>(
root.asReader().get("objectField").as<DynamicObject>().as(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
checkList<uint32_t>(
root.get("objectField").as<DynamicObject>().as(Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
checkList<uint32_t>(
root.getObject("objectField", Schema::from<List<uint32_t>>()),
{123u, 456u, 789u, 123456789u});
}
}
TEST(DynamicApi, UnionsRead) {
MallocMessageBuilder builder;
auto root = builder.initRoot<TestUnion>();
root.getUnion0().setU0f1s32(1234567);
root.getUnion1().setU1f1sp("foo");
root.getUnion2().setU2f0s1(true);
root.getUnion3().setU3f0s64(1234567890123456789ll);
{
auto dynamic = toDynamic(root.asReader());
{
auto u = dynamic.get("union0").as<DynamicUnion>();
ASSERT_TRUE(u.which() != nullptr);
EXPECT_EQ("u0f1s32", u.which()->getProto().getName());
EXPECT_EQ(1234567, u.get().as<int32_t>());
}
{
auto u = dynamic.get("union1").as<DynamicUnion>();
ASSERT_TRUE(u.which() != nullptr);
EXPECT_EQ("u1f1sp", u.which()->getProto().getName());
EXPECT_EQ("foo", u.get().as<Text>());
}
{
auto u = dynamic.get("union2").as<DynamicUnion>();
ASSERT_TRUE(u.which() != nullptr);
EXPECT_EQ("u2f0s1", u.which()->getProto().getName());
EXPECT_TRUE(u.get().as<bool>());
}
{
auto u = dynamic.get("union3").as<DynamicUnion>();
ASSERT_TRUE(u.which() != nullptr);
EXPECT_EQ("u3f0s64", u.which()->getProto().getName());
EXPECT_EQ(1234567890123456789ll, u.get().as<int64_t>());
}
}
{
// Again as a builder.
auto dynamic = toDynamic(root);
{
auto u = dynamic.get("union0").as<DynamicUnion>();
ASSERT_TRUE(u.which() != nullptr);
EXPECT_EQ("u0f1s32", u.which()->getProto().getName());
EXPECT_EQ(1234567, u.get().as<int32_t>());
}
{
auto u = dynamic.get("union1").as<DynamicUnion>();
ASSERT_TRUE(u.which() != nullptr);
EXPECT_EQ("u1f1sp", u.which()->getProto().getName());
EXPECT_EQ("foo", u.get().as<Text>());
}
{
auto u = dynamic.get("union2").as<DynamicUnion>();
ASSERT_TRUE(u.which() != nullptr);
EXPECT_EQ("u2f0s1", u.which()->getProto().getName());
EXPECT_TRUE(u.get().as<bool>());
}
{
auto u = dynamic.get("union3").as<DynamicUnion>();
ASSERT_TRUE(u.which() != nullptr);
EXPECT_EQ("u3f0s64", u.which()->getProto().getName());
EXPECT_EQ(1234567890123456789ll, u.get().as<int64_t>());
}
}
}
TEST(DynamicApi, UnionsWrite) {
MallocMessageBuilder builder;
auto root = builder.initRoot<DynamicStruct>(Schema::from<TestUnion>());
root.get("union0").as<DynamicUnion>().set("u0f1s32", 1234567);
root.get("union1").as<DynamicUnion>().set("u1f1sp", "foo");
root.get("union2").as<DynamicUnion>().set("u2f0s1", true);
root.get("union3").as<DynamicUnion>().set("u3f0s64", 1234567890123456789ll);
auto reader = root.asReader().as<TestUnion>();
ASSERT_EQ(TestUnion::Union0::U0F1S32, reader.getUnion0().which());
EXPECT_EQ(1234567, reader.getUnion0().getU0f1s32());
ASSERT_EQ(TestUnion::Union1::U1F1SP, reader.getUnion1().which());
EXPECT_EQ("foo", reader.getUnion1().getU1f1sp());
ASSERT_EQ(TestUnion::Union2::U2F0S1, reader.getUnion2().which());
EXPECT_TRUE(reader.getUnion2().getU2f0s1());
ASSERT_EQ(TestUnion::Union3::U3F0S64, reader.getUnion3().which());
EXPECT_EQ(1234567890123456789ll, reader.getUnion3().getU3f0s64());
}
} // namespace
......
......@@ -24,8 +24,6 @@
#define CAPNPROTO_PRIVATE
#include "dynamic.h"
#include "logging.h"
#include <unordered_map>
#include <unordered_set>
namespace capnproto {
......@@ -122,7 +120,7 @@ uint16_t DynamicEnum::asImpl(uint64_t requestedTypeId) {
// =======================================================================================
DynamicStruct::Reader DynamicObject::Reader::as(StructSchema schema) {
DynamicStruct::Reader DynamicObject::as(StructSchema schema) {
if (reader.kind == internal::ObjectKind::NULL_POINTER) {
return DynamicStruct::Reader(schema, internal::StructReader());
}
......@@ -131,17 +129,8 @@ DynamicStruct::Reader DynamicObject::Reader::as(StructSchema schema) {
}
return DynamicStruct::Reader(schema, reader.structReader);
}
DynamicStruct::Builder DynamicObject::Builder::as(StructSchema schema) {
if (builder.kind == internal::ObjectKind::NULL_POINTER) {
return DynamicStruct::Builder(schema, internal::StructBuilder());
}
VALIDATE_INPUT(builder.kind == internal::ObjectKind::STRUCT, "Object is not a struct.") {
return DynamicStruct::Builder(schema, internal::StructBuilder());
}
return DynamicStruct::Builder(schema, builder.structBuilder);
}
DynamicList::Reader DynamicObject::Reader::as(ListSchema schema) {
DynamicList::Reader DynamicObject::as(ListSchema schema) {
if (reader.kind == internal::ObjectKind::NULL_POINTER) {
return DynamicList::Reader(schema, internal::ListReader());
}
......@@ -150,21 +139,12 @@ DynamicList::Reader DynamicObject::Reader::as(ListSchema schema) {
}
return DynamicList::Reader(schema, reader.listReader);
}
DynamicList::Builder DynamicObject::Builder::as(ListSchema schema) {
if (builder.kind == internal::ObjectKind::NULL_POINTER) {
return DynamicList::Builder(schema, internal::ListBuilder());
}
VALIDATE_INPUT(builder.kind == internal::ObjectKind::LIST, "Object is not a list.") {
return DynamicList::Builder(schema, internal::ListBuilder());
}
return DynamicList::Builder(schema, builder.listBuilder);
}
// =======================================================================================
Maybe<StructSchema::Member> DynamicUnion::Reader::which() {
auto members = schema.getMembers();
uint16_t discrim = reader.getDataField<uint32_t>(
uint16_t discrim = reader.getDataField<uint16_t>(
schema.getProto().getBody().getUnionMember().getDiscriminantOffset() * ELEMENTS);
if (discrim < members.size()) {
......@@ -175,7 +155,7 @@ Maybe<StructSchema::Member> DynamicUnion::Reader::which() {
}
Maybe<StructSchema::Member> DynamicUnion::Builder::which() {
auto members = schema.getMembers();
uint16_t discrim = builder.getDataField<uint32_t>(
uint16_t discrim = builder.getDataField<uint16_t>(
schema.getProto().getBody().getUnionMember().getDiscriminantOffset() * ELEMENTS);
if (discrim < members.size()) {
......@@ -186,50 +166,117 @@ Maybe<StructSchema::Member> DynamicUnion::Builder::which() {
}
DynamicValue::Reader DynamicUnion::Reader::get() {
auto w = which();
RECOVERABLE_PRECOND(w != nullptr, "Can't get() unknown union value.") {
return DynamicValue::Reader();
}
CHECK(w->getProto().getBody().which() == schema::StructNode::Member::Body::FIELD_MEMBER,
"Unsupported union member type.");
return DynamicValue::Reader(DynamicStruct::Reader::getImpl(reader, *w));
return DynamicValue::Reader(DynamicStruct::Reader::getImpl(reader, checkIsKnown()));
}
DynamicValue::Builder DynamicUnion::Builder::get() {
auto w = which();
RECOVERABLE_PRECOND(w != nullptr, "Can't get() unknown union value.") {
return DynamicValue::Builder();
}
CHECK(w->getProto().getBody().which() == schema::StructNode::Member::Body::FIELD_MEMBER,
"Unsupported union member type.");
return DynamicValue::Builder(DynamicStruct::Builder::getImpl(builder, *w));
return DynamicValue::Builder(DynamicStruct::Builder::getImpl(builder, checkIsKnown()));
}
void DynamicUnion::Builder::set(StructSchema::Member member, DynamicValue::Reader value) {
auto containingUnion = member.getContainingUnion();
RECOVERABLE_PRECOND(containingUnion != nullptr && *containingUnion == schema,
"`member` is not a member of this union.") {
return;
}
builder.setDataField<uint16_t>(
schema.getProto().getBody().getUnionMember().getDiscriminantOffset() * ELEMENTS,
member.getIndex());
setDiscriminant(member);
DynamicStruct::Builder::setImpl(builder, member, value);
}
DynamicValue::Builder DynamicUnion::Builder::init(StructSchema::Member member) {
builder.setDataField<uint16_t>(
schema.getProto().getBody().getUnionMember().getDiscriminantOffset() * ELEMENTS,
member.getIndex());
setDiscriminant(member);
return DynamicStruct::Builder::initImpl(builder, member);
}
DynamicValue::Builder DynamicUnion::Builder::init(StructSchema::Member member, uint size) {
setDiscriminant(member);
return DynamicStruct::Builder::initImpl(builder, member, size);
}
DynamicStruct::Builder DynamicUnion::Builder::getObject(StructSchema schema) {
return DynamicStruct::Builder::getObjectImpl(builder, checkIsObject(), schema);
}
DynamicList::Builder DynamicUnion::Builder::getObject(ListSchema schema) {
return DynamicStruct::Builder::getObjectImpl(builder, checkIsObject(), schema);
}
Text::Builder DynamicUnion::Builder::getObjectAsText() {
return DynamicStruct::Builder::getObjectAsTextImpl(builder, checkIsObject());
}
Data::Builder DynamicUnion::Builder::getObjectAsData() {
return DynamicStruct::Builder::getObjectAsDataImpl(builder, checkIsObject());
}
DynamicStruct::Builder DynamicUnion::Builder::initObject(
StructSchema::Member member, StructSchema type) {
setObjectDiscriminant(member);
return DynamicStruct::Builder::initFieldImpl(builder, member, type);
}
DynamicList::Builder DynamicUnion::Builder::initObject(
StructSchema::Member member, ListSchema type, uint size) {
setObjectDiscriminant(member);
return DynamicStruct::Builder::initFieldImpl(builder, member, type, size);
}
Text::Builder DynamicUnion::Builder::initObjectAsText(StructSchema::Member member, uint size) {
setObjectDiscriminant(member);
return DynamicStruct::Builder::initFieldAsTextImpl(builder, member, size);
}
Data::Builder DynamicUnion::Builder::initObjectAsData(StructSchema::Member member, uint size) {
setObjectDiscriminant(member);
return DynamicStruct::Builder::initFieldAsDataImpl(builder, member, size);
}
void DynamicUnion::Builder::set(Text::Reader name, DynamicValue::Reader value) {
set(schema.getMemberByName(name), value);
}
DynamicValue::Builder DynamicUnion::Builder::init(Text::Reader name) {
return init(schema.getMemberByName(name));
}
DynamicValue::Builder DynamicUnion::Builder::init(Text::Reader name, uint size) {
return init(schema.getMemberByName(name), size);
}
DynamicStruct::Builder DynamicUnion::Builder::initObject(Text::Reader name, StructSchema type) {
return initObject(schema.getMemberByName(name), type);
}
DynamicList::Builder DynamicUnion::Builder::initObject(
Text::Reader name, ListSchema type, uint size) {
return initObject(schema.getMemberByName(name), type, size);
}
Text::Builder DynamicUnion::Builder::initObjectAsText(Text::Reader name, uint size) {
return initObjectAsText(schema.getMemberByName(name), size);
}
Data::Builder DynamicUnion::Builder::initObjectAsData(Text::Reader name, uint size) {
return initObjectAsData(schema.getMemberByName(name), size);
}
StructSchema::Member DynamicUnion::Reader::checkIsKnown() {
auto w = which();
PRECOND(w != nullptr, "Can't get() unknown union value.");
CHECK(w->getProto().getBody().which() == schema::StructNode::Member::Body::FIELD_MEMBER,
"Unsupported union member type.");
return *w;
}
StructSchema::Member DynamicUnion::Builder::checkIsKnown() {
auto w = which();
PRECOND(w != nullptr, "Can't get() unknown union value.");
CHECK(w->getProto().getBody().which() == schema::StructNode::Member::Body::FIELD_MEMBER,
"Unsupported union member type.");
return *w;
}
StructSchema::Member DynamicUnion::Builder::checkIsObject() {
auto result = checkIsKnown();
PRECOND(result.getProto().getBody().getFieldMember().getType().getBody().which() ==
schema::Type::Body::OBJECT_TYPE, "Expected Object.");
return result;
}
void DynamicUnion::Builder::setDiscriminant(StructSchema::Member member) {
auto containingUnion = member.getContainingUnion();
PRECOND(containingUnion != nullptr && *containingUnion == schema,
"`member` is not a member of this union.");
builder.setDataField<uint16_t>(
schema.getProto().getBody().getUnionMember().getDiscriminantOffset() * ELEMENTS,
member.getIndex());
return DynamicStruct::Builder::initImpl(builder, member, size);
}
void DynamicUnion::Builder::setObjectDiscriminant(StructSchema::Member member) {
PRECOND(member.getProto().getBody().getFieldMember().getType().getBody().which() ==
schema::Type::Body::OBJECT_TYPE, "Expected Object.");
setDiscriminant(member);
}
// =======================================================================================
......@@ -268,19 +315,94 @@ DynamicValue::Builder DynamicStruct::Builder::init(StructSchema::Member member,
"`member` is not a member of this struct.");
return initImpl(builder, member, size);
}
DynamicStruct::Builder DynamicStruct::Builder::getObject(
StructSchema::Member member, StructSchema type) {
PRECOND(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
switch (member.getProto().getBody().which()) {
case schema::StructNode::Member::Body::UNION_MEMBER:
FAIL_PRECOND("Expected an Object.");
return DynamicStruct::Builder();
case schema::StructNode::Member::Body::FIELD_MEMBER: {
auto field = member.getProto().getBody().getFieldMember();
PRECOND(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
"Expected an Object.");
return getObjectImpl(builder, member, type);
}
}
FAIL_CHECK("switch() missing case.", member.getProto().getBody().which());
return DynamicStruct::Builder();
}
DynamicList::Builder DynamicStruct::Builder::getObject(
StructSchema::Member member, ListSchema type) {
PRECOND(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
switch (member.getProto().getBody().which()) {
case schema::StructNode::Member::Body::UNION_MEMBER:
FAIL_PRECOND("Expected an Object.");
return DynamicList::Builder();
case schema::StructNode::Member::Body::FIELD_MEMBER: {
auto field = member.getProto().getBody().getFieldMember();
PRECOND(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
"Expected an Object.");
return getObjectImpl(builder, member, type);
}
}
FAIL_CHECK("switch() missing case.", member.getProto().getBody().which());
return DynamicList::Builder();
}
Text::Builder DynamicStruct::Builder::getObjectAsText(StructSchema::Member member) {
PRECOND(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
switch (member.getProto().getBody().which()) {
case schema::StructNode::Member::Body::UNION_MEMBER:
FAIL_PRECOND("Expected an Object.");
return Text::Builder();
case schema::StructNode::Member::Body::FIELD_MEMBER: {
auto field = member.getProto().getBody().getFieldMember();
PRECOND(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
"Expected an Object.");
return getObjectAsDataImpl(builder, member);
}
}
FAIL_CHECK("switch() missing case.", member.getProto().getBody().which());
return Text::Builder();
}
Data::Builder DynamicStruct::Builder::getObjectAsData(StructSchema::Member member) {
PRECOND(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
switch (member.getProto().getBody().which()) {
case schema::StructNode::Member::Body::UNION_MEMBER:
FAIL_PRECOND("Expected an Object.");
return Data::Builder();
case schema::StructNode::Member::Body::FIELD_MEMBER: {
auto field = member.getProto().getBody().getFieldMember();
PRECOND(field.getType().getBody().which() == schema::Type::Body::OBJECT_TYPE,
"Expected an Object.");
return getObjectAsDataImpl(builder, member);
}
}
FAIL_CHECK("switch() missing case.", member.getProto().getBody().which());
return Data::Builder();
}
DynamicStruct::Builder DynamicStruct::Builder::initObject(
StructSchema::Member member, StructSchema type) {
PRECOND(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
switch (member.getProto().getBody().which()) {
case schema::StructNode::Member::Body::UNION_MEMBER:
FAIL_PRECOND("Can't init() a union. get() it first and then init() one of its members.");
FAIL_PRECOND("Expected an Object.");
return DynamicStruct::Builder();
case schema::StructNode::Member::Body::FIELD_MEMBER: {
auto field = member.getProto().getBody().getFieldMember();
PRECOND(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().)");
"Expected an Object.");
return initFieldImpl(builder, member, type);
}
}
......@@ -293,14 +415,13 @@ DynamicList::Builder DynamicStruct::Builder::initObject(
PRECOND(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
switch (member.getProto().getBody().which()) {
case schema::StructNode::Member::Body::UNION_MEMBER:
FAIL_PRECOND("Can't init() a union. get() it first and then init() one of its members.");
FAIL_PRECOND("Expected an Object.");
return DynamicList::Builder();
case schema::StructNode::Member::Body::FIELD_MEMBER: {
auto field = member.getProto().getBody().getFieldMember();
PRECOND(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().)");
"Expected an Object.");
return initFieldImpl(builder, member, type, size);
}
}
......@@ -312,14 +433,13 @@ Text::Builder DynamicStruct::Builder::initObjectAsText(StructSchema::Member memb
PRECOND(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
switch (member.getProto().getBody().which()) {
case schema::StructNode::Member::Body::UNION_MEMBER:
FAIL_PRECOND("Can't init() a union. get() it first and then init() one of its members.");
FAIL_PRECOND("Expected an Object.");
return Text::Builder();
case schema::StructNode::Member::Body::FIELD_MEMBER: {
auto field = member.getProto().getBody().getFieldMember();
PRECOND(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().)");
"Expected an Object.");
return initFieldAsDataImpl(builder, member, size);
}
}
......@@ -331,14 +451,13 @@ Data::Builder DynamicStruct::Builder::initObjectAsData(StructSchema::Member memb
PRECOND(member.getContainingStruct() == schema, "`member` is not a member of this struct.");
switch (member.getProto().getBody().which()) {
case schema::StructNode::Member::Body::UNION_MEMBER:
FAIL_PRECOND("Can't init() a union. get() it first and then init() one of its members.");
FAIL_PRECOND("Expected an Object.");
return Data::Builder();
case schema::StructNode::Member::Body::FIELD_MEMBER: {
auto field = member.getProto().getBody().getFieldMember();
PRECOND(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().)");
"Expected an Object.");
return initFieldAsDataImpl(builder, member, size);
}
}
......@@ -348,73 +467,50 @@ Data::Builder DynamicStruct::Builder::initObjectAsData(StructSchema::Member memb
}
DynamicValue::Reader DynamicStruct::Reader::get(Text::Reader name) {
auto member = schema.findMemberByName(name);
RECOVERABLE_PRECOND(member != nullptr, "struct has no such member", name) {
return DynamicValue::Reader();
}
return getImpl(reader, *member);
return getImpl(reader, schema.getMemberByName(name));
}
DynamicValue::Builder DynamicStruct::Builder::get(Text::Reader name) {
auto member = schema.findMemberByName(name);
RECOVERABLE_PRECOND(member != nullptr, "struct has no such member", name) {
return DynamicValue::Builder();
}
return getImpl(builder, *member);
return getImpl(builder, schema.getMemberByName(name));
}
void DynamicStruct::Builder::set(Text::Reader name, DynamicValue::Reader value) {
auto member = schema.findMemberByName(name);
RECOVERABLE_PRECOND(member != nullptr, "struct has no such member", name) {
return;
}
return setImpl(builder, *member, value);
setImpl(builder, schema.getMemberByName(name), value);
}
void DynamicStruct::Builder::set(Text::Reader name,
std::initializer_list<DynamicValue::Reader> value) {
init(name, value.size()).as<DynamicList>().copyFrom(value);
}
DynamicValue::Builder DynamicStruct::Builder::init(Text::Reader name) {
auto member = schema.findMemberByName(name);
RECOVERABLE_PRECOND(member != nullptr, "struct has no such member", name) {
return DynamicValue::Builder();
}
return initImpl(builder, *member);
return initImpl(builder, schema.getMemberByName(name));
}
DynamicValue::Builder DynamicStruct::Builder::init(Text::Reader name, uint size) {
auto member = schema.findMemberByName(name);
RECOVERABLE_PRECOND(member != nullptr, "struct has no such member", name) {
return DynamicValue::Builder();
}
return initImpl(builder, *member, size);
return initImpl(builder, schema.getMemberByName(name), size);
}
DynamicStruct::Builder DynamicStruct::Builder::getObject(
Text::Reader name, StructSchema type) {
return getObject(schema.getMemberByName(name), type);
}
DynamicList::Builder DynamicStruct::Builder::getObject(Text::Reader name, ListSchema type) {
return getObject(schema.getMemberByName(name), type);
}
Text::Builder DynamicStruct::Builder::getObjectAsText(Text::Reader name) {
return getObjectAsText(schema.getMemberByName(name));
}
Data::Builder DynamicStruct::Builder::getObjectAsData(Text::Reader name) {
return getObjectAsText(schema.getMemberByName(name));
}
DynamicStruct::Builder DynamicStruct::Builder::initObject(
Text::Reader name, StructSchema type) {
auto member = schema.findMemberByName(name);
RECOVERABLE_PRECOND(member != nullptr, "struct has no such member", name) {
return DynamicStruct::Builder();
}
return initObject(*member, type);
return initObject(schema.getMemberByName(name), type);
}
DynamicList::Builder DynamicStruct::Builder::initObject(
Text::Reader name, ListSchema type, uint size) {
auto member = schema.findMemberByName(name);
RECOVERABLE_PRECOND(member != nullptr, "struct has no such member", name) {
return DynamicList::Builder();
}
return initObject(*member, type, size);
return initObject(schema.getMemberByName(name), type, size);
}
Text::Builder DynamicStruct::Builder::initObjectAsText(Text::Reader name, uint size) {
auto member = schema.findMemberByName(name);
RECOVERABLE_PRECOND(member != nullptr, "struct has no such member", name) {
return Text::Builder();
}
return initObjectAsText(*member, size);
return initObjectAsText(schema.getMemberByName(name), size);
}
Data::Builder DynamicStruct::Builder::initObjectAsData(Text::Reader name, uint size) {
auto member = schema.findMemberByName(name);
RECOVERABLE_PRECOND(member != nullptr, "struct has no such member", name) {
return Data::Builder();
}
return initObjectAsText(*member, size);
return initObjectAsText(schema.getMemberByName(name), size);
}
void DynamicStruct::Builder::copyFrom(Reader other) {
......@@ -497,7 +593,7 @@ DynamicValue::Reader DynamicStruct::Reader::getImpl(
}
case schema::Type::Body::OBJECT_TYPE: {
return DynamicValue::Reader(DynamicObject::Reader(
return DynamicValue::Reader(DynamicObject(
reader.getObjectField(field.getOffset() * REFERENCES,
dval.getObjectValue<internal::TrustedMessage>())));
}
......@@ -573,13 +669,11 @@ DynamicValue::Builder DynamicStruct::Builder::getImpl(
typedDval.data(), typedDval.size() * BYTES));
}
case schema::Type::Body::LIST_TYPE: {
auto elementType = type.getListType();
case schema::Type::Body::LIST_TYPE:
return DynamicValue::Builder(DynamicList::Builder(
ListSchema::of(elementType, member.getContainingStruct()),
ListSchema::of(type.getListType(), member.getContainingStruct()),
builder.getListField(field.getOffset() * REFERENCES,
dval.getListValue<internal::TrustedMessage>())));
}
case schema::Type::Body::STRUCT_TYPE: {
auto structSchema =
......@@ -593,9 +687,10 @@ DynamicValue::Builder DynamicStruct::Builder::getImpl(
}
case schema::Type::Body::OBJECT_TYPE: {
return DynamicValue::Builder(DynamicObject::Builder(
builder.getObjectField(field.getOffset() * REFERENCES,
dval.getObjectValue<internal::TrustedMessage>())));
return DynamicValue::Builder(DynamicObject(
builder.asReader().getObjectField(
field.getOffset() * REFERENCES,
dval.getObjectValue<internal::TrustedMessage>())));
}
case schema::Type::Body::INTERFACE_TYPE:
......@@ -611,6 +706,30 @@ DynamicValue::Builder DynamicStruct::Builder::getImpl(
FAIL_CHECK("switch() missing case.", member.getProto().getBody().which());
return DynamicValue::Builder();
}
DynamicStruct::Builder DynamicStruct::Builder::getObjectImpl(
internal::StructBuilder builder, StructSchema::Member field, StructSchema type) {
return DynamicStruct::Builder(type,
builder.getStructField(
field.getProto().getBody().getFieldMember().getOffset() * REFERENCES,
structSizeFromSchema(type), nullptr));
}
DynamicList::Builder DynamicStruct::Builder::getObjectImpl(
internal::StructBuilder builder, StructSchema::Member field, ListSchema type) {
return DynamicList::Builder(type,
builder.getListField(
field.getProto().getBody().getFieldMember().getOffset() * REFERENCES,
nullptr));
}
Text::Builder DynamicStruct::Builder::getObjectAsTextImpl(
internal::StructBuilder builder, StructSchema::Member field) {
return builder.getBlobField<Text>(
field.getProto().getBody().getFieldMember().getOffset() * REFERENCES, nullptr, 0 * BYTES);
}
Data::Builder DynamicStruct::Builder::getObjectAsDataImpl(
internal::StructBuilder builder, StructSchema::Member field) {
return builder.getBlobField<Data>(
field.getProto().getBody().getFieldMember().getOffset() * REFERENCES, nullptr, 0 * BYTES);
}
void DynamicStruct::Builder::setImpl(
internal::StructBuilder builder, StructSchema::Member member, DynamicValue::Reader value) {
......@@ -841,7 +960,7 @@ DynamicValue::Reader DynamicList::Reader::operator[](uint index) {
schema.getEnumElementType(), reader.getDataElement<uint16_t>(index * ELEMENTS)));
case schema::Type::Body::OBJECT_TYPE:
return DynamicValue::Reader(DynamicObject::Reader(
return DynamicValue::Reader(DynamicObject(
reader.getObjectElement(index * ELEMENTS)));
case schema::Type::Body::INTERFACE_TYPE:
......@@ -1158,7 +1277,6 @@ BuilderFor<typeName> DynamicValue::Builder::AsImpl<typeName>::apply(Builder buil
HANDLE_TYPE(bool, BOOL, bool)
HANDLE_TYPE(text, TEXT, Text)
HANDLE_TYPE(data, DATA, Data)
HANDLE_TYPE(list, LIST, DynamicList)
HANDLE_TYPE(struct, STRUCT, DynamicStruct)
HANDLE_TYPE(enum, ENUM, DynamicEnum)
......@@ -1167,6 +1285,30 @@ HANDLE_TYPE(union, UNION, DynamicUnion)
#undef HANDLE_TYPE
Data::Reader DynamicValue::Reader::AsImpl<Data>::apply(Reader reader) {
if (reader.type == TEXT) {
// Implicitly convert from text.
return reader.textValue;
}
VALIDATE_INPUT(reader.type == DATA,
"Type mismatch when using DynamicValue::Reader::as().") {
return Data::Reader();
}
return reader.dataValue;
}
Data::Builder DynamicValue::Builder::AsImpl<Data>::apply(Builder builder) {
if (builder.type == TEXT) {
// Implicitly convert from text.
return builder.textValue;
}
VALIDATE_INPUT(builder.type == DATA,
"Type mismatch when using DynamicValue::Builder::as().") {
return Data::Builder();
}
return builder.dataValue;
}
// As in the header, HANDLE_TYPE(void, VOID, Void) crashes GCC 4.7.
Void DynamicValue::Reader::AsImpl<Void>::apply(Reader reader) {
VALIDATE_INPUT(reader.type == VOID,
......
......@@ -65,10 +65,7 @@ struct DynamicValue {
class Builder;
};
class DynamicEnum;
struct DynamicObject {
class Reader;
class Builder;
};
class DynamicObject;
struct DynamicUnion {
class Reader;
class Builder;
......@@ -103,6 +100,9 @@ class DynamicEnum {
public:
DynamicEnum() = default;
template <typename T, typename EnableIf = TypeIfEnum<T>>
inline DynamicEnum(T&& value): DynamicEnum(toDynamic(value)) {}
template <typename T>
inline T as() { return static_cast<T>(asImpl(typeId<T>())); }
// Cast to a native enum type.
......@@ -134,9 +134,13 @@ private:
// -------------------------------------------------------------------
class DynamicObject::Reader {
class DynamicObject {
// Represents an "Object" field of unknown type. This class behaves as a Reader. There is no
// equivalent Builder; you must use getObject() or initObject() on the containing struct and
// specify a type if you want to build an Object field.
public:
Reader() = default;
DynamicObject() = default;
template <typename T>
inline typename T::Reader as() { return AsImpl<T>::apply(*this); }
......@@ -148,31 +152,7 @@ public:
private:
internal::ObjectReader reader;
inline Reader(internal::ObjectReader reader): reader(reader) {}
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.
friend struct DynamicStruct;
friend struct DynamicList;
};
class DynamicObject::Builder {
public:
Builder() = default;
template <typename T>
inline typename T::Builder as() { return AsImpl<T>::apply(*this); }
// Convert the object to the given struct, list, or blob type.
DynamicStruct::Builder as(StructSchema schema);
DynamicList::Builder as(ListSchema schema);
private:
internal::ObjectBuilder builder;
inline Builder(internal::ObjectBuilder builder): builder(builder) {}
inline DynamicObject(internal::ObjectReader reader): reader(reader) {}
template <typename T, Kind kind = kind<T>()> struct AsImpl;
// Implementation backing the as() method. Needs to be a struct to allow partial
......@@ -205,6 +185,8 @@ private:
inline Reader(StructSchema::Union schema, internal::StructReader reader)
: schema(schema), reader(reader) {}
StructSchema::Member checkIsKnown();
friend struct DynamicStruct;
};
......@@ -223,6 +205,25 @@ public:
DynamicValue::Builder init(StructSchema::Member member);
DynamicValue::Builder init(StructSchema::Member member, uint size);
DynamicStruct::Builder getObject(StructSchema schema);
DynamicList::Builder getObject(ListSchema schema);
Text::Builder getObjectAsText();
Data::Builder getObjectAsData();
DynamicStruct::Builder initObject(StructSchema::Member member, StructSchema type);
DynamicList::Builder initObject(StructSchema::Member member, ListSchema type, uint size);
Text::Builder initObjectAsText(StructSchema::Member member, uint size);
Data::Builder initObjectAsData(StructSchema::Member member, uint size);
// Get/init an "Object" member. Must specify the type.
void set(Text::Reader name, DynamicValue::Reader value);
DynamicValue::Builder init(Text::Reader member);
DynamicValue::Builder init(Text::Reader name, uint size);
DynamicStruct::Builder initObject(Text::Reader name, StructSchema type);
DynamicList::Builder initObject(Text::Reader name, ListSchema type, uint size);
Text::Builder initObjectAsText(Text::Reader name, uint size);
Data::Builder initObjectAsData(Text::Reader name, uint size);
// Convenience methods that identify the member by text name.
private:
StructSchema::Union schema;
internal::StructBuilder builder;
......@@ -230,6 +231,11 @@ private:
inline Builder(StructSchema::Union schema, internal::StructBuilder builder)
: schema(schema), builder(builder) {}
StructSchema::Member checkIsKnown();
StructSchema::Member checkIsObject();
void setDiscriminant(StructSchema::Member member);
void setObjectDiscriminant(StructSchema::Member member);
friend struct DynamicStruct;
};
......@@ -239,6 +245,9 @@ class DynamicStruct::Reader {
public:
Reader() = default;
template <typename T, typename EnableIf = FromReader<T>>
inline Reader(T&& value): Reader(toDynamic(value)) {}
template <typename T>
typename T::Reader as();
// Convert the dynamic struct to its compiled-in type.
......@@ -265,7 +274,7 @@ private:
template <typename T>
friend struct internal::PointerHelpers;
friend class DynamicUnion::Reader;
friend struct DynamicObject;
friend class DynamicObject;
friend class DynamicStruct::Builder;
friend struct DynamicList;
friend class MessageReader;
......@@ -278,6 +287,9 @@ class DynamicStruct::Builder {
public:
Builder() = default;
template <typename T, typename EnableIf = FromBuilder<T>>
inline Builder(T&& value): Builder(toDynamic(value)) {}
template <typename T>
typename T::Builder as();
// Cast to a particular struct type.
......@@ -294,6 +306,12 @@ public:
DynamicValue::Builder init(StructSchema::Member member, uint size);
// Init a struct, list, or blob field.
DynamicStruct::Builder getObject(StructSchema::Member member, StructSchema type);
DynamicList::Builder getObject(StructSchema::Member member, ListSchema type);
Text::Builder getObjectAsText(StructSchema::Member member);
Data::Builder getObjectAsData(StructSchema::Member member);
// Get an object field. You must specify the type.
DynamicStruct::Builder initObject(StructSchema::Member member, StructSchema type);
DynamicList::Builder initObject(StructSchema::Member member, ListSchema type, uint size);
Text::Builder initObjectAsText(StructSchema::Member member, uint size);
......@@ -305,6 +323,10 @@ public:
void set(Text::Reader name, std::initializer_list<DynamicValue::Reader> value);
DynamicValue::Builder init(Text::Reader name);
DynamicValue::Builder init(Text::Reader name, uint size);
DynamicStruct::Builder getObject(Text::Reader name, StructSchema type);
DynamicList::Builder getObject(Text::Reader name, ListSchema type);
Text::Builder getObjectAsText(Text::Reader name);
Data::Builder getObjectAsData(Text::Reader name);
DynamicStruct::Builder initObject(Text::Reader name, StructSchema type);
DynamicList::Builder initObject(Text::Reader name, ListSchema type, uint size);
Text::Builder initObjectAsText(Text::Reader name, uint size);
......@@ -326,8 +348,18 @@ private:
static DynamicValue::Builder getImpl(
internal::StructBuilder builder, StructSchema::Member member);
static DynamicStruct::Builder getObjectImpl(
internal::StructBuilder builder, StructSchema::Member field, StructSchema type);
static DynamicList::Builder getObjectImpl(
internal::StructBuilder builder, StructSchema::Member field, ListSchema type);
static Text::Builder getObjectAsTextImpl(
internal::StructBuilder builder, StructSchema::Member field);
static Data::Builder getObjectAsDataImpl(
internal::StructBuilder builder, StructSchema::Member field);
static void setImpl(
internal::StructBuilder builder, StructSchema::Member member, DynamicValue::Reader value);
static DynamicValue::Builder initImpl(
internal::StructBuilder builder, StructSchema::Member member, uint size);
static DynamicValue::Builder initImpl(
......@@ -344,7 +376,6 @@ private:
template <typename T>
friend struct internal::PointerHelpers;
friend class DynamicUnion::Builder;
friend struct DynamicObject;
friend struct DynamicList;
friend class MessageReader;
friend class MessageBuilder;
......@@ -358,6 +389,9 @@ class DynamicList::Reader {
public:
Reader() = default;
template <typename T, typename EnableIf = FromReader<T>>
inline Reader(T&& value): Reader(toDynamic(value)) {}
template <typename T>
typename T::Reader as();
// Try to convert to any List<T>, Data, or Text. Throws an exception if the underlying data
......@@ -383,7 +417,7 @@ private:
template <typename T>
friend struct internal::PointerHelpers;
friend struct DynamicStruct;
friend struct DynamicObject;
friend class DynamicObject;
friend class DynamicList::Builder;
template <typename T, ::capnproto::Kind k>
friend struct ::capnproto::ToDynamic_;
......@@ -393,6 +427,9 @@ class DynamicList::Builder {
public:
Builder() = default;
template <typename T, typename EnableIf = FromBuilder<T>>
inline Builder(T&& value): Builder(toDynamic(value)) {}
template <typename T>
typename T::Builder as();
// Try to convert to any List<T>, Data, or Text. Throws an exception if the underlying data
......@@ -425,7 +462,6 @@ private:
template <typename T>
friend struct internal::PointerHelpers;
friend struct DynamicStruct;
friend struct DynamicObject;
template <typename T, ::capnproto::Kind k>
friend struct ::capnproto::ToDynamic_;
};
......@@ -445,8 +481,8 @@ struct MaybeReaderBuilder<DynamicEnum, Kind::UNKNOWN> {
template <>
struct MaybeReaderBuilder<DynamicObject, Kind::UNKNOWN> {
typedef DynamicObject::Reader Reader;
typedef DynamicObject::Builder Builder;
typedef DynamicObject Reader;
typedef DynamicObject Builder;
};
template <>
......@@ -480,13 +516,17 @@ public:
inline Reader(unsigned long long value);
inline Reader(float value);
inline Reader(double value);
inline Reader(const char* value); // Text
inline Reader(Text::Reader value);
inline Reader(Data::Reader value);
inline Reader(DynamicList::Reader value);
inline Reader(DynamicEnum value);
inline Reader(DynamicStruct::Reader value);
inline Reader(DynamicUnion::Reader value);
inline Reader(DynamicObject::Reader value);
inline Reader(DynamicObject value);
template <typename T, typename EnableIf = decltype(toDynamic(instance<T>()))>
inline Reader(T value): Reader(toDynamic(value)) {}
template <typename T>
inline ReaderFor<T> as() { return AsImpl<T>::apply(*this); }
......@@ -494,8 +534,8 @@ public:
// - 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.
// - List<T> for any T listed above: Returns List<T>::Reader.
// - DynamicEnum: Returns DynamicEnum.
// - DynamicStruct, DynamicList, DynamicObject, DynamicUnion: Returns the corresponding Reader.
// - DynamicEnum, DynamicObject: Returns the corresponding type.
// - DynamicStruct, DynamicList, DynamicUnion: Returns the corresponding Reader.
//
// DynamicValue allows various implicit conversions:
// - Any integer can be converted to any other integer type so long as the actual value is within
......@@ -505,6 +545,7 @@ public:
// - Integers can be converted to floating points. This may lose information, but won't throw.
// - 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).
//
// Any other conversion attempt will throw an exception.
......@@ -526,7 +567,7 @@ private:
DynamicEnum enumValue;
DynamicStruct::Reader structValue;
DynamicUnion::Reader unionValue;
DynamicObject::Reader objectValue;
DynamicObject objectValue;
};
template <typename T, Kind kind = kind<T>()> struct AsImpl;
......@@ -557,7 +598,7 @@ public:
inline Builder(DynamicEnum value);
inline Builder(DynamicStruct::Builder value);
inline Builder(DynamicUnion::Builder value);
inline Builder(DynamicObject::Builder value);
inline Builder(DynamicObject value);
template <typename T>
inline BuilderFor<T> as() { return AsImpl<T>::apply(*this); }
......@@ -583,7 +624,7 @@ private:
DynamicEnum enumValue;
DynamicStruct::Builder structValue;
DynamicUnion::Builder unionValue;
DynamicObject::Builder objectValue;
DynamicObject objectValue;
};
template <typename T, Kind kind = kind<T>()> struct AsImpl;
......@@ -669,7 +710,7 @@ BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value) {
}
template <typename T>
DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) {
return DynamicEnum(Schema::from<T>(), static_cast<uint16_t>(value));
return DynamicEnum(Schema::from<RemoveReference<T>>(), static_cast<uint16_t>(value));
}
#define CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
......@@ -694,6 +735,7 @@ CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long long, UINT, uint);
CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(float, FLOAT, float);
CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(double, FLOAT, float);
CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicEnum, ENUM, enum);
CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicObject, OBJECT, object);
#undef CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
#define CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
......@@ -707,10 +749,11 @@ CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Data, DATA, data);
CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicList, LIST, list);
CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicStruct, STRUCT, struct);
CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicUnion, UNION, union);
CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicObject, OBJECT, object);
#undef CAPNPROTO_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
inline DynamicValue::Reader::Reader(const char* value): Reader(Text::Reader(value)) {}
#define CAPNPROTO_DECLARE_TYPE(name, discrim, typeName) \
template <> \
struct DynamicValue::Reader::AsImpl<typeName> { \
......@@ -769,26 +812,26 @@ struct DynamicValue::Builder::AsImpl<T, Kind::ENUM> {
template <typename T>
struct DynamicValue::Reader::AsImpl<T, Kind::STRUCT> {
static T apply(Reader reader) {
static typename T::Reader apply(Reader reader) {
return reader.as<DynamicStruct>().as<T>();
}
};
template <typename T>
struct DynamicValue::Builder::AsImpl<T, Kind::STRUCT> {
static T apply(Builder builder) {
static typename T::Builder apply(Builder builder) {
return builder.as<DynamicStruct>().as<T>();
}
};
template <typename T>
struct DynamicValue::Reader::AsImpl<T, Kind::LIST> {
static T apply(Reader reader) {
static typename T::Reader apply(Reader reader) {
return reader.as<DynamicList>().as<T>();
}
};
template <typename T>
struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
static T apply(Builder builder) {
static typename T::Builder apply(Builder builder) {
return builder.as<DynamicList>().as<T>();
}
};
......@@ -796,28 +839,16 @@ struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
// -------------------------------------------------------------------
template <typename T>
struct DynamicObject::Reader::AsImpl<T, Kind::STRUCT> {
static T apply(Reader reader) {
return reader.as(Schema::from<T>()).as<T>();
}
};
template <typename T>
struct DynamicObject::Builder::AsImpl<T, Kind::STRUCT> {
static T apply(Builder builder) {
return builder.as(Schema::from<T>()).as<T>();
struct DynamicObject::AsImpl<T, Kind::STRUCT> {
static T apply(DynamicObject value) {
return value.as(Schema::from<T>()).as<T>();
}
};
template <typename T>
struct DynamicObject::Reader::AsImpl<T, Kind::LIST> {
static T apply(Reader reader) {
return reader.as(Schema::from<T>()).as<T>();
}
};
template <typename T>
struct DynamicObject::Builder::AsImpl<T, Kind::LIST> {
static T apply(Builder builder) {
return builder.as(Schema::from<T>()).as<T>();
struct DynamicObject::AsImpl<T, Kind::LIST> {
static T apply(DynamicObject value) {
return value.as(Schema::from<T>()).as<T>();
}
};
......@@ -838,6 +869,15 @@ typename T::Builder DynamicStruct::Builder::as() {
return typename T::Builder(builder);
}
template <>
inline DynamicStruct::Reader DynamicStruct::Reader::as<DynamicStruct>() {
return *this;
}
template <>
inline DynamicStruct::Builder DynamicStruct::Builder::as<DynamicStruct>() {
return *this;
}
inline DynamicStruct::Reader DynamicStruct::Builder::asReader() {
return DynamicStruct::Reader(schema, builder.asReader());
}
......@@ -859,6 +899,15 @@ typename T::Builder DynamicList::Builder::as() {
return typename T::Builder(builder);
}
template <>
inline DynamicList::Reader DynamicList::Reader::as<DynamicList>() {
return *this;
}
template <>
inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
return *this;
}
} // namespace capnproto
#endif // CAPNPROTO_DYNAMIC_H_
......@@ -427,7 +427,8 @@ struct WireHelpers {
word* ptr;
if (ref->isNull()) {
if (defaultValue == nullptr) {
if (defaultValue == nullptr ||
reinterpret_cast<const WireReference*>(defaultValue)->isNull()) {
ptr = allocate(ref, segment, size.total(), WireReference::STRUCT);
ref->structRef.set(size);
} else {
......@@ -508,7 +509,8 @@ struct WireHelpers {
word* ptr;
if (ref->isNull()) {
if (defaultValue == nullptr) {
if (defaultValue == nullptr ||
reinterpret_cast<const WireReference*>(defaultValue)->isNull()) {
return ListBuilder();
}
ptr = copyMessage(segment, ref, defaultRef);
......@@ -619,7 +621,8 @@ struct WireHelpers {
word* ptr;
if (ref->isNull()) {
if (defaultValue == nullptr) {
if (defaultValue == nullptr ||
reinterpret_cast<const WireReference*>(defaultValue)->isNull()) {
return ObjectBuilder();
} else {
ptr = copyMessage(segment, ref, reinterpret_cast<const WireReference*>(defaultValue));
......@@ -668,7 +671,8 @@ struct WireHelpers {
if (ref == nullptr || ref->isNull()) {
useDefault:
if (defaultValue == nullptr) {
if (defaultValue == nullptr ||
reinterpret_cast<const WireReference*>(defaultValue)->isNull()) {
return StructReader(nullptr, nullptr, nullptr, 0 * BITS, 0 * REFERENCES, 0 * BITS,
std::numeric_limits<int>::max());
}
......@@ -714,7 +718,8 @@ struct WireHelpers {
const word* ptr;
if (ref == nullptr || ref->isNull()) {
useDefault:
if (defaultValue == nullptr) {
if (defaultValue == nullptr ||
reinterpret_cast<const WireReference*>(defaultValue)->isNull()) {
return ListReader();
}
segment = nullptr;
......@@ -874,7 +879,8 @@ struct WireHelpers {
const void* defaultValue, ByteCount defaultSize)) {
if (ref == nullptr || ref->isNull()) {
useDefault:
if (defaultValue == nullptr) {
if (defaultValue == nullptr ||
reinterpret_cast<const WireReference*>(defaultValue)->isNull()) {
defaultValue = "";
}
return Text::Reader(reinterpret_cast<const char*>(defaultValue), defaultSize / BYTES);
......@@ -973,7 +979,8 @@ struct WireHelpers {
const word* ptr;
if (ref == nullptr || ref->isNull()) {
useDefault:
if (defaultValue == nullptr) {
if (defaultValue == nullptr ||
reinterpret_cast<const WireReference*>(defaultValue)->isNull()) {
return ObjectReader();
}
segment = nullptr;
......
......@@ -647,7 +647,7 @@ struct ObjectBuilder {
ObjectBuilder(): kind(ObjectKind::NULL_POINTER), structBuilder() {}
ObjectBuilder(StructBuilder structBuilder)
: kind(ObjectKind::STRUCT), structBuilder(structBuilder) {}
ObjectBuilder(ListBuilder listBuilderBuilder)
ObjectBuilder(ListBuilder listBuilder)
: kind(ObjectKind::LIST), listBuilder(listBuilder) {}
};
......
......@@ -122,6 +122,12 @@ Maybe<StructSchema::Member> StructSchema::findMemberByName(Text::Reader name) co
return findSchemaMemberByName(raw, name, 0, getMembers());
}
StructSchema::Member StructSchema::getMemberByName(Text::Reader name) const {
Maybe<StructSchema::Member> member = findMemberByName(name);
PRECOND(member != nullptr, "struct has no such member", name);
return *member;
}
Maybe<StructSchema::Union> StructSchema::Member::getContainingUnion() const {
if (unionIndex == 0) return nullptr;
return parent.getMembers()[unionIndex - 1].asUnion();
......@@ -142,6 +148,12 @@ Maybe<StructSchema::Member> StructSchema::Union::findMemberByName(Text::Reader n
return findSchemaMemberByName(parent.raw, name, index + 1, getMembers());
}
StructSchema::Member StructSchema::Union::getMemberByName(Text::Reader name) const {
Maybe<StructSchema::Member> member = findMemberByName(name);
PRECOND(member != nullptr, "struct has no such member", name);
return *member;
}
// -------------------------------------------------------------------
EnumSchema::EnumerantList EnumSchema::getEnumerants() const {
......@@ -152,6 +164,12 @@ Maybe<EnumSchema::Enumerant> EnumSchema::findEnumerantByName(Text::Reader name)
return findSchemaMemberByName(raw, name, 0, getEnumerants());
}
EnumSchema::Enumerant EnumSchema::getEnumerantByName(Text::Reader name) const {
Maybe<EnumSchema::Enumerant> enumerant = findEnumerantByName(name);
PRECOND(enumerant != nullptr, "enum has no such enumerant", name);
return *enumerant;
}
// -------------------------------------------------------------------
InterfaceSchema::MethodList InterfaceSchema::getMethods() const {
......@@ -162,6 +180,12 @@ Maybe<InterfaceSchema::Method> InterfaceSchema::findMethodByName(Text::Reader na
return findSchemaMemberByName(raw, name, 0, getMethods());
}
InterfaceSchema::Method InterfaceSchema::getMethodByName(Text::Reader name) const {
Maybe<InterfaceSchema::Method> method = findMethodByName(name);
PRECOND(method != nullptr, "interface has no such method", name);
return *method;
}
// =======================================================================================
ListSchema ListSchema::of(schema::Type::Body::Which primitiveType) {
......
......@@ -100,8 +100,12 @@ public:
class MemberList;
MemberList getMembers() const;
Maybe<Member> findMemberByName(Text::Reader name) const;
Member getMemberByName(Text::Reader name) const;
// Like findMemberByName() but throws an exception on failure.
private:
StructSchema(const internal::RawSchema* raw): Schema(raw) {}
template <typename T> static inline StructSchema fromImpl() {
......@@ -148,8 +152,12 @@ public:
Union() = default;
MemberList getMembers() const;
Maybe<Member> findMemberByName(Text::Reader name) const;
Member getMemberByName(Text::Reader name) const;
// Like findMemberByName() but throws an exception on failure.
private:
inline Union(const Member& base): Member(base) {}
......@@ -187,8 +195,12 @@ public:
class EnumerantList;
EnumerantList getEnumerants() const;
Maybe<Enumerant> findEnumerantByName(Text::Reader name) const;
Enumerant getEnumerantByName(Text::Reader name) const;
// Like findEnumerantByName() but throws an exception on failure.
private:
EnumSchema(const internal::RawSchema* raw): Schema(raw) {}
template <typename T> static inline EnumSchema fromImpl() {
......@@ -250,8 +262,12 @@ public:
class MethodList;
MethodList getMethods() const;
Maybe<Method> findMethodByName(Text::Reader name) const;
Method getMethodByName(Text::Reader name) const;
// Like findMethodByName() but throws an exception on failure.
private:
InterfaceSchema(const internal::RawSchema* raw): Schema(raw) {}
template <typename T> static inline InterfaceSchema fromImpl() {
......
......@@ -498,7 +498,7 @@ outerFileContext schemaNodes = fileContext where
DescEnum d -> muJust $ enumContext context d
_ -> muNull
context "typeSchema" = case desc of
DescUnion u -> muNull
DescUnion _ -> muNull
_ -> muJust $ schemaContext context desc
context s = parent s
......
......@@ -523,7 +523,7 @@ encodeSchema requestedFiles allFiles = (encRoot, nodesForEmbedding) where
BuiltinType BuiltinFloat64 -> 11
BuiltinType BuiltinText -> 12
BuiltinType BuiltinData -> 13
BuiltinType BuiltinObject -> 19
BuiltinType BuiltinObject -> 18
ListType _ -> 14
EnumType _ -> 15
StructType _ -> 16
......
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