Commit 7c6c617d authored by Kenton Varda's avatar Kenton Varda

Generate usable code for groups, although making schemas work is still an open…

Generate usable code for groups, although making schemas work is still an open problem.  I think I'm going to do the schema rewrite now.
parent c1e33ebf
...@@ -322,6 +322,41 @@ private: ...@@ -322,6 +322,41 @@ private:
// ----------------------------------------------------------------- // -----------------------------------------------------------------
struct DiscriminantChecks {
kj::String check;
kj::String set;
};
DiscriminantChecks makeDiscriminantChecks(kj::StringPtr scope,
kj::StringPtr memberName,
StructSchema::Union containingUnion) {
auto unionProto = containingUnion.getProto();
kj::StringPtr unionScope;
kj::String ownUnionScope;
if (unionProto.getName().size() > 0) {
ownUnionScope = kj::str(toTitleCase(unionProto.getName()), "::");
unionScope = ownUnionScope;
} else {
// Anonymous union.
unionScope = scope;
}
auto discrimOffset = unionProto.getBody().getUnionMember().getDiscriminantOffset();
kj::String upperCase = toUpperCase(memberName);
return DiscriminantChecks {
kj::str(
" KJ_IREQUIRE(which() == ", unionScope, upperCase, ",\n"
" \"Must check which() before get()ing a union member.\");\n"),
kj::str(
" _builder.setDataField<", unionScope, "Which>(\n"
" ", discrimOffset, " * ::capnp::ELEMENTS, ",
unionScope, upperCase, ");\n")
};
}
// -----------------------------------------------------------------
struct FieldText { struct FieldText {
kj::StringTree readerMethodDecls; kj::StringTree readerMethodDecls;
kj::StringTree builderMethodDecls; kj::StringTree builderMethodDecls;
...@@ -450,28 +485,9 @@ private: ...@@ -450,28 +485,9 @@ private:
kj::String titleCase = toTitleCase(proto.getName()); kj::String titleCase = toTitleCase(proto.getName());
kj::String unionSet, unionCheck; DiscriminantChecks unionDiscrim;
KJ_IF_MAYBE(u, member.getContainingUnion()) { KJ_IF_MAYBE(u, member.getContainingUnion()) {
auto unionProto = u->getProto(); unionDiscrim = makeDiscriminantChecks(scope, proto.getName(), *u);
kj::StringPtr unionScope;
kj::String ownUnionScope;
if (unionProto.getName().size() > 0) {
ownUnionScope = kj::str(toTitleCase(unionProto.getName()), "::");
unionScope = ownUnionScope;
} else {
// Anonymous union.
unionScope = scope;
}
auto discrimOffset = unionProto.getBody().getUnionMember().getDiscriminantOffset();
kj::String upperCase = toUpperCase(proto.getName());
unionCheck = kj::str(
" KJ_IREQUIRE(which() == ", unionScope, upperCase, ",\n"
" \"Must check which() before get()ing a union member.\");\n");
unionSet = kj::str(
" _builder.setDataField<", unionScope, "Which>(\n"
" ", discrimOffset, " * ::capnp::ELEMENTS, ",
unionScope, upperCase, ");\n");
} }
uint offset = field.getOffset(); uint offset = field.getOffset();
...@@ -489,18 +505,18 @@ private: ...@@ -489,18 +505,18 @@ private:
kj::strTree( kj::strTree(
"inline ", type, " ", scope, "Reader::get", titleCase, "() const {\n", "inline ", type, " ", scope, "Reader::get", titleCase, "() const {\n",
unionCheck, unionDiscrim.check,
" return _reader.getDataField<", type, ">(\n" " return _reader.getDataField<", type, ">(\n"
" ", offset, " * ::capnp::ELEMENTS", defaultMaskParam, ");\n", " ", offset, " * ::capnp::ELEMENTS", defaultMaskParam, ");\n",
"}\n" "}\n"
"\n" "\n"
"inline ", type, " ", scope, "Builder::get", titleCase, "() {\n", "inline ", type, " ", scope, "Builder::get", titleCase, "() {\n",
unionCheck, unionDiscrim.check,
" return _builder.getDataField<", type, ">(\n" " return _builder.getDataField<", type, ">(\n"
" ", offset, " * ::capnp::ELEMENTS", defaultMaskParam, ");\n", " ", offset, " * ::capnp::ELEMENTS", defaultMaskParam, ");\n",
"}\n" "}\n"
"inline void ", scope, "Builder::set", titleCase, "(", type, " value) {\n", "inline void ", scope, "Builder::set", titleCase, "(", type, " value) {\n",
unionSet, unionDiscrim.set,
" _builder.setDataField<", type, ">(\n" " _builder.setDataField<", type, ">(\n"
" ", offset, " * ::capnp::ELEMENTS, value", defaultMaskParam, ");\n", " ", offset, " * ::capnp::ELEMENTS, value", defaultMaskParam, ");\n",
"}\n" "}\n"
...@@ -541,64 +557,64 @@ private: ...@@ -541,64 +557,64 @@ private:
kj::strTree( kj::strTree(
"inline bool ", scope, "Reader::has", titleCase, "() const {\n", "inline bool ", scope, "Reader::has", titleCase, "() const {\n",
unionCheck, unionDiscrim.check,
" return !_reader.isPointerFieldNull(", offset, " * ::capnp::POINTERS);\n" " return !_reader.isPointerFieldNull(", offset, " * ::capnp::POINTERS);\n"
"}\n" "}\n"
"inline bool ", scope, "Builder::has", titleCase, "() {\n", "inline bool ", scope, "Builder::has", titleCase, "() {\n",
unionCheck, unionDiscrim.check,
" return !_builder.isPointerFieldNull(", offset, " * ::capnp::POINTERS);\n" " return !_builder.isPointerFieldNull(", offset, " * ::capnp::POINTERS);\n"
"}\n" "}\n"
"template <typename T>\n" "template <typename T>\n"
"inline typename T::Reader ", scope, "Reader::get", titleCase, "() const {\n", "inline typename T::Reader ", scope, "Reader::get", titleCase, "() const {\n",
unionCheck, unionDiscrim.check,
" return ::capnp::_::PointerHelpers<T>::get(\n" " return ::capnp::_::PointerHelpers<T>::get(\n"
" _reader, ", offset, " * ::capnp::POINTERS);\n" " _reader, ", offset, " * ::capnp::POINTERS);\n"
"}\n" "}\n"
"template <typename T>\n" "template <typename T>\n"
"inline typename T::Builder ", scope, "Builder::get", titleCase, "() {\n", "inline typename T::Builder ", scope, "Builder::get", titleCase, "() {\n",
unionCheck, unionDiscrim.check,
" return ::capnp::_::PointerHelpers<T>::get(\n" " return ::capnp::_::PointerHelpers<T>::get(\n"
" _builder, ", offset, " * ::capnp::POINTERS);\n" " _builder, ", offset, " * ::capnp::POINTERS);\n"
"}\n" "}\n"
"template <typename T, typename Param>\n" "template <typename T, typename Param>\n"
"inline typename T::Reader ", scope, "Reader::get", titleCase, "(Param&& param) const {\n", "inline typename T::Reader ", scope, "Reader::get", titleCase, "(Param&& param) const {\n",
unionCheck, unionDiscrim.check,
" return ::capnp::_::PointerHelpers<T>::getDynamic(\n" " return ::capnp::_::PointerHelpers<T>::getDynamic(\n"
" _reader, ", offset, " * ::capnp::POINTERS, ::kj::fwd<Param>(param));\n" " _reader, ", offset, " * ::capnp::POINTERS, ::kj::fwd<Param>(param));\n"
"}\n" "}\n"
"template <typename T, typename Param>\n" "template <typename T, typename Param>\n"
"inline typename T::Builder ", scope, "Builder::get", titleCase, "(Param&& param) {\n", "inline typename T::Builder ", scope, "Builder::get", titleCase, "(Param&& param) {\n",
unionCheck, unionDiscrim.check,
" return ::capnp::_::PointerHelpers<T>::getDynamic(\n" " return ::capnp::_::PointerHelpers<T>::getDynamic(\n"
" _builder, ", offset, " * ::capnp::POINTERS, ::kj::fwd<Param>(param));\n" " _builder, ", offset, " * ::capnp::POINTERS, ::kj::fwd<Param>(param));\n"
"}\n" "}\n"
"template <typename T>\n" "template <typename T>\n"
"inline void ", scope, "Builder::set", titleCase, "(typename T::Reader value) {\n", "inline void ", scope, "Builder::set", titleCase, "(typename T::Reader value) {\n",
unionSet, unionDiscrim.set,
" ::capnp::_::PointerHelpers<T>::set(\n" " ::capnp::_::PointerHelpers<T>::set(\n"
" _builder, ", offset, " * ::capnp::POINTERS, value);\n" " _builder, ", offset, " * ::capnp::POINTERS, value);\n"
"}\n" "}\n"
"template <typename T, typename U>" "template <typename T, typename U>"
"inline void ", scope, "Builder::set", titleCase, "(std::initializer_list<U> value) {\n", "inline void ", scope, "Builder::set", titleCase, "(std::initializer_list<U> value) {\n",
unionSet, unionDiscrim.set,
" ::capnp::_::PointerHelpers<T>::set(\n" " ::capnp::_::PointerHelpers<T>::set(\n"
" _builder, ", offset, " * ::capnp::POINTERS, value);\n" " _builder, ", offset, " * ::capnp::POINTERS, value);\n"
"}\n" "}\n"
"template <typename T, typename... Params>\n" "template <typename T, typename... Params>\n"
"inline typename T::Builder ", scope, "Builder::init", titleCase, "(Params&&... params) {\n", "inline typename T::Builder ", scope, "Builder::init", titleCase, "(Params&&... params) {\n",
unionSet, unionDiscrim.set,
" return ::capnp::_::PointerHelpers<T>::init(\n" " return ::capnp::_::PointerHelpers<T>::init(\n"
" _builder, ", offset, " * ::capnp::POINTERS, ::kj::fwd<Params>(params)...);\n" " _builder, ", offset, " * ::capnp::POINTERS, ::kj::fwd<Params>(params)...);\n"
"}\n" "}\n"
"template <typename T>\n" "template <typename T>\n"
"inline void ", scope, "Builder::adopt", titleCase, "(::capnp::Orphan<T>&& value) {\n", "inline void ", scope, "Builder::adopt", titleCase, "(::capnp::Orphan<T>&& value) {\n",
unionSet, unionDiscrim.set,
" ::capnp::_::PointerHelpers<T>::adopt(\n" " ::capnp::_::PointerHelpers<T>::adopt(\n"
" _builder, ", offset, " * ::capnp::POINTERS, kj::mv(value));\n" " _builder, ", offset, " * ::capnp::POINTERS, kj::mv(value));\n"
"}\n" "}\n"
"template <typename T, typename... Params>\n" "template <typename T, typename... Params>\n"
"inline ::capnp::Orphan<T> ", scope, "Builder::disown", titleCase, "(Params&&... params) {\n", "inline ::capnp::Orphan<T> ", scope, "Builder::disown", titleCase, "(Params&&... params) {\n",
unionCheck, unionDiscrim.check,
" return ::capnp::_::PointerHelpers<T>::disown(\n" " return ::capnp::_::PointerHelpers<T>::disown(\n"
" _builder, ", offset, " * ::capnp::POINTERS, ::kj::fwd<Params>(params)...);\n" " _builder, ", offset, " * ::capnp::POINTERS, ::kj::fwd<Params>(params)...);\n"
"}\n" "}\n"
...@@ -677,32 +693,32 @@ private: ...@@ -677,32 +693,32 @@ private:
kj::strTree( kj::strTree(
"inline bool ", scope, "Reader::has", titleCase, "() const {\n", "inline bool ", scope, "Reader::has", titleCase, "() const {\n",
unionCheck, unionDiscrim.check,
" return !_reader.isPointerFieldNull(", offset, " * ::capnp::POINTERS);\n" " return !_reader.isPointerFieldNull(", offset, " * ::capnp::POINTERS);\n"
"}\n" "}\n"
"inline bool ", scope, "Builder::has", titleCase, "() {\n", "inline bool ", scope, "Builder::has", titleCase, "() {\n",
unionCheck, unionDiscrim.check,
" return !_builder.isPointerFieldNull(", offset, " * ::capnp::POINTERS);\n" " return !_builder.isPointerFieldNull(", offset, " * ::capnp::POINTERS);\n"
"}\n" "}\n"
"inline ", type, "::Reader ", scope, "Reader::get", titleCase, "() const {\n", "inline ", type, "::Reader ", scope, "Reader::get", titleCase, "() const {\n",
unionCheck, unionDiscrim.check,
" return ::capnp::_::PointerHelpers<", type, ">::get(\n" " return ::capnp::_::PointerHelpers<", type, ">::get(\n"
" _reader, ", offset, " * ::capnp::POINTERS", defaultParam, ");\n" " _reader, ", offset, " * ::capnp::POINTERS", defaultParam, ");\n"
"}\n" "}\n"
"inline ", type, "::Builder ", scope, "Builder::get", titleCase, "() {\n", "inline ", type, "::Builder ", scope, "Builder::get", titleCase, "() {\n",
unionCheck, unionDiscrim.check,
" return ::capnp::_::PointerHelpers<", type, ">::get(\n" " return ::capnp::_::PointerHelpers<", type, ">::get(\n"
" _builder, ", offset, " * ::capnp::POINTERS", defaultParam, ");\n" " _builder, ", offset, " * ::capnp::POINTERS", defaultParam, ");\n"
"}\n" "}\n"
"inline void ", scope, "Builder::set", titleCase, "(", type, "::Reader value) {\n", "inline void ", scope, "Builder::set", titleCase, "(", type, "::Reader value) {\n",
unionSet, unionDiscrim.set,
" ::capnp::_::PointerHelpers<", type, ">::set(\n" " ::capnp::_::PointerHelpers<", type, ">::set(\n"
" _builder, ", offset, " * ::capnp::POINTERS, value);\n" " _builder, ", offset, " * ::capnp::POINTERS, value);\n"
"}\n", "}\n",
kind == FieldKind::LIST && !isStructList kind == FieldKind::LIST && !isStructList
? kj::strTree( ? kj::strTree(
"inline void ", scope, "Builder::set", titleCase, "(std::initializer_list<", elementReaderType, "> value) {\n", "inline void ", scope, "Builder::set", titleCase, "(std::initializer_list<", elementReaderType, "> value) {\n",
unionSet, unionDiscrim.set,
" ::capnp::_::PointerHelpers<", type, ">::set(\n" " ::capnp::_::PointerHelpers<", type, ">::set(\n"
" _builder, ", offset, " * ::capnp::POINTERS, value);\n" " _builder, ", offset, " * ::capnp::POINTERS, value);\n"
"}\n") "}\n")
...@@ -710,24 +726,24 @@ private: ...@@ -710,24 +726,24 @@ private:
kind == FieldKind::STRUCT kind == FieldKind::STRUCT
? kj::strTree( ? kj::strTree(
"inline ", type, "::Builder ", scope, "Builder::init", titleCase, "() {\n", "inline ", type, "::Builder ", scope, "Builder::init", titleCase, "() {\n",
unionSet, unionDiscrim.set,
" return ::capnp::_::PointerHelpers<", type, ">::init(\n" " return ::capnp::_::PointerHelpers<", type, ">::init(\n"
" _builder, ", offset, " * ::capnp::POINTERS);\n" " _builder, ", offset, " * ::capnp::POINTERS);\n"
"}\n") "}\n")
: kj::strTree( : kj::strTree(
"inline ", type, "::Builder ", scope, "Builder::init", titleCase, "(unsigned int size) {\n", "inline ", type, "::Builder ", scope, "Builder::init", titleCase, "(unsigned int size) {\n",
unionSet, unionDiscrim.set,
" return ::capnp::_::PointerHelpers<", type, ">::init(\n" " return ::capnp::_::PointerHelpers<", type, ">::init(\n"
" _builder, ", offset, " * ::capnp::POINTERS, size);\n" " _builder, ", offset, " * ::capnp::POINTERS, size);\n"
"}\n"), "}\n"),
"inline void ", scope, "Builder::adopt", titleCase, "(\n" "inline void ", scope, "Builder::adopt", titleCase, "(\n"
" ::capnp::Orphan<", type, ">&& value) {\n", " ::capnp::Orphan<", type, ">&& value) {\n",
unionSet, unionDiscrim.set,
" ::capnp::_::PointerHelpers<", type, ">::adopt(\n" " ::capnp::_::PointerHelpers<", type, ">::adopt(\n"
" _builder, ", offset, " * ::capnp::POINTERS, kj::mv(value));\n" " _builder, ", offset, " * ::capnp::POINTERS, kj::mv(value));\n"
"}\n" "}\n"
"inline ::capnp::Orphan<", type, "> ", scope, "Builder::disown", titleCase, "() {\n", "inline ::capnp::Orphan<", type, "> ", scope, "Builder::disown", titleCase, "() {\n",
unionCheck, unionDiscrim.check,
" return ::capnp::_::PointerHelpers<", type, ">::disown(\n" " return ::capnp::_::PointerHelpers<", type, ">::disown(\n"
" _builder, ", offset, " * ::capnp::POINTERS);\n" " _builder, ", offset, " * ::capnp::POINTERS);\n"
"}\n" "}\n"
...@@ -765,11 +781,12 @@ private: ...@@ -765,11 +781,12 @@ private:
" friend class ::capnp::Orphanage;\n" " friend class ::capnp::Orphanage;\n"
" friend ::kj::StringTree KJ_STRINGIFY(", fullName, "::Reader reader);\n" " friend ::kj::StringTree KJ_STRINGIFY(", fullName, "::Reader reader);\n"
"};\n" "};\n"
"\n" "\n",
stringifier.size() > 0 ? kj::strTree(
"inline ::kj::StringTree KJ_STRINGIFY(", fullName, "::Reader reader) {\n" "inline ::kj::StringTree KJ_STRINGIFY(", fullName, "::Reader reader) {\n"
" return ::capnp::_::", stringifier, "<", fullName, ">(reader._reader);\n" " return ::capnp::_::", stringifier, "<", fullName, ">(reader._reader);\n"
"}\n" "}\n"
"\n"); "\n") : kj::strTree());
} }
kj::StringTree makeBuilderDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType, kj::StringTree makeBuilderDef(kj::StringPtr fullName, kj::StringPtr unqualifiedParentType,
...@@ -794,11 +811,12 @@ private: ...@@ -794,11 +811,12 @@ private:
" friend class ::capnp::Orphanage;\n" " friend class ::capnp::Orphanage;\n"
" friend ::kj::StringTree KJ_STRINGIFY(", fullName, "::Builder builder);\n" " friend ::kj::StringTree KJ_STRINGIFY(", fullName, "::Builder builder);\n"
"};\n" "};\n"
"\n" "\n",
stringifier.size() > 0 ? kj::strTree(
"inline ::kj::StringTree KJ_STRINGIFY(", fullName, "::Builder builder) {\n" "inline ::kj::StringTree KJ_STRINGIFY(", fullName, "::Builder builder) {\n"
" return ::capnp::_::", stringifier, "<", fullName, ">(builder._builder.asReader());\n" " return ::capnp::_::", stringifier, "<", fullName, ">(builder._builder.asReader());\n"
"}\n" "}\n"
"\n"); "\n") : kj::strTree());
} }
// ----------------------------------------------------------------- // -----------------------------------------------------------------
...@@ -945,6 +963,12 @@ private: ...@@ -945,6 +963,12 @@ private:
auto fullName = kj::str(containingType, "::", titleCase); auto fullName = kj::str(containingType, "::", titleCase);
auto subText = makeMembersText(namespace_, fullName, member.asGroup().getMembers()); auto subText = makeMembersText(namespace_, fullName, member.asGroup().getMembers());
DiscriminantChecks unionDiscrim;
KJ_IF_MAYBE(u, member.getContainingUnion()) {
unionDiscrim = makeDiscriminantChecks(
kj::str(containingType, "::"), proto.getName(), *u);
}
return MembersText { return MembersText {
kj::strTree( kj::strTree(
" struct ", titleCase, ";\n"), " struct ", titleCase, ";\n"),
...@@ -961,9 +985,9 @@ private: ...@@ -961,9 +985,9 @@ private:
kj::mv(subText.innerTypeDefs)), kj::mv(subText.innerTypeDefs)),
kj::strTree( kj::strTree(
makeReaderDef(fullName, titleCase, "groupString", makeReaderDef(fullName, titleCase, "",
kj::mv(subText.readerMethodDecls)), kj::mv(subText.readerMethodDecls)),
makeBuilderDef(fullName, titleCase, "groupString", makeBuilderDef(fullName, titleCase, "",
kj::mv(subText.builderMethodDecls)), kj::mv(subText.builderMethodDecls)),
kj::mv(subText.innerTypeReaderBuilderDefs)), kj::mv(subText.innerTypeReaderBuilderDefs)),
...@@ -971,26 +995,28 @@ private: ...@@ -971,26 +995,28 @@ private:
" inline ", titleCase, "::Reader get", titleCase, "() const;\n"), " inline ", titleCase, "::Reader get", titleCase, "() const;\n"),
kj::strTree( kj::strTree(
" inline ", titleCase, "::Builder get", titleCase, "();\n"), " inline ", titleCase, "::Builder get", titleCase, "();\n"
" inline ", titleCase, "::Builder init", titleCase, "();\n"),
kj::strTree( kj::strTree(
"inline ", fullName, "::Reader ", containingType, "::Reader::get", titleCase, "() const {\n" "inline ", fullName, "::Reader ", containingType, "::Reader::get", titleCase, "() const {\n",
unionDiscrim.check,
" return ", fullName, "::Reader(_reader);\n" " return ", fullName, "::Reader(_reader);\n"
"}\n" "}\n"
"inline ", fullName, "::Builder ", containingType, "::Builder::get", titleCase, "() {\n" "inline ", fullName, "::Builder ", containingType, "::Builder::get", titleCase, "() {\n",
unionDiscrim.check,
" return ", fullName, "::Builder(_builder);\n"
"}\n"
// TODO(soon): This should really zero out the existing group. Maybe unions should
// support zeroing out the whole union?
"inline ", fullName, "::Builder ", containingType, "::Builder::init", titleCase, "() {\n",
unionDiscrim.set,
" return ", fullName, "::Builder(_builder);\n" " return ", fullName, "::Builder(_builder);\n"
"}\n", "}\n",
kj::mv(subText.inlineMethodDefs)), kj::mv(subText.inlineMethodDefs)),
kj::strTree( kj::mv(subText.capnpPrivateDecls),
"CAPNP_DECLARE_GROUP(\n" kj::mv(subText.capnpPrivateDefs),
" ", namespace_, "::", fullName, ",\n"
" ", namespace_, "::", containingType, ", ", member.getIndex(), ");\n",
kj::mv(subText.capnpPrivateDecls)),
kj::strTree(
"CAPNP_DEFINE_GROUP(\n"
" ", namespace_, "::", fullName, ");\n",
kj::mv(subText.capnpPrivateDefs)),
}; };
} }
} }
......
...@@ -402,6 +402,44 @@ TEST(Encoding, UnnamedUnion) { ...@@ -402,6 +402,44 @@ TEST(Encoding, UnnamedUnion) {
} }
} }
TEST(Encoding, Groups) {
MallocMessageBuilder builder;
auto root = builder.initRoot<test::TestGroups>();
{
auto foo = root.getGroups().initFoo();
foo.setCorge(12345678);
foo.setGrault(123456789012345ll);
foo.setGarply("foobar");
EXPECT_EQ(12345678, foo.getCorge());
EXPECT_EQ(123456789012345ll, foo.getGrault());
EXPECT_EQ("foobar", foo.getGarply());
}
{
auto bar = root.getGroups().initBar();
bar.setCorge(23456789);
bar.setGrault("barbaz");
bar.setGarply(234567890123456ll);
EXPECT_EQ(23456789, bar.getCorge());
EXPECT_EQ("barbaz", bar.getGrault());
EXPECT_EQ(234567890123456ll, bar.getGarply());
}
{
auto baz = root.getGroups().initBaz();
baz.setCorge(34567890);
baz.setGrault("bazqux");
baz.setGarply("quxquux");
EXPECT_EQ(34567890, baz.getCorge());
EXPECT_EQ("bazqux", baz.getGrault());
EXPECT_EQ("quxquux", baz.getGarply());
}
}
TEST(Encoding, UnionDefault) { TEST(Encoding, UnionDefault) {
MallocMessageBuilder builder; MallocMessageBuilder builder;
TestUnionDefaults::Reader reader = builder.getRoot<TestUnionDefaults>().asReader(); TestUnionDefaults::Reader reader = builder.getRoot<TestUnionDefaults>().asReader();
......
...@@ -272,19 +272,19 @@ struct TestUnnamedUnion { ...@@ -272,19 +272,19 @@ struct TestUnnamedUnion {
struct TestGroups { struct TestGroups {
groups union { groups union {
foo group { foo group {
fooCorge @0 :Int32; corge @0 :Int32;
fooGrault @2 :Int64; grault @2 :Int64;
bazGarply @8 :Text; garply @8 :Text;
} }
bar group { bar group {
barCorge @3 :Int32; corge @3 :Int32;
barGrault @4 :Text; grault @4 :Text;
barGarply @5 :Int64; garply @5 :Int64;
} }
baz group { baz group {
bazCorge @1 :Int32; corge @1 :Int32;
bazGrault @6 :Text; grault @6 :Text;
bazGarply @7 :Text; garply @7 :Text;
} }
} }
} }
......
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