Commit e7b9e4da authored by Kenton Varda's avatar Kenton Varda

Schema convenience interface.

parent 80722b03
......@@ -78,5 +78,42 @@ TEST(Blob, Data) {
EXPECT_EQ(Data::Reader("az"), builder.slice(1, 3));
}
TEST(Blob, Compare) {
EXPECT_TRUE (Data::Reader("foo") == Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foo") != Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("foo") <= Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("foo") >= Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foo") < Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foo") > Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foo") == Data::Reader("bar"));
EXPECT_TRUE (Data::Reader("foo") != Data::Reader("bar"));
EXPECT_FALSE(Data::Reader("foo") <= Data::Reader("bar"));
EXPECT_TRUE (Data::Reader("foo") >= Data::Reader("bar"));
EXPECT_FALSE(Data::Reader("foo") < Data::Reader("bar"));
EXPECT_TRUE (Data::Reader("foo") > Data::Reader("bar"));
EXPECT_FALSE(Data::Reader("bar") == Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("bar") != Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("bar") <= Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("bar") >= Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("bar") < Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("bar") > Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foobar") == Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("foobar") != Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foobar") <= Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("foobar") >= Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foobar") < Data::Reader("foo"));
EXPECT_TRUE (Data::Reader("foobar") > Data::Reader("foo"));
EXPECT_FALSE(Data::Reader("foo") == Data::Reader("foobar"));
EXPECT_TRUE (Data::Reader("foo") != Data::Reader("foobar"));
EXPECT_TRUE (Data::Reader("foo") <= Data::Reader("foobar"));
EXPECT_FALSE(Data::Reader("foo") >= Data::Reader("foobar"));
EXPECT_TRUE (Data::Reader("foo") < Data::Reader("foobar"));
EXPECT_FALSE(Data::Reader("foo") > Data::Reader("foobar"));
}
} // namespace
} // namespace capnproto
......@@ -114,12 +114,8 @@ public:
typedef Text Reads;
inline Reader(): Data::Reader("", 0) {}
inline Reader(const char* text): Data::Reader(text, strlen(text)) {
CAPNPROTO_INLINE_DPRECOND(text[size()] == '\0', "Text must be NUL-terminated.");
}
inline Reader(char* text): Data::Reader(text, strlen(text)) {
CAPNPROTO_INLINE_DPRECOND(text[size()] == '\0', "Text must be NUL-terminated.");
}
inline Reader(const char* text): Data::Reader(text, strlen(text)) {}
inline Reader(char* text): Data::Reader(text, strlen(text)) {}
inline Reader(const char* text, uint size): Data::Reader(text, size) {
CAPNPROTO_INLINE_DPRECOND(text[size] == '\0', "Text must be NUL-terminated.");
}
......
......@@ -121,8 +121,29 @@ struct PointerHelpers<TrustedMessage> {
#endif
struct RawSchema {
// The generated code defines a constant RawSchema for every compiled declaration.
//
// This is an internal structure which could change in the future.
const word* encodedNode;
// Encoded SchemaNode, readable via readMessageTrusted<schema::Node>(encodedNode).
const RawSchema* const* dependencies;
// Pointers to other types on which this one depends, sorted by ID.
// TODO(someday): Make this a hashtable.
struct MemberInfo {
uint16_t unionIndex; // 0 = not in a union, >0 = parent union's index + 1
uint16_t index; // index of the member
};
const MemberInfo* membersByName;
// Indexes of members sorted by name. Used to implement name lookup.
// TODO(someday): Make this a hashtable.
uint32_t dependencyCount;
uint32_t memberCount;
// Sizes of above tables.
};
template <typename T>
......
......@@ -179,14 +179,14 @@ static typename RootType::Reader readMessageTrusted(const word* data);
// To create a trusted message, build a message using a MallocAllocator whose preferred segment
// size is larger than the message size. This guarantees that the message will be allocated as a
// single segment, meaning getSegmentsForOutput() returns a single word array. That word array
// is your message; you may pass a pointer to its first word into readTrusted() to read the
// is your message; you may pass a pointer to its first word into readMessageTrusted() to read the
// message.
//
// This can be particularly handy for embedding messages in generated code: you can
// embed the raw bytes (using AlignedData) then make a Reader for it using this. This is the way
// default values are embedded in code generated by the Cap'n Proto compiler. E.g., if you have
// a message MyMessage, you can read its default value like so:
// MyMessage::Reader reader = Message<MyMessage>::ReadTrusted(MyMessage::DEFAULT.words);
// MyMessage::Reader reader = Message<MyMessage>::readMessageTrusted(MyMessage::DEFAULT.words);
template <typename Type>
static typename Type::Reader defaultValue();
......
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "schema.h"
#include <gtest/gtest.h>
#include "test-util.h"
namespace capnproto {
namespace internal {
namespace {
TEST(Schema, Structs) {
StructSchema schema = Schema::from<TestAllTypes>();
EXPECT_EQ(typeId<TestAllTypes>(), schema.getProto().getId());
EXPECT_TRUE(schema.getDependency(typeId<TestEnum>()) == Schema::from<TestEnum>());
EXPECT_TRUE(schema.getDependency(typeId<TestEnum>()) != schema);
EXPECT_TRUE(schema.getDependency(typeId<TestAllTypes>()) == Schema::from<TestAllTypes>());
EXPECT_TRUE(schema.getDependency(typeId<TestAllTypes>()) == schema);
EXPECT_ANY_THROW(schema.getDependency(typeId<TestDefaults>()));
EXPECT_TRUE(schema.asStruct() == schema);
EXPECT_ANY_THROW(schema.asEnum());
EXPECT_ANY_THROW(schema.asInterface());
ASSERT_EQ(schema.members().size(),
schema.getProto().getBody().getStructNode().getMembers().size());
StructSchema::Member member = schema.members()[0];
EXPECT_EQ("voidField", member.getProto().getName());
EXPECT_TRUE(member.getContainingStruct() == schema);
EXPECT_TRUE(member.getContainingUnion() == nullptr);
EXPECT_ANY_THROW(member.asUnion());
Maybe<StructSchema::Member> lookup = schema.findMemberByName("voidField");
ASSERT_TRUE(lookup != nullptr);
EXPECT_TRUE(*lookup == member);
EXPECT_TRUE(*lookup != schema.members()[1]);
EXPECT_TRUE(schema.findMemberByName("noSuchField") == nullptr);
EXPECT_TRUE(schema.findMemberByName("int32Field") != nullptr);
EXPECT_TRUE(schema.findMemberByName("float32List") != nullptr);
EXPECT_TRUE(schema.findMemberByName("dataList") != nullptr);
EXPECT_TRUE(schema.findMemberByName("textField") != nullptr);
EXPECT_TRUE(schema.findMemberByName("structField") != nullptr);
}
TEST(Schema, FieldLookupOutOfOrder) {
// Tests that name lookup works correctly when the fields are defined out-of-order in the schema
// file.
auto schema = Schema::from<test::TestOutOfOrder>().asStruct();
EXPECT_EQ("qux", schema.members()[0].getProto().getName());
EXPECT_EQ("grault", schema.members()[1].getProto().getName());
EXPECT_EQ("bar", schema.members()[2].getProto().getName());
EXPECT_EQ("foo", schema.members()[3].getProto().getName());
EXPECT_EQ("corge", schema.members()[4].getProto().getName());
EXPECT_EQ("waldo", schema.members()[5].getProto().getName());
EXPECT_EQ("quux", schema.members()[6].getProto().getName());
EXPECT_EQ("garply", schema.members()[7].getProto().getName());
EXPECT_EQ("baz", schema.members()[8].getProto().getName());
EXPECT_EQ(3, schema.findMemberByName("foo")->getProto().getOrdinal());
EXPECT_EQ(2, schema.findMemberByName("bar")->getProto().getOrdinal());
EXPECT_EQ(8, schema.findMemberByName("baz")->getProto().getOrdinal());
EXPECT_EQ(0, schema.findMemberByName("qux")->getProto().getOrdinal());
EXPECT_EQ(6, schema.findMemberByName("quux")->getProto().getOrdinal());
EXPECT_EQ(4, schema.findMemberByName("corge")->getProto().getOrdinal());
EXPECT_EQ(1, schema.findMemberByName("grault")->getProto().getOrdinal());
EXPECT_EQ(7, schema.findMemberByName("garply")->getProto().getOrdinal());
EXPECT_EQ(5, schema.findMemberByName("waldo")->getProto().getOrdinal());
}
TEST(Schema, Unions) {
auto schema = Schema::from<TestUnion>().asStruct();
EXPECT_TRUE(schema.findMemberByName("bit0") != nullptr);
EXPECT_TRUE(schema.findMemberByName("u1f0s8") == nullptr);
auto maybeUnion1 = schema.findMemberByName("union1");
ASSERT_TRUE(maybeUnion1 != nullptr);
auto union1 = maybeUnion1->asUnion();
EXPECT_TRUE(union1.findMemberByName("bin0") == nullptr);
EXPECT_TRUE(union1.getContainingUnion() == nullptr);
auto maybeU1f0s8 = union1.findMemberByName("u1f0s8");
ASSERT_TRUE(maybeU1f0s8 != nullptr);
auto u1f0s8 = *maybeU1f0s8;
EXPECT_EQ("u1f0s8", u1f0s8.getProto().getName());
EXPECT_TRUE(u1f0s8.getContainingStruct() == schema);
EXPECT_TRUE(*u1f0s8.getContainingUnion() == union1);
EXPECT_TRUE(union1.findMemberByName("u1f1s8") != nullptr);
EXPECT_TRUE(union1.findMemberByName("u1f0s32") != nullptr);
EXPECT_TRUE(union1.findMemberByName("u1f0sp") != nullptr);
EXPECT_TRUE(union1.findMemberByName("u1f1s1") != nullptr);
EXPECT_TRUE(union1.findMemberByName("u0f0s1") == nullptr);
EXPECT_TRUE(union1.findMemberByName("u2f0s8") == nullptr);
EXPECT_TRUE(union1.findMemberByName("noSuchField") == nullptr);
}
TEST(Schema, Enums) {
EnumSchema schema = Schema::from<TestEnum>();
EXPECT_EQ(typeId<TestEnum>(), schema.getProto().getId());
EXPECT_ANY_THROW(schema.getDependency(typeId<TestAllTypes>()));
EXPECT_ANY_THROW(schema.getDependency(typeId<TestEnum>()));
EXPECT_ANY_THROW(schema.asStruct());
EXPECT_ANY_THROW(schema.asInterface());
EXPECT_TRUE(schema.asEnum() == schema);
ASSERT_EQ(schema.enumerants().size(),
schema.getProto().getBody().getEnumNode().getEnumerants().size());
EnumSchema::Enumerant enumerant = schema.enumerants()[0];
EXPECT_EQ("foo", enumerant.getProto().getName());
EXPECT_TRUE(enumerant.getContainingEnum() == schema);
Maybe<EnumSchema::Enumerant> lookup = schema.findEnumerantByName("foo");
ASSERT_TRUE(lookup != nullptr);
EXPECT_TRUE(*lookup == enumerant);
EXPECT_TRUE(*lookup != schema.enumerants()[1]);
EXPECT_TRUE(schema.findEnumerantByName("noSuchEnumerant") == nullptr);
EXPECT_TRUE(schema.findEnumerantByName("bar") != nullptr);
EXPECT_TRUE(schema.findEnumerantByName("qux") != nullptr);
EXPECT_TRUE(schema.findEnumerantByName("corge") != nullptr);
EXPECT_TRUE(schema.findEnumerantByName("grault") != nullptr);
}
// TODO(someday): Test interface schemas when interfaces are implemented.
TEST(Schema, Lists) {
EXPECT_EQ(schema::Type::Body::VOID_TYPE, Schema::from<List<Void>>().whichElementType());
EXPECT_EQ(schema::Type::Body::BOOL_TYPE, Schema::from<List<bool>>().whichElementType());
EXPECT_EQ(schema::Type::Body::INT8_TYPE, Schema::from<List<int8_t>>().whichElementType());
EXPECT_EQ(schema::Type::Body::INT16_TYPE, Schema::from<List<int16_t>>().whichElementType());
EXPECT_EQ(schema::Type::Body::INT32_TYPE, Schema::from<List<int32_t>>().whichElementType());
EXPECT_EQ(schema::Type::Body::INT64_TYPE, Schema::from<List<int64_t>>().whichElementType());
EXPECT_EQ(schema::Type::Body::UINT8_TYPE, Schema::from<List<uint8_t>>().whichElementType());
EXPECT_EQ(schema::Type::Body::UINT16_TYPE, Schema::from<List<uint16_t>>().whichElementType());
EXPECT_EQ(schema::Type::Body::UINT32_TYPE, Schema::from<List<uint32_t>>().whichElementType());
EXPECT_EQ(schema::Type::Body::UINT64_TYPE, Schema::from<List<uint64_t>>().whichElementType());
EXPECT_EQ(schema::Type::Body::FLOAT32_TYPE, Schema::from<List<float>>().whichElementType());
EXPECT_EQ(schema::Type::Body::FLOAT64_TYPE, Schema::from<List<double>>().whichElementType());
EXPECT_EQ(schema::Type::Body::TEXT_TYPE, Schema::from<List<Text>>().whichElementType());
EXPECT_EQ(schema::Type::Body::DATA_TYPE, Schema::from<List<Data>>().whichElementType());
EXPECT_ANY_THROW(Schema::from<List<uint16_t>>().getStructElementType());
EXPECT_ANY_THROW(Schema::from<List<uint16_t>>().getEnumElementType());
EXPECT_ANY_THROW(Schema::from<List<uint16_t>>().getInterfaceElementType());
EXPECT_ANY_THROW(Schema::from<List<uint16_t>>().getListElementType());
{
ListSchema schema = Schema::from<List<TestAllTypes>>();
EXPECT_EQ(schema::Type::Body::STRUCT_TYPE, schema.whichElementType());
EXPECT_TRUE(schema.getStructElementType() == Schema::from<TestAllTypes>());
EXPECT_ANY_THROW(schema.getEnumElementType());
EXPECT_ANY_THROW(schema.getInterfaceElementType());
EXPECT_ANY_THROW(schema.getListElementType());
}
{
ListSchema schema = Schema::from<List<TestEnum>>();
EXPECT_EQ(schema::Type::Body::ENUM_TYPE, schema.whichElementType());
EXPECT_TRUE(schema.getEnumElementType() == Schema::from<TestEnum>());
EXPECT_ANY_THROW(schema.getStructElementType());
EXPECT_ANY_THROW(schema.getInterfaceElementType());
EXPECT_ANY_THROW(schema.getListElementType());
}
// TODO(someday): Test interfaces.
{
ListSchema schema = Schema::from<List<List<int32_t>>>();
EXPECT_EQ(schema::Type::Body::LIST_TYPE, schema.whichElementType());
EXPECT_ANY_THROW(schema.getStructElementType());
EXPECT_ANY_THROW(schema.getEnumElementType());
EXPECT_ANY_THROW(schema.getInterfaceElementType());
ListSchema inner = schema.getListElementType();
EXPECT_EQ(schema::Type::Body::INT32_TYPE, inner.whichElementType());
}
{
ListSchema schema = Schema::from<List<List<TestAllTypes>>>();
EXPECT_EQ(schema::Type::Body::LIST_TYPE, schema.whichElementType());
EXPECT_ANY_THROW(schema.getStructElementType());
EXPECT_ANY_THROW(schema.getEnumElementType());
EXPECT_ANY_THROW(schema.getInterfaceElementType());
ListSchema inner = schema.getListElementType();
EXPECT_EQ(schema::Type::Body::STRUCT_TYPE, inner.whichElementType());
EXPECT_TRUE(inner.getStructElementType() == Schema::from<TestAllTypes>());
}
{
ListSchema schema = Schema::from<List<List<TestEnum>>>();
EXPECT_EQ(schema::Type::Body::LIST_TYPE, schema.whichElementType());
EXPECT_ANY_THROW(schema.getStructElementType());
EXPECT_ANY_THROW(schema.getEnumElementType());
EXPECT_ANY_THROW(schema.getInterfaceElementType());
ListSchema inner = schema.getListElementType();
EXPECT_EQ(schema::Type::Body::ENUM_TYPE, inner.whichElementType());
EXPECT_TRUE(inner.getEnumElementType() == Schema::from<TestEnum>());
}
{
auto context = Schema::from<TestAllTypes>();
auto type = context.findMemberByName("enumList")
->getProto().getBody().getFieldMember().getType();
ListSchema schema = ListSchema::of(type.getBody().getListType(), context);
EXPECT_EQ(schema::Type::Body::ENUM_TYPE, schema.whichElementType());
EXPECT_TRUE(schema.getEnumElementType() == Schema::from<TestEnum>());
EXPECT_ANY_THROW(schema.getStructElementType());
EXPECT_ANY_THROW(schema.getInterfaceElementType());
EXPECT_ANY_THROW(schema.getListElementType());
}
}
} // namespace
} // namespace internal
} // namespace capnproto
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define CAPNPROTO_PRIVATE
#include "schema.h"
#include "message.h"
#include "logging.h"
namespace capnproto {
schema::Node::Reader Schema::getProto() const {
return readMessageTrusted<schema::Node>(raw->encodedNode);
}
Schema Schema::getDependency(uint64_t id) const {
uint lower = 0;
uint upper = raw->dependencyCount;
while (lower < upper) {
uint mid = (lower + upper) / 2;
Schema candidate(raw->dependencies[mid]);
uint64_t candidateId = candidate.getProto().getId();
if (candidateId == id) {
return candidate;
} else if (candidateId < id) {
lower = mid + 1;
} else {
upper = mid;
}
}
FAIL_PRECOND("Requested ID not found in dependency table.", id);
return Schema();
}
StructSchema Schema::asStruct() const {
PRECOND(getProto().getBody().which() == schema::Node::Body::STRUCT_NODE,
"Tried to use non-struct schema as a struct.",
getProto().getDisplayName());
return StructSchema(raw);
}
EnumSchema Schema::asEnum() const {
PRECOND(getProto().getBody().which() == schema::Node::Body::ENUM_NODE,
"Tried to use non-enum schema as an enum.",
getProto().getDisplayName());
return EnumSchema(raw);
}
InterfaceSchema Schema::asInterface() const {
PRECOND(getProto().getBody().which() == schema::Node::Body::INTERFACE_NODE,
"Tried to use non-interface schema as an interface.",
getProto().getDisplayName());
return InterfaceSchema(raw);
}
// =======================================================================================
namespace {
template <typename List>
auto findSchemaMemberByName(const internal::RawSchema* raw, Text::Reader name,
uint unionIndex, List&& list)
-> Maybe<RemoveReference<decltype(list[0])>> {
uint lower = 0;
uint upper = raw->memberCount;
while (lower < upper) {
uint mid = (lower + upper) / 2;
const internal::RawSchema::MemberInfo& member = raw->membersByName[mid];
if (member.unionIndex == unionIndex) {
auto candidate = list[member.index];
Text::Reader candidateName = candidate.getProto().getName();
if (candidateName == name) {
return candidate;
} else if (candidateName < name) {
lower = mid + 1;
} else {
upper = mid;
}
} else if (member.unionIndex < unionIndex) {
lower = mid + 1;
} else {
upper = mid;
}
}
return nullptr;
}
} // namespace
StructSchema::MemberList StructSchema::members() const {
return MemberList(*this, 0, getProto().getBody().getStructNode().getMembers());
}
Maybe<StructSchema::Member> StructSchema::findMemberByName(Text::Reader name) const {
return findSchemaMemberByName(raw, name, 0, members());
}
Maybe<StructSchema::Union> StructSchema::Member::getContainingUnion() const {
if (unionIndex == 0) return nullptr;
return parent.members()[unionIndex - 1].asUnion();
}
StructSchema::Union StructSchema::Member::asUnion() const {
PRECOND(proto.getBody().which() == schema::StructNode::Member::Body::UNION_MEMBER,
"Tried to use non-union struct member as a union.",
parent.getProto().getDisplayName(), proto.getName());
return Union(*this);
}
StructSchema::MemberList StructSchema::Union::members() const {
return MemberList(parent, index + 1, proto.getBody().getUnionMember().getMembers());
}
Maybe<StructSchema::Member> StructSchema::Union::findMemberByName(Text::Reader name) const {
return findSchemaMemberByName(parent.raw, name, index + 1, members());
}
// -------------------------------------------------------------------
EnumSchema::EnumerantList EnumSchema::enumerants() const {
return EnumerantList(*this, getProto().getBody().getEnumNode().getEnumerants());
}
Maybe<EnumSchema::Enumerant> EnumSchema::findEnumerantByName(Text::Reader name) const {
return findSchemaMemberByName(raw, name, 0, enumerants());
}
// -------------------------------------------------------------------
InterfaceSchema::MethodList InterfaceSchema::methods() const {
return MethodList(*this, getProto().getBody().getInterfaceNode().getMethods());
}
Maybe<InterfaceSchema::Method> InterfaceSchema::findMethodByName(Text::Reader name) const {
return findSchemaMemberByName(raw, name, 0, methods());
}
// =======================================================================================
ListSchema ListSchema::of(schema::Type::Body::Which primitiveType) {
switch (primitiveType) {
case schema::Type::Body::VOID_TYPE:
case schema::Type::Body::BOOL_TYPE:
case schema::Type::Body::INT8_TYPE:
case schema::Type::Body::INT16_TYPE:
case schema::Type::Body::INT32_TYPE:
case schema::Type::Body::INT64_TYPE:
case schema::Type::Body::UINT8_TYPE:
case schema::Type::Body::UINT16_TYPE:
case schema::Type::Body::UINT32_TYPE:
case schema::Type::Body::UINT64_TYPE:
case schema::Type::Body::FLOAT32_TYPE:
case schema::Type::Body::FLOAT64_TYPE:
case schema::Type::Body::TEXT_TYPE:
case schema::Type::Body::DATA_TYPE:
break;
case schema::Type::Body::STRUCT_TYPE:
case schema::Type::Body::ENUM_TYPE:
case schema::Type::Body::INTERFACE_TYPE:
case schema::Type::Body::LIST_TYPE:
FAIL_PRECOND("Must use one of the other ListSchema::of() overloads for complex types.");
break;
case schema::Type::Body::OBJECT_TYPE:
FAIL_PRECOND("List(Object) not supported.");
break;
}
return ListSchema(primitiveType);
}
ListSchema ListSchema::of(schema::Type::Reader elementType, Schema context) {
auto body = elementType.getBody();
switch (body.which()) {
case schema::Type::Body::VOID_TYPE:
case schema::Type::Body::BOOL_TYPE:
case schema::Type::Body::INT8_TYPE:
case schema::Type::Body::INT16_TYPE:
case schema::Type::Body::INT32_TYPE:
case schema::Type::Body::INT64_TYPE:
case schema::Type::Body::UINT8_TYPE:
case schema::Type::Body::UINT16_TYPE:
case schema::Type::Body::UINT32_TYPE:
case schema::Type::Body::UINT64_TYPE:
case schema::Type::Body::FLOAT32_TYPE:
case schema::Type::Body::FLOAT64_TYPE:
case schema::Type::Body::TEXT_TYPE:
case schema::Type::Body::DATA_TYPE:
return of(body.which());
case schema::Type::Body::STRUCT_TYPE:
return of(context.getDependency(body.getStructType()).asStruct());
case schema::Type::Body::ENUM_TYPE:
return of(context.getDependency(body.getEnumType()).asEnum());
case schema::Type::Body::INTERFACE_TYPE:
return of(context.getDependency(body.getInterfaceType()).asInterface());
case schema::Type::Body::LIST_TYPE:
return of(of(body.getListType(), context));
case schema::Type::Body::OBJECT_TYPE:
FAIL_PRECOND("List(Object) not supported.");
return ListSchema();
}
FAIL_CHECK("missing switch case");
return ListSchema();
}
StructSchema ListSchema::getStructElementType() const {
PRECOND(nestingDepth == 0 && elementType == schema::Type::Body::STRUCT_TYPE,
"ListSchema::getStructElementType(): The elements are not structs.");
return elementSchema.asStruct();
}
EnumSchema ListSchema::getEnumElementType() const {
PRECOND(nestingDepth == 0 && elementType == schema::Type::Body::ENUM_TYPE,
"ListSchema::getEnumElementType(): The elements are not enums.");
return elementSchema.asEnum();
}
InterfaceSchema ListSchema::getInterfaceElementType() const {
PRECOND(nestingDepth == 0 && elementType == schema::Type::Body::INTERFACE_TYPE,
"ListSchema::getInterfaceElementType(): The elements are not interfaces.");
return elementSchema.asInterface();
}
ListSchema ListSchema::getListElementType() const {
PRECOND(nestingDepth > 0,
"ListSchema::getListElementType(): The elements are not lists.");
return ListSchema(elementType, nestingDepth - 1, elementSchema);
}
} // namespace capnproto
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CAPNPROTO_SCHEMA_H_
#define CAPNPROTO_SCHEMA_H_
#include "schema.capnp.h"
namespace capnproto {
class Schema;
class StructSchema;
class EnumSchema;
class InterfaceSchema;
class ListSchema;
template <typename T, Kind k = kind<T>()> struct SchemaType_ { typedef Schema Type; };
template <typename T> struct SchemaType_<T, Kind::PRIMITIVE> { typedef schema::Type::Body::Which Type; };
template <typename T> struct SchemaType_<T, Kind::BLOB> { typedef schema::Type::Body::Which Type; };
template <typename T> struct SchemaType_<T, Kind::ENUM> { typedef EnumSchema Type; };
template <typename T> struct SchemaType_<T, Kind::STRUCT> { typedef StructSchema Type; };
template <typename T> struct SchemaType_<T, Kind::INTERFACE> { typedef InterfaceSchema Type; };
template <typename T> struct SchemaType_<T, Kind::LIST> { typedef ListSchema Type; };
template <typename T>
using SchemaType = typename SchemaType_<T>::Type;
// SchemaType<T> is the type of T's schema, e.g. StructSchema if T is a struct.
class Schema {
// Convenience wrapper around capnproto::schema::Node.
public:
inline Schema(): raw(nullptr) {}
template <typename T>
static inline SchemaType<T> from() { return SchemaType<T>::template fromImpl<T>(); }
// Get the Schema for a particular compiled-in type.
schema::Node::Reader getProto() const;
Schema getDependency(uint64_t id) const;
// Gets the Schema for one of this Schema's dependencies. For example, if this Schema is for a
// struct, you could look up the schema for one of its fields' types. Throws an exception if this
// schema doesn't actually depend on the given id. Note that annotation declarations are not
// considered dependencies for this purpose.
StructSchema asStruct() const;
EnumSchema asEnum() const;
InterfaceSchema asInterface() const;
// Cast the Schema to a specific type. Throws an exception if the type doesn't match.
inline bool operator==(const Schema& other) const { return raw == other.raw; }
inline bool operator!=(const Schema& other) const { return raw != other.raw; }
// Determine whether two Schemas are wrapping the exact same underlying data, by identity. If
// you want to check if two Schemas represent the same type (but possibly different versions of
// it), compare their IDs instead.
private:
const internal::RawSchema* raw;
inline explicit Schema(const internal::RawSchema* raw): raw(raw) {}
template <typename T> static inline Schema fromImpl() {
return Schema(&internal::rawSchema<T>());
}
friend class StructSchema;
friend class EnumSchema;
friend class InterfaceSchema;
};
// -------------------------------------------------------------------
class StructSchema: public Schema {
public:
StructSchema() = default;
class Member;
class Union;
class MemberList;
MemberList members() const;
Maybe<Member> findMemberByName(Text::Reader name) const;
private:
StructSchema(const internal::RawSchema* raw): Schema(raw) {}
template <typename T> static inline StructSchema fromImpl() {
return StructSchema(&internal::rawSchema<T>());
}
friend class Schema;
};
class StructSchema::Member {
public:
Member() = default;
inline schema::StructNode::Member::Reader getProto() const { return proto; }
inline StructSchema getContainingStruct() const { return parent; }
inline uint getIndex() const { return index; }
// Get the index of this member within the containing struct or union.
Maybe<Union> getContainingUnion() const;
// If this a member of a union, gets the containing union schema.
Union asUnion() const;
// Cast the member to a Union. Throws an exception if not a union.
inline bool operator==(const Member& other) const;
inline bool operator!=(const Member& other) const { return !(*this == other); }
private:
StructSchema parent;
uint unionIndex; // 0 = none, >0 = actual union index - 1
uint index;
mutable schema::StructNode::Member::Reader proto;
// TODO(soon): Make all reader methods const and then remove this ugly use of "mutable".
inline Member(StructSchema parent, uint unionIndex, uint index,
schema::StructNode::Member::Reader proto)
: parent(parent), unionIndex(unionIndex), index(index), proto(proto) {}
friend class StructSchema;
};
class StructSchema::Union: public Member {
public:
Union() = default;
MemberList members() const;
Maybe<Member> findMemberByName(Text::Reader name) const;
private:
inline Union(const Member& base): Member(base) {}
friend class StructSchema;
};
class StructSchema::MemberList {
public:
inline uint size() const { return list.size(); }
inline Member operator[](uint index) const { return Member(parent, unionIndex, index, list[index]); }
typedef internal::IndexingIterator<MemberList, Member> iterator;
inline iterator begin() const { return iterator(this, 0); }
inline iterator end() const { return iterator(this, size()); }
private:
StructSchema parent;
uint unionIndex;
List<schema::StructNode::Member>::Reader list;
inline MemberList(StructSchema parent, uint unionIndex,
List<schema::StructNode::Member>::Reader list)
: parent(parent), unionIndex(unionIndex), list(list) {}
friend class StructSchema;
};
// -------------------------------------------------------------------
class EnumSchema: public Schema {
public:
class Enumerant;
class EnumerantList;
EnumerantList enumerants() const;
Maybe<Enumerant> findEnumerantByName(Text::Reader name) const;
private:
EnumSchema(const internal::RawSchema* raw): Schema(raw) {}
template <typename T> static inline EnumSchema fromImpl() {
return EnumSchema(&internal::rawSchema<T>());
}
friend class Schema;
};
class EnumSchema::Enumerant {
public:
Enumerant() = default;
inline schema::EnumNode::Enumerant::Reader getProto() const { return proto; }
inline EnumSchema getContainingEnum() { return parent; }
inline uint16_t getOrdinal() { return ordinal; }
inline bool operator==(const Enumerant& other) const;
inline bool operator!=(const Enumerant& other) const { return !(*this == other); }
private:
EnumSchema parent;
uint16_t ordinal;
mutable schema::EnumNode::Enumerant::Reader proto;
// TODO(soon): Make all reader methods const and then remove this ugly use of "mutable".
inline Enumerant(EnumSchema parent, uint16_t ordinal, schema::EnumNode::Enumerant::Reader proto)
: parent(parent), ordinal(ordinal), proto(proto) {}
friend class EnumSchema;
};
class EnumSchema::EnumerantList {
public:
inline uint size() const { return list.size(); }
inline Enumerant operator[](uint index) const { return Enumerant(parent, index, list[index]); }
typedef internal::IndexingIterator<EnumerantList, Enumerant> iterator;
inline iterator begin() const { return iterator(this, 0); }
inline iterator end() const { return iterator(this, size()); }
private:
EnumSchema parent;
List<schema::EnumNode::Enumerant>::Reader list;
inline EnumerantList(EnumSchema parent, List<schema::EnumNode::Enumerant>::Reader list)
: parent(parent), list(list) {}
friend class EnumSchema;
};
// -------------------------------------------------------------------
class InterfaceSchema: public Schema {
public:
class Method;
class MethodList;
MethodList methods() const;
Maybe<Method> findMethodByName(Text::Reader name) const;
private:
InterfaceSchema(const internal::RawSchema* raw): Schema(raw) {}
template <typename T> static inline InterfaceSchema fromImpl() {
return InterfaceSchema(&internal::rawSchema<T>());
}
friend class Schema;
};
class InterfaceSchema::Method {
public:
Method() = default;
inline schema::InterfaceNode::Method::Reader getProto() const { return proto; }
inline InterfaceSchema getContainingInterface() { return parent; }
inline uint16_t getOrdinal() { return ordinal; }
inline bool operator==(const Method& other) const;
inline bool operator!=(const Method& other) const { return !(*this == other); }
private:
InterfaceSchema parent;
uint16_t ordinal;
mutable schema::InterfaceNode::Method::Reader proto;
// TODO(soon): Make all reader methods const and then remove this ugly use of "mutable".
inline Method(InterfaceSchema parent, uint16_t ordinal,
schema::InterfaceNode::Method::Reader proto)
: parent(parent), ordinal(ordinal), proto(proto) {}
friend class InterfaceSchema;
};
class InterfaceSchema::MethodList {
public:
inline uint size() const { return list.size(); }
inline Method operator[](uint index) const { return Method(parent, index, list[index]); }
typedef internal::IndexingIterator<MethodList, Method> iterator;
inline iterator begin() const { return iterator(this, 0); }
inline iterator end() const { return iterator(this, size()); }
private:
InterfaceSchema parent;
List<schema::InterfaceNode::Method>::Reader list;
inline MethodList(InterfaceSchema parent, List<schema::InterfaceNode::Method>::Reader list)
: parent(parent), list(list) {}
friend class InterfaceSchema;
};
// -------------------------------------------------------------------
class ListSchema {
// ListSchema is a little different because list types are not described by schema nodes. So,
// ListSchema doesn't subclass Schema.
public:
ListSchema() = default;
static ListSchema of(schema::Type::Body::Which primitiveType);
static ListSchema of(StructSchema elementType);
static ListSchema of(EnumSchema elementType);
static ListSchema of(InterfaceSchema elementType);
static ListSchema of(ListSchema elementType);
// Construct the schema for a list of the given type.
static ListSchema of(schema::Type::Reader elementType, Schema context);
// Construct from an element type schema. Requires a context which can handle getDependency()
// requests for any type ID found in the schema.
inline schema::Type::Body::Which whichElementType() const;
// Get the element type's "which()". ListSchema does not actually store a schema::Type::Reader
// describing the element type, but if it did, this would be equivalent to calling
// .getBody().which() on that type.
StructSchema getStructElementType() const;
EnumSchema getEnumElementType() const;
InterfaceSchema getInterfaceElementType() const;
ListSchema getListElementType() const;
// Get the schema for complex element types. Each of these throws an exception if the element
// type is not of the requested kind.
private:
schema::Type::Body::Which elementType;
uint8_t nestingDepth; // 0 for T, 1 for List(T), 2 for List(List(T)), ...
Schema elementSchema; // if elementType is struct, enum, interface...
inline ListSchema(schema::Type::Body::Which elementType)
: elementType(elementType), nestingDepth(0) {}
inline ListSchema(schema::Type::Body::Which elementType, Schema elementSchema)
: elementType(elementType), nestingDepth(0), elementSchema(elementSchema) {}
inline ListSchema(schema::Type::Body::Which elementType, uint8_t nestingDepth,
Schema elementSchema)
: elementType(elementType), nestingDepth(nestingDepth), elementSchema(elementSchema) {}
template <typename T>
struct FromImpl;
template <typename T> static inline ListSchema fromImpl() {
return FromImpl<T>::get();
}
friend class Schema;
};
// =======================================================================================
// inline implementation
template <> inline schema::Type::Body::Which Schema::from<Void>() { return schema::Type::Body::VOID_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<bool>() { return schema::Type::Body::BOOL_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<int8_t>() { return schema::Type::Body::INT8_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<int16_t>() { return schema::Type::Body::INT16_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<int32_t>() { return schema::Type::Body::INT32_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<int64_t>() { return schema::Type::Body::INT64_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<uint8_t>() { return schema::Type::Body::UINT8_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<uint16_t>() { return schema::Type::Body::UINT16_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<uint32_t>() { return schema::Type::Body::UINT32_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<uint64_t>() { return schema::Type::Body::UINT64_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<float>() { return schema::Type::Body::FLOAT32_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<double>() { return schema::Type::Body::FLOAT64_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<Text>() { return schema::Type::Body::TEXT_TYPE; }
template <> inline schema::Type::Body::Which Schema::from<Data>() { return schema::Type::Body::DATA_TYPE; }
inline bool StructSchema::Member::operator==(const Member& other) const {
return parent == other.parent && unionIndex == other.unionIndex && index == other.index;
}
inline bool EnumSchema::Enumerant::operator==(const Enumerant& other) const {
return parent == other.parent && ordinal == other.ordinal;
}
inline bool InterfaceSchema::Method::operator==(const Method& other) const {
return parent == other.parent && ordinal == other.ordinal;
}
inline ListSchema ListSchema::of(StructSchema elementType) {
return ListSchema(schema::Type::Body::STRUCT_TYPE, 0, elementType);
}
inline ListSchema ListSchema::of(EnumSchema elementType) {
return ListSchema(schema::Type::Body::ENUM_TYPE, 0, elementType);
}
inline ListSchema ListSchema::of(InterfaceSchema elementType) {
return ListSchema(schema::Type::Body::INTERFACE_TYPE, 0, elementType);
}
inline ListSchema ListSchema::of(ListSchema elementType) {
return ListSchema(elementType.elementType, elementType.nestingDepth + 1,
elementType.elementSchema);
}
inline schema::Type::Body::Which ListSchema::whichElementType() const {
return nestingDepth == 0 ? elementType : schema::Type::Body::LIST_TYPE;
}
template <typename T>
struct ListSchema::FromImpl<List<T>> {
static inline ListSchema get() { return of(Schema::from<T>()); }
};
} // namespace capnproto
#endif // CAPNPROTO_SCHEMA_H_
......@@ -164,6 +164,18 @@ struct TestObject {
objectField @0 :Object;
}
struct TestOutOfOrder {
foo @3 :Text;
bar @2 :Text;
baz @8 :Text;
qux @0 :Text;
quux @6 :Text;
corge @4 :Text;
grault @1 :Text;
garply @7 :Text;
waldo @5 :Text;
}
struct TestUnion {
union0 @0 union {
# Pack union 0 under ideal conditions: there is no unused padding space prior to it.
......
......@@ -32,9 +32,10 @@ import qualified Data.Digest.MD5 as MD5
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.List as List
import Data.Maybe(catMaybes)
import Data.Maybe(catMaybes, mapMaybe)
import Data.Binary.IEEE754(floatToWord, doubleToWord)
import Data.Map((!))
import Data.Function(on)
import Text.Printf(printf)
import Text.Hastache
import Text.Hastache.Context
......@@ -277,11 +278,47 @@ descDependencies (DescMethod d) =
concat $ typeDependencies (methodReturnType d) : map paramDependencies (methodParams d)
descDependencies _ = []
memberIndexes :: Int -> [(Int, Int)]
memberIndexes unionIndex = zip (repeat unionIndex) [0..]
memberTable (DescStruct desc) = let
-- Fields and unions of the struct.
topMembers = zip (memberIndexes 0) $ mapMaybe memberName
$ List.sortBy (compare `on` ordinal) $ structMembers desc
-- Fields of each union.
innerMembers = zipWith indexedUnionMembers [1..]
$ List.sortBy (compare `on` unionNumber) $ structUnions desc
ordinal (DescField f) = fieldNumber f
ordinal (DescUnion u) = unionNumber u
ordinal _ = 65536 -- doesn't really matter what this is; will be filtered out later
memberName (DescField f) = Just $ fieldName f
memberName (DescUnion u) = Just $ unionName u
memberName _ = Nothing
indexedUnionMembers i u = zip (memberIndexes i) $ mapMaybe memberName
$ List.sortBy (compare `on` ordinal) $ unionMembers u
in concat $ topMembers : innerMembers
memberTable (DescEnum desc) = zip (memberIndexes 0) $ map enumerantName
$ List.sortBy (compare `on` enumerantNumber) $ enumerants desc
memberTable (DescInterface desc) = zip (memberIndexes 0) $ map methodName
$ List.sortBy (compare `on` methodNumber) $ interfaceMethods desc
memberTable _ = []
outerFileContext schemaNodes = fileContext where
schemaDepContext parent i = mkStrContext context where
context "dependencyId" = MuVariable (printf "%016x" i :: String)
context s = parent s
schemaMemberByNameContext parent (ui, mi) = mkStrContext context where
context "memberUnionIndex" = MuVariable ui
context "memberIndex" = MuVariable mi
context s = parent s
schemaContext parent desc = mkStrContext context where
node = schemaNodes ! descId desc
......@@ -289,11 +326,18 @@ outerFileContext schemaNodes = fileContext where
depIds = map head $ List.group $ List.sort $ descDependencies desc
membersByName = map fst $ List.sortBy (compare `on` memberByNameKey) $ memberTable desc
memberByNameKey ((unionIndex, _), name) = (unionIndex, name)
context "schemaWordCount" = MuVariable $ div (length node + 7) 8
context "schemaBytes" = MuVariable $ delimit ",\n " codeLines
context "schemaId" = MuVariable (printf "%016x" (descId desc) :: String)
context "schemaDependencyCount" = MuVariable $ length depIds
context "schemaDependencies" =
MuList $ map (schemaDepContext context) depIds
context "schemaMemberCount" = MuVariable $ length membersByName
context "schemaMembersByName" =
MuList $ map (schemaMemberByNameContext context) membersByName
context s = parent s
enumerantContext parent desc = mkStrContext context where
......
......@@ -64,8 +64,13 @@ static const ::capnproto::internal::RawSchema* const d_{{schemaId}}[] = {
{{/schemaDependencies}}
nullptr
};
static const ::capnproto::internal::RawSchema::MemberInfo m_{{schemaId}}[] = {
{{#schemaMembersByName}}
{ {{memberUnionIndex}}, {{memberIndex}} },
{{/schemaMembersByName}}
};
const ::capnproto::internal::RawSchema s_{{schemaId}} = {
b_{{schemaId}}.words, d_{{schemaId}}
b_{{schemaId}}.words, d_{{schemaId}}, m_{{schemaId}}, {{schemaDependencyCount}}, {{schemaMemberCount}}
};
{{/typeSchema}}
{{/fileTypes}}
......
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