Commit c6712690 authored by Kenton Varda's avatar Kenton Varda

Make Schema default constructors produce consistent, non-crashy values. This…

Make Schema default constructors produce consistent, non-crashy values.  This improves the dynamic interface's robustness, particularly when exceptions are disabled.
parent 5d6ff087
......@@ -250,6 +250,20 @@ TEST(Schema, UnnamedUnion) {
EXPECT_TRUE(schema.findFieldByName("after") != nullptr);
}
TEST(Schema, NullSchemas) {
EXPECT_EQ(0xff, (uint)Schema().getProto().which());
EXPECT_TRUE(StructSchema().getProto().isStruct());
EXPECT_TRUE(EnumSchema().getProto().isEnum());
EXPECT_TRUE(InterfaceSchema().getProto().isInterface());
EXPECT_TRUE(ConstSchema().getProto().isConst());
EXPECT_EQ("(null schema)", Schema().getProto().getDisplayName());
EXPECT_EQ("(null struct schema)", StructSchema().getProto().getDisplayName());
EXPECT_EQ("(null enum schema)", EnumSchema().getProto().getDisplayName());
EXPECT_EQ("(null interface schema)", InterfaceSchema().getProto().getDisplayName());
EXPECT_EQ("(null const schema)", ConstSchema().getProto().getDisplayName());
}
} // namespace
} // namespace _ (private)
} // namespace capnp
......@@ -27,6 +27,161 @@
namespace capnp {
namespace _ { // private
// Null schemas generated using the below schema file with:
//
// capnp eval -Isrc null-schemas.capnp interface --flat |
// hexdump -v -e '8/1 "0x%02x, "' -e '1/8 "\n"'; echo
//
// I totally don't understand hexdump format strings and came up with this command based on trial
// and error.
//
// @0x879863d4b2cc4a1e;
//
// using Node = import "/capnp/schema.capnp".Node;
//
// const node :Node = (
// id = 0x0000000000000000,
// displayName = "(null schema)");
//
// const struct :Node = (
// id = 0x0000000000000001,
// displayName = "(null struct schema)",
// struct = (
// dataWordCount = 0,
// pointerCount = 0,
// preferredListEncoding = empty));
//
// const enum :Node = (
// id = 0x0000000000000002,
// displayName = "(null enum schema)",
// enum = ());
//
// const interface :Node = (
// id = 0x0000000000000003,
// displayName = "(null interface schema)",
// interface = ());
//
// const const :Node = (
// id = 0x0000000000000004,
// displayName = "(null const schema)",
// const = (type = (void = void), value = (void = void)));
static const AlignedData<13> NULL_SCHEMA_BYTES = {{
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, // union discriminant intentionally mangled
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x73, 0x63,
0x68, 0x65, 0x6d, 0x61, 0x29, 0x00, 0x00, 0x00,
}};
const RawSchema NULL_SCHEMA = {
0x0000000000000000, NULL_SCHEMA_BYTES.words, 13,
nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr
};
static const AlignedData<14> NULL_STRUCT_SCHEMA_BYTES = {{
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x73, 0x74,
0x72, 0x75, 0x63, 0x74, 0x20, 0x73, 0x63, 0x68,
0x65, 0x6d, 0x61, 0x29, 0x00, 0x00, 0x00, 0x00,
}};
const RawSchema NULL_STRUCT_SCHEMA = {
0x0000000000000001, NULL_STRUCT_SCHEMA_BYTES.words, 14,
nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr
};
static const AlignedData<14> NULL_ENUM_SCHEMA_BYTES = {{
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x65, 0x6e,
0x75, 0x6d, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d,
0x61, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}};
const RawSchema NULL_ENUM_SCHEMA = {
0x0000000000000002, NULL_ENUM_SCHEMA_BYTES.words, 14,
nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr
};
static const AlignedData<14> NULL_INTERFACE_SCHEMA_BYTES = {{
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x20,
0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x29, 0x00,
}};
const RawSchema NULL_INTERFACE_SCHEMA = {
0x0000000000000003, NULL_INTERFACE_SCHEMA_BYTES.words, 14,
nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr
};
static const AlignedData<20> NULL_CONST_SCHEMA_BYTES = {{
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00,
0x28, 0x6e, 0x75, 0x6c, 0x6c, 0x20, 0x63, 0x6f,
0x6e, 0x73, 0x74, 0x20, 0x73, 0x63, 0x68, 0x65,
0x6d, 0x61, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}};
const RawSchema NULL_CONST_SCHEMA = {
0x0000000000000004, NULL_CONST_SCHEMA_BYTES.words, 20,
nullptr, nullptr, 0, 0, nullptr, nullptr, nullptr
};
} // namespace _ (private)
// =======================================================================================
schema::Node::Reader Schema::getProto() const {
return readMessageUnchecked<schema::Node>(raw->encodedNode);
}
......@@ -61,25 +216,33 @@ Schema Schema::getDependency(uint64_t id) const {
StructSchema Schema::asStruct() const {
KJ_REQUIRE(getProto().isStruct(), "Tried to use non-struct schema as a struct.",
getProto().getDisplayName());
getProto().getDisplayName()) {
return StructSchema();
}
return StructSchema(raw);
}
EnumSchema Schema::asEnum() const {
KJ_REQUIRE(getProto().isEnum(), "Tried to use non-enum schema as an enum.",
getProto().getDisplayName());
getProto().getDisplayName()) {
return EnumSchema();
}
return EnumSchema(raw);
}
InterfaceSchema Schema::asInterface() const {
KJ_REQUIRE(getProto().isInterface(), "Tried to use non-interface schema as an interface.",
getProto().getDisplayName());
getProto().getDisplayName()) {
return InterfaceSchema();
}
return InterfaceSchema(raw);
}
ConstSchema Schema::asConst() const {
KJ_REQUIRE(getProto().isConst(), "Tried to use non-constant schema as a constant.",
getProto().getDisplayName());
getProto().getDisplayName()) {
return ConstSchema();
}
return ConstSchema(raw);
}
......
......@@ -47,11 +47,21 @@ 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.
namespace _ { // private
extern const RawSchema NULL_SCHEMA;
extern const RawSchema NULL_STRUCT_SCHEMA;
extern const RawSchema NULL_ENUM_SCHEMA;
extern const RawSchema NULL_INTERFACE_SCHEMA;
extern const RawSchema NULL_CONST_SCHEMA;
// The schema types default to these null (empty) schemas in case of error, especially when
// exceptions are disabled.
} // namespace _ (private)
class Schema {
// Convenience wrapper around capnp::schema::Node.
public:
inline Schema(): raw(nullptr) {}
inline Schema(): raw(&_::NULL_SCHEMA) {}
template <typename T>
static inline SchemaType<T> from() { return SchemaType<T>::template fromImpl<T>(); }
......@@ -136,7 +146,7 @@ private:
class StructSchema: public Schema {
public:
StructSchema() = default;
inline StructSchema(): Schema(&_::NULL_STRUCT_SCHEMA) {}
class Field;
class FieldList;
......@@ -275,7 +285,7 @@ private:
class EnumSchema: public Schema {
public:
EnumSchema() = default;
inline EnumSchema(): Schema(&_::NULL_ENUM_SCHEMA) {}
class Enumerant;
class EnumerantList;
......@@ -344,7 +354,7 @@ private:
class InterfaceSchema: public Schema {
public:
InterfaceSchema() = default;
inline InterfaceSchema(): Schema(&_::NULL_INTERFACE_SCHEMA) {}
class Method;
class MethodList;
......@@ -431,7 +441,7 @@ class ConstSchema: public Schema {
// `ConstSchema` can be implicitly cast to DynamicValue to read its value.
public:
ConstSchema() = default;
inline ConstSchema(): Schema(&_::NULL_CONST_SCHEMA) {}
template <typename T>
ReaderFor<T> as() const;
......
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