Преглед на файлове

meta: internal and external indexing to disambiguate property overloads

Michele Caini преди 6 години
родител
ревизия
717b091b49
променени са 3 файла, в които са добавени 158 реда и са изтрити 172 реда
  1. 6 8
      docs/md/meta.md
  2. 43 27
      src/entt/meta/factory.hpp
  3. 109 137
      test/entt/meta/meta.cpp

+ 6 - 8
docs/md/meta.md

@@ -475,8 +475,8 @@ class.
 ## Properties and meta objects
 ## Properties and meta objects
 
 
 Sometimes (for example, when it comes to creating an editor) it might be useful
 Sometimes (for example, when it comes to creating an editor) it might be useful
-to be able to attach properties to the meta objects created. Fortunately, this
-is possible for most of them.<br/>
+to attach properties to the meta objects created. Fortunately, this is possible
+for most of them.<br/>
 For the meta objects that support properties, the member functions of the
 For the meta objects that support properties, the member functions of the
 factory used for registering them will return a decorated version of the factory
 factory used for registering them will return a decorated version of the factory
 itself. The latter can be used to attach properties to the last created meta
 itself. The latter can be used to attach properties to the last created meta
@@ -489,7 +489,7 @@ entt::meta<my_type>().type("reflected_type"_hs).prop("tooltip"_hs, "message");
 
 
 Properties are always in the key/value form. There are no restrictions on the
 Properties are always in the key/value form. There are no restrictions on the
 type of the key or value, as long as they are copy constructible objects.<br/>
 type of the key or value, as long as they are copy constructible objects.<br/>
-Furthermore, the `prop` function supports different formats for properties:
+Multiple formats are supported when it comes to defining a property:
 
 
 * Properties as key/value pairs:
 * Properties as key/value pairs:
 
 
@@ -516,8 +516,7 @@ Furthermore, the `prop` function supports different formats for properties:
           .prop(std::make_tuple(std::make_pair("tooltip"_hs, "message"), my_enum::key_only));
           .prop(std::make_tuple(std::make_pair("tooltip"_hs, "message"), my_enum::key_only));
   ```
   ```
 
 
-  A tuple can contain one or more properties defined as described above, except
-  for the key/value form. The properties will be treated individually.
+  A tuple contains one or more properties. All of them are treated individually.
 
 
 * Annotations:
 * Annotations:
 
 
@@ -525,9 +524,8 @@ Furthermore, the `prop` function supports different formats for properties:
   entt::meta<my_type>().type("reflected_type"_hs).prop(&property_generator);
   entt::meta<my_type>().type("reflected_type"_hs).prop(&property_generator);
   ```
   ```
 
 
-  An annotation is an invocable object that returns one or more properties
-  defined as described above, except for the key/value form. The properties will
-  be treated individually.
+  An annotation is an invocable object that returns one or more properties. All
+  of them are treated individually.
 
 
 It's possible to invoke the `prop` function several times if needed, one for
 It's possible to invoke the `prop` function several times if needed, one for
 each property to associate with the last meta object created:
 each property to associate with the last meta object created:

+ 43 - 27
src/entt/meta/factory.hpp

@@ -686,39 +686,47 @@ public:
 /**
 /**
  * @brief Extended meta factory to be used for reflection purposes.
  * @brief Extended meta factory to be used for reflection purposes.
  * @tparam Type Reflected type for which the factory was created.
  * @tparam Type Reflected type for which the factory was created.
+ * @tparam Spec Property specialization pack used to disambiguate overloads.
  */
  */
-template<typename Type, typename...>
+template<typename Type, typename... Spec>
 class extended_meta_factory: public meta_factory<Type> {
 class extended_meta_factory: public meta_factory<Type> {
-    /*! @brief A meta factory is allowed to _extend_ itself. */
-    friend class meta_factory<Type>;
-
     bool duplicate(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT {
     bool duplicate(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT {
         return node && (node->key() == key || duplicate(key, node->next));
         return node && (node->key() == key || duplicate(key, node->next));
     }
     }
 
 
-    template<typename... Property, std::size_t... Index>
-    void unpack(std::tuple<Property...> property, std::index_sequence<Index...>) {
-        (unpack(choice<3>, std::get<Index>(property)), ...);
+    template<std::size_t Step = 0, std::size_t... Index, typename... Property, typename... Other>
+    void unpack(std::index_sequence<Index...>, std::tuple<Property...> property, Other &&... other) {
+        unroll<Step>(choice<3>, std::move(std::get<Index>(property))..., std::forward<Other>(other)...);
+    }
+
+    template<std::size_t Step = 0, typename... Property, typename... Other>
+    void unroll(choice_t<3>, std::tuple<Property...> property, Other &&... other) {
+        unpack<Step>(std::index_sequence_for<Property...>{}, std::move(property), std::forward<Other>(other)...);
     }
     }
 
 
-    template<typename... Property>
-    void unpack(choice_t<3>, std::tuple<Property...> property) {
-        unpack(std::move(property), std::index_sequence_for<Property...>{});
+    template<std::size_t Step = 0, typename... Property, typename... Other>
+    void unroll(choice_t<2>, std::pair<Property...> property, Other &&... other) {
+        assign<Step>(std::move(property.first), std::move(property.second));
+        unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
     }
     }
 
 
-    template<typename... KeyOrValue>
-    void unpack(choice_t<2>, std::pair<KeyOrValue...> property) {
-        unpack(choice<0>, std::move(property.first), std::move(property.second));
+    template<std::size_t Step = 0, typename Property, typename... Other>
+    std::enable_if_t<!std::is_invocable_v<Property>>
+    unroll(choice_t<1>, Property &&property, Other &&... other) {
+        assign<Step>(std::forward<Property>(property));
+        unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
     }
     }
 
 
-    template<typename Func>
-    std::enable_if_t<std::is_invocable_v<Func>, void>
-    unpack(choice_t<1>, Func &&func) {
-        unpack(choice<3>, std::forward<Func>(func)());
+    template<std::size_t Step = 0, typename Func, typename... Other>
+    void unroll(choice_t<0>, Func &&func, Other &&... other) {
+        unroll<Step>(choice<3>, std::forward<Func>(func)(), std::forward<Other>(other)...);
     }
     }
 
 
-    template<typename Key, typename... Value>
-    void unpack(choice_t<0>, Key &&key, Value &&... value) {
+    template<std::size_t>
+    void unroll(choice_t<0>) {}
+
+    template<std::size_t = 0, typename Key, typename... Value>
+    void assign(Key &&key, Value &&... value) {
         static auto property{std::make_tuple(std::forward<Key>(key), std::forward<Value>(value)...)};
         static auto property{std::make_tuple(std::forward<Key>(key), std::forward<Value>(value)...)};
 
 
         static internal::meta_prop_node node{
         static internal::meta_prop_node node{
@@ -739,11 +747,15 @@ class extended_meta_factory: public meta_factory<Type> {
         *curr = &node;
         *curr = &node;
     }
     }
 
 
+public:
+    /**
+     * @brief Constructs an extended factory from a given node.
+     * @param target The underlying node to which to assign the properties.
+     */
     extended_meta_factory(entt::internal::meta_prop_node **target)
     extended_meta_factory(entt::internal::meta_prop_node **target)
         : curr{target}
         : curr{target}
     {}
     {}
 
 
-public:
     /**
     /**
      * @brief Assigns a property to the last meta object created.
      * @brief Assigns a property to the last meta object created.
      *
      *
@@ -756,10 +768,14 @@ public:
      * @return A meta factory for the parent type.
      * @return A meta factory for the parent type.
      */
      */
     template<typename PropertyOrKey, typename... Value>
     template<typename PropertyOrKey, typename... Value>
-    auto prop(PropertyOrKey &&property_or_key, Value &&... value) {
-        static_assert(sizeof...(Value) <= 1);
-        unpack(choice<3>, std::forward<PropertyOrKey>(property_or_key), std::forward<Value>(value)...);
-        return *this;
+    auto prop(PropertyOrKey &&property_or_key, Value &&... value) && {
+        if constexpr(sizeof...(Value) == 0) {
+            unroll(choice<3>, std::forward<PropertyOrKey>(property_or_key));
+        } else {
+            assign(std::forward<PropertyOrKey>(property_or_key), std::forward<Value>(value)...);
+        }
+
+        return extended_meta_factory<Type, Spec..., PropertyOrKey, Value...>{curr};
     }
     }
 
 
     /**
     /**
@@ -773,9 +789,9 @@ public:
      * @return A meta factory for the parent type.
      * @return A meta factory for the parent type.
      */
      */
     template <typename... Property>
     template <typename... Property>
-    auto props(Property... property) {
-        (prop(property), ...);
-        return *this;
+    auto props(Property... property) && {
+        unroll(choice<3>, std::forward<Property>(property)...);
+        return extended_meta_factory<Type, Spec..., Property...>{curr};
     }
     }
 
 
 private:
 private:

+ 109 - 137
test/entt/meta/meta.cpp

@@ -17,8 +17,9 @@ Type get(Type &prop) {
     return prop;
     return prop;
 }
 }
 
 
-enum class properties {
+enum class props {
     prop_int,
     prop_int,
+    prop_value,
     prop_bool,
     prop_bool,
     key_only,
     key_only,
     prop_list
     prop_list
@@ -149,20 +150,21 @@ struct Meta: ::testing::Test {
 
 
         entt::meta<char>()
         entt::meta<char>()
                 .type("char"_hs)
                 .type("char"_hs)
-                    .prop(properties::prop_int, 42)
+                    .prop(props::prop_int, 42)
                 .data<&set<char>, &get<char>>("value"_hs);
                 .data<&set<char>, &get<char>>("value"_hs);
 
 
-        entt::meta<properties>()
-                .data<properties::prop_bool>("prop_bool"_hs)
-                    .prop(properties::prop_int, 0)
-                .data<properties::prop_int>("prop_int"_hs)
-                    .prop(std::make_tuple(std::make_pair(properties::prop_bool, true), std::make_pair(properties::prop_int, 0)))
-                    .prop(properties::key_only)
-                .data<properties::key_only>("key_only"_hs)
-                    .prop([]() { return properties::key_only; })
-                .data<&set<properties>, &get<properties>>("value"_hs)
-                .data<properties::prop_list>("prop_list"_hs)
-                    .props(std::make_pair(properties::prop_bool, true), std::make_pair(properties::prop_int, 0), properties::key_only);
+        entt::meta<props>()
+                .data<props::prop_bool>("prop_bool"_hs)
+                    .prop(props::prop_int, 0)
+                    .prop(props::prop_value, 3)
+                .data<props::prop_int>("prop_int"_hs)
+                    .prop(std::make_tuple(std::make_pair(props::prop_bool, true), std::make_pair(props::prop_int, 0), std::make_pair(props::prop_value, 3)))
+                    .prop(props::key_only)
+                .data<props::key_only>("key_only"_hs)
+                    .prop([]() { return props::key_only; })
+                .data<&set<props>, &get<props>>("value"_hs)
+                .data<props::prop_list>("prop_list"_hs)
+                    .props(std::make_pair(props::prop_bool, false), std::make_pair(props::prop_int, 0), std::make_pair(props::prop_value, 3), props::key_only);
 
 
         entt::meta<unsigned int>().data<0u>("min"_hs).data<100u>("max"_hs);
         entt::meta<unsigned int>().data<0u>("min"_hs).data<100u>("max"_hs);
 
 
@@ -171,12 +173,12 @@ struct Meta: ::testing::Test {
 
 
         entt::meta<derived_type>()
         entt::meta<derived_type>()
                 .type("derived"_hs)
                 .type("derived"_hs)
-                    .prop(properties::prop_int, 99)
+                    .prop(props::prop_int, 99)
                 .base<base_type>()
                 .base<base_type>()
                 .ctor<const base_type &, int, char>()
                 .ctor<const base_type &, int, char>()
-                    .prop(properties::prop_bool, false)
+                    .prop(props::prop_bool, false)
                 .ctor<&derived_factory>()
                 .ctor<&derived_factory>()
-                    .prop(properties::prop_int, 42)
+                    .prop(props::prop_int, 42)
                 .conv<&derived_type::f>()
                 .conv<&derived_type::f>()
                 .conv<&derived_type::g>();
                 .conv<&derived_type::g>();
 
 
@@ -192,13 +194,13 @@ struct Meta: ::testing::Test {
         entt::meta<data_type>()
         entt::meta<data_type>()
                 .type("data"_hs)
                 .type("data"_hs)
                 .data<&data_type::i, entt::as_alias_t>("i"_hs)
                 .data<&data_type::i, entt::as_alias_t>("i"_hs)
-                    .prop(properties::prop_int, 0)
+                    .prop(props::prop_int, 0)
                 .data<&data_type::j>("j"_hs)
                 .data<&data_type::j>("j"_hs)
-                    .prop(properties::prop_int, 1)
+                    .prop(props::prop_int, 1)
                 .data<&data_type::h>("h"_hs)
                 .data<&data_type::h>("h"_hs)
-                    .prop(properties::prop_int, 2)
+                    .prop(props::prop_int, 2)
                 .data<&data_type::k>("k"_hs)
                 .data<&data_type::k>("k"_hs)
-                    .prop(properties::prop_int, 3)
+                    .prop(props::prop_int, 3)
                 .data<&data_type::empty>("empty"_hs)
                 .data<&data_type::empty>("empty"_hs)
                 .data<&data_type::v, entt::as_void_t>("v"_hs);
                 .data<&data_type::v, entt::as_void_t>("v"_hs);
 
 
@@ -211,15 +213,15 @@ struct Meta: ::testing::Test {
                 .type("func"_hs)
                 .type("func"_hs)
                 .func<entt::overload<int(const base_type &, int, int)>(&func_type::f)>("f3"_hs)
                 .func<entt::overload<int(const base_type &, int, int)>(&func_type::f)>("f3"_hs)
                 .func<entt::overload<int(int, int)>(&func_type::f)>("f2"_hs)
                 .func<entt::overload<int(int, int)>(&func_type::f)>("f2"_hs)
-                    .prop(properties::prop_bool, false)
+                    .prop(props::prop_bool, false)
                 .func<entt::overload<int(int) const>(&func_type::f)>("f1"_hs)
                 .func<entt::overload<int(int) const>(&func_type::f)>("f1"_hs)
-                    .prop(properties::prop_bool, false)
+                    .prop(props::prop_bool, false)
                 .func<&func_type::g>("g"_hs)
                 .func<&func_type::g>("g"_hs)
-                    .prop(properties::prop_bool, false)
+                    .prop(props::prop_bool, false)
                 .func<&func_type::h>("h"_hs)
                 .func<&func_type::h>("h"_hs)
-                    .prop(properties::prop_bool, false)
+                    .prop(props::prop_bool, false)
                 .func<&func_type::k>("k"_hs)
                 .func<&func_type::k>("k"_hs)
-                    .prop(properties::prop_bool, false)
+                    .prop(props::prop_bool, false)
                 .func<&func_type::v, entt::as_void_t>("v"_hs)
                 .func<&func_type::v, entt::as_void_t>("v"_hs)
                 .func<&func_type::a, entt::as_alias_t>("a"_hs);
                 .func<&func_type::a, entt::as_alias_t>("a"_hs);
 
 
@@ -232,14 +234,14 @@ struct Meta: ::testing::Test {
 
 
         entt::meta<an_abstract_type>()
         entt::meta<an_abstract_type>()
                 .type("an_abstract_type"_hs)
                 .type("an_abstract_type"_hs)
-                    .prop(properties::prop_bool, false)
+                    .prop(props::prop_bool, false)
                 .data<&an_abstract_type::i>("i"_hs)
                 .data<&an_abstract_type::i>("i"_hs)
                 .func<&an_abstract_type::f>("f"_hs)
                 .func<&an_abstract_type::f>("f"_hs)
                 .func<&an_abstract_type::g>("g"_hs);
                 .func<&an_abstract_type::g>("g"_hs);
 
 
         entt::meta<another_abstract_type>()
         entt::meta<another_abstract_type>()
                 .type("another_abstract_type"_hs)
                 .type("another_abstract_type"_hs)
-                    .prop(properties::prop_int, 42)
+                    .prop(props::prop_int, 42)
                 .data<&another_abstract_type::j>("j"_hs)
                 .data<&another_abstract_type::j>("j"_hs)
                 .func<&another_abstract_type::h>("h"_hs);
                 .func<&another_abstract_type::h>("h"_hs);
 
 
@@ -255,7 +257,7 @@ struct Meta: ::testing::Test {
 
 
         entt::meta<derived_type>()
         entt::meta<derived_type>()
                 .type("my_type"_hs)
                 .type("my_type"_hs)
-                    .prop(properties::prop_bool, false)
+                    .prop(props::prop_bool, false)
                 .ctor<>();
                 .ctor<>();
 
 
         entt::meta<another_abstract_type>()
         entt::meta<another_abstract_type>()
@@ -924,11 +926,11 @@ TEST_F(Meta, MetaHandleEmpty) {
 }
 }
 
 
 TEST_F(Meta, MetaProp) {
 TEST_F(Meta, MetaProp) {
-    auto prop = entt::resolve<char>().prop(properties::prop_int);
+    auto prop = entt::resolve<char>().prop(props::prop_int);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
     ASSERT_NE(prop, entt::meta_prop{});
     ASSERT_NE(prop, entt::meta_prop{});
-    ASSERT_EQ(prop.key(), properties::prop_int);
+    ASSERT_EQ(prop.key(), props::prop_int);
     ASSERT_EQ(prop.value(), 42);
     ASSERT_EQ(prop.value(), 42);
 }
 }
 
 
@@ -1014,16 +1016,16 @@ TEST_F(Meta, MetaCtor) {
 
 
     ctor.prop([](auto prop) {
     ctor.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_bool);
+        ASSERT_EQ(prop.key(), props::prop_bool);
         ASSERT_FALSE(prop.value().template cast<bool>());
         ASSERT_FALSE(prop.value().template cast<bool>());
     });
     });
 
 
-    ASSERT_FALSE(ctor.prop(properties::prop_int));
+    ASSERT_FALSE(ctor.prop(props::prop_int));
 
 
-    auto prop = ctor.prop(properties::prop_bool);
+    auto prop = ctor.prop(props::prop_bool);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_bool);
+    ASSERT_EQ(prop.key(), props::prop_bool);
     ASSERT_FALSE(prop.value().template cast<bool>());
     ASSERT_FALSE(prop.value().template cast<bool>());
 }
 }
 
 
@@ -1048,16 +1050,16 @@ TEST_F(Meta, MetaCtorFunc) {
 
 
     ctor.prop([](auto prop) {
     ctor.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_int);
+        ASSERT_EQ(prop.key(), props::prop_int);
         ASSERT_EQ(prop.value(), 42);
         ASSERT_EQ(prop.value(), 42);
     });
     });
 
 
-    ASSERT_FALSE(ctor.prop(properties::prop_bool));
+    ASSERT_FALSE(ctor.prop(props::prop_bool));
 
 
-    auto prop = ctor.prop(properties::prop_int);
+    auto prop = ctor.prop(props::prop_int);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_int);
+    ASSERT_EQ(prop.key(), props::prop_int);
     ASSERT_EQ(prop.value(), 42);
     ASSERT_EQ(prop.value(), 42);
 }
 }
 
 
@@ -1155,16 +1157,16 @@ TEST_F(Meta, MetaData) {
 
 
     data.prop([](auto prop) {
     data.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_int);
+        ASSERT_EQ(prop.key(), props::prop_int);
         ASSERT_EQ(prop.value(), 0);
         ASSERT_EQ(prop.value(), 0);
     });
     });
 
 
-    ASSERT_FALSE(data.prop(properties::prop_bool));
+    ASSERT_FALSE(data.prop(props::prop_bool));
 
 
-    auto prop = data.prop(properties::prop_int);
+    auto prop = data.prop(props::prop_int);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_int);
+    ASSERT_EQ(prop.key(), props::prop_int);
     ASSERT_EQ(prop.value(), 0);
     ASSERT_EQ(prop.value(), 0);
 }
 }
 
 
@@ -1184,16 +1186,16 @@ TEST_F(Meta, MetaDataConst) {
 
 
     data.prop([](auto prop) {
     data.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_int);
+        ASSERT_EQ(prop.key(), props::prop_int);
         ASSERT_EQ(prop.value(), 1);
         ASSERT_EQ(prop.value(), 1);
     });
     });
 
 
-    ASSERT_FALSE(data.prop(properties::prop_bool));
+    ASSERT_FALSE(data.prop(props::prop_bool));
 
 
-    auto prop = data.prop(properties::prop_int);
+    auto prop = data.prop(props::prop_int);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_int);
+    ASSERT_EQ(prop.key(), props::prop_int);
     ASSERT_EQ(prop.value(), 1);
     ASSERT_EQ(prop.value(), 1);
 }
 }
 
 
@@ -1212,16 +1214,16 @@ TEST_F(Meta, MetaDataStatic) {
 
 
     data.prop([](auto prop) {
     data.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_int);
+        ASSERT_EQ(prop.key(), props::prop_int);
         ASSERT_EQ(prop.value(), 2);
         ASSERT_EQ(prop.value(), 2);
     });
     });
 
 
-    ASSERT_FALSE(data.prop(properties::prop_bool));
+    ASSERT_FALSE(data.prop(props::prop_bool));
 
 
-    auto prop = data.prop(properties::prop_int);
+    auto prop = data.prop(props::prop_int);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_int);
+    ASSERT_EQ(prop.key(), props::prop_int);
     ASSERT_EQ(prop.value(), 2);
     ASSERT_EQ(prop.value(), 2);
 }
 }
 
 
@@ -1240,16 +1242,16 @@ TEST_F(Meta, MetaDataConstStatic) {
 
 
     data.prop([](auto prop) {
     data.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_int);
+        ASSERT_EQ(prop.key(), props::prop_int);
         ASSERT_EQ(prop.value(), 3);
         ASSERT_EQ(prop.value(), 3);
     });
     });
 
 
-    ASSERT_FALSE(data.prop(properties::prop_bool));
+    ASSERT_FALSE(data.prop(props::prop_bool));
 
 
-    auto prop = data.prop(properties::prop_int);
+    auto prop = data.prop(props::prop_int);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_int);
+    ASSERT_EQ(prop.key(), props::prop_int);
     ASSERT_EQ(prop.value(), 3);
     ASSERT_EQ(prop.value(), 3);
 }
 }
 
 
@@ -1474,16 +1476,16 @@ TEST_F(Meta, MetaFunc) {
 
 
     func.prop([](auto prop) {
     func.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_bool);
+        ASSERT_EQ(prop.key(), props::prop_bool);
         ASSERT_FALSE(prop.value().template cast<bool>());
         ASSERT_FALSE(prop.value().template cast<bool>());
     });
     });
 
 
-    ASSERT_FALSE(func.prop(properties::prop_int));
+    ASSERT_FALSE(func.prop(props::prop_int));
 
 
-    auto prop = func.prop(properties::prop_bool);
+    auto prop = func.prop(props::prop_bool);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_bool);
+    ASSERT_EQ(prop.key(), props::prop_bool);
     ASSERT_FALSE(prop.value().cast<bool>());
     ASSERT_FALSE(prop.value().cast<bool>());
 }
 }
 
 
@@ -1511,16 +1513,16 @@ TEST_F(Meta, MetaFuncConst) {
 
 
     func.prop([](auto prop) {
     func.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_bool);
+        ASSERT_EQ(prop.key(), props::prop_bool);
         ASSERT_FALSE(prop.value().template cast<bool>());
         ASSERT_FALSE(prop.value().template cast<bool>());
     });
     });
 
 
-    ASSERT_FALSE(func.prop(properties::prop_int));
+    ASSERT_FALSE(func.prop(props::prop_int));
 
 
-    auto prop = func.prop(properties::prop_bool);
+    auto prop = func.prop(props::prop_bool);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_bool);
+    ASSERT_EQ(prop.key(), props::prop_bool);
     ASSERT_FALSE(prop.value().cast<bool>());
     ASSERT_FALSE(prop.value().cast<bool>());
 }
 }
 
 
@@ -1546,16 +1548,16 @@ TEST_F(Meta, MetaFuncRetVoid) {
 
 
     func.prop([](auto prop) {
     func.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_bool);
+        ASSERT_EQ(prop.key(), props::prop_bool);
         ASSERT_FALSE(prop.value().template cast<bool>());
         ASSERT_FALSE(prop.value().template cast<bool>());
     });
     });
 
 
-    ASSERT_FALSE(func.prop(properties::prop_int));
+    ASSERT_FALSE(func.prop(props::prop_int));
 
 
-    auto prop = func.prop(properties::prop_bool);
+    auto prop = func.prop(props::prop_bool);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_bool);
+    ASSERT_EQ(prop.key(), props::prop_bool);
     ASSERT_FALSE(prop.value().cast<bool>());
     ASSERT_FALSE(prop.value().cast<bool>());
 }
 }
 
 
@@ -1583,16 +1585,16 @@ TEST_F(Meta, MetaFuncStatic) {
 
 
     func.prop([](auto prop) {
     func.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_bool);
+        ASSERT_EQ(prop.key(), props::prop_bool);
         ASSERT_FALSE(prop.value().template cast<bool>());
         ASSERT_FALSE(prop.value().template cast<bool>());
     });
     });
 
 
-    ASSERT_FALSE(func.prop(properties::prop_int));
+    ASSERT_FALSE(func.prop(props::prop_int));
 
 
-    auto prop = func.prop(properties::prop_bool);
+    auto prop = func.prop(props::prop_bool);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_bool);
+    ASSERT_EQ(prop.key(), props::prop_bool);
     ASSERT_FALSE(prop.value().cast<bool>());
     ASSERT_FALSE(prop.value().cast<bool>());
 }
 }
 
 
@@ -1617,16 +1619,16 @@ TEST_F(Meta, MetaFuncStaticRetVoid) {
 
 
     func.prop([](auto *prop) {
     func.prop([](auto *prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop->key(), properties::prop_bool);
+        ASSERT_EQ(prop->key(), props::prop_bool);
         ASSERT_FALSE(prop->value().template cast<bool>());
         ASSERT_FALSE(prop->value().template cast<bool>());
     });
     });
 
 
-    ASSERT_FALSE(func.prop(properties::prop_int));
+    ASSERT_FALSE(func.prop(props::prop_int));
 
 
-    auto prop = func.prop(properties::prop_bool);
+    auto prop = func.prop(props::prop_bool);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_bool);
+    ASSERT_EQ(prop.key(), props::prop_bool);
     ASSERT_FALSE(prop.value().cast<bool>());
     ASSERT_FALSE(prop.value().cast<bool>());
 }
 }
 
 
@@ -1698,16 +1700,16 @@ TEST_F(Meta, MetaType) {
 
 
     type.prop([](auto prop) {
     type.prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_int);
+        ASSERT_EQ(prop.key(), props::prop_int);
         ASSERT_EQ(prop.value(), 99);
         ASSERT_EQ(prop.value(), 99);
     });
     });
 
 
-    ASSERT_FALSE(type.prop(properties::prop_bool));
+    ASSERT_FALSE(type.prop(props::prop_bool));
 
 
-    auto prop = type.prop(properties::prop_int);
+    auto prop = type.prop(props::prop_int);
 
 
     ASSERT_TRUE(prop);
     ASSERT_TRUE(prop);
-    ASSERT_EQ(prop.key(), properties::prop_int);
+    ASSERT_EQ(prop.key(), props::prop_int);
     ASSERT_EQ(prop.value(), 99);
     ASSERT_EQ(prop.value(), 99);
 }
 }
 
 
@@ -1715,7 +1717,7 @@ TEST_F(Meta, MetaTypeTraits) {
     ASSERT_TRUE(entt::resolve<void>().is_void());
     ASSERT_TRUE(entt::resolve<void>().is_void());
     ASSERT_TRUE(entt::resolve<bool>().is_integral());
     ASSERT_TRUE(entt::resolve<bool>().is_integral());
     ASSERT_TRUE(entt::resolve<double>().is_floating_point());
     ASSERT_TRUE(entt::resolve<double>().is_floating_point());
-    ASSERT_TRUE(entt::resolve<properties>().is_enum());
+    ASSERT_TRUE(entt::resolve<props>().is_enum());
     ASSERT_TRUE(entt::resolve<union_type>().is_union());
     ASSERT_TRUE(entt::resolve<union_type>().is_union());
     ASSERT_TRUE(entt::resolve<derived_type>().is_class());
     ASSERT_TRUE(entt::resolve<derived_type>().is_class());
     ASSERT_TRUE(entt::resolve<int *>().is_pointer());
     ASSERT_TRUE(entt::resolve<int *>().is_pointer());
@@ -1934,8 +1936,8 @@ TEST_F(Meta, MetaFuncFromBase) {
 
 
 TEST_F(Meta, MetaPropFromBase) {
 TEST_F(Meta, MetaPropFromBase) {
     auto type = entt::resolve<concrete_type>();
     auto type = entt::resolve<concrete_type>();
-    auto prop_bool = type.prop(properties::prop_bool);
-    auto prop_int = type.prop(properties::prop_int);
+    auto prop_bool = type.prop(props::prop_bool);
+    auto prop_int = type.prop(props::prop_int);
 
 
     ASSERT_TRUE(prop_bool);
     ASSERT_TRUE(prop_bool);
     ASSERT_TRUE(prop_int);
     ASSERT_TRUE(prop_int);
@@ -1960,7 +1962,7 @@ TEST_F(Meta, AbstractClass) {
 }
 }
 
 
 TEST_F(Meta, EnumAndNamedConstants) {
 TEST_F(Meta, EnumAndNamedConstants) {
-    auto type = entt::resolve<properties>();
+    auto type = entt::resolve<props>();
 
 
     ASSERT_TRUE(type.data("prop_bool"_hs));
     ASSERT_TRUE(type.data("prop_bool"_hs));
     ASSERT_TRUE(type.data("prop_int"_hs));
     ASSERT_TRUE(type.data("prop_int"_hs));
@@ -1968,11 +1970,11 @@ TEST_F(Meta, EnumAndNamedConstants) {
     ASSERT_EQ(type.data("prop_bool"_hs).type(), type);
     ASSERT_EQ(type.data("prop_bool"_hs).type(), type);
     ASSERT_EQ(type.data("prop_int"_hs).type(), type);
     ASSERT_EQ(type.data("prop_int"_hs).type(), type);
 
 
-    ASSERT_FALSE(type.data("prop_bool"_hs).set({}, properties::prop_int));
-    ASSERT_FALSE(type.data("prop_int"_hs).set({}, properties::prop_bool));
+    ASSERT_FALSE(type.data("prop_bool"_hs).set({}, props::prop_int));
+    ASSERT_FALSE(type.data("prop_int"_hs).set({}, props::prop_bool));
 
 
-    ASSERT_EQ(type.data("prop_bool"_hs).get({}).cast<properties>(), properties::prop_bool);
-    ASSERT_EQ(type.data("prop_int"_hs).get({}).cast<properties>(), properties::prop_int);
+    ASSERT_EQ(type.data("prop_bool"_hs).get({}).cast<props>(), props::prop_bool);
+    ASSERT_EQ(type.data("prop_int"_hs).get({}).cast<props>(), props::prop_int);
 }
 }
 
 
 TEST_F(Meta, ArithmeticTypeAndNamedConstants) {
 TEST_F(Meta, ArithmeticTypeAndNamedConstants) {
@@ -1992,68 +1994,38 @@ TEST_F(Meta, ArithmeticTypeAndNamedConstants) {
 }
 }
 
 
 TEST_F(Meta, Variables) {
 TEST_F(Meta, Variables) {
-    auto p_data = entt::resolve<properties>().data("value"_hs);
+    auto p_data = entt::resolve<props>().data("value"_hs);
     auto c_data = entt::resolve("char"_hs).data("value"_hs);
     auto c_data = entt::resolve("char"_hs).data("value"_hs);
 
 
-    properties prop{properties::prop_int};
+    props prop{props::prop_int};
     char c = 'c';
     char c = 'c';
 
 
-    p_data.set(prop, properties::prop_bool);
+    p_data.set(prop, props::prop_bool);
     c_data.set(c, 'x');
     c_data.set(c, 'x');
 
 
-    ASSERT_EQ(p_data.get(prop).cast<properties>(), properties::prop_bool);
+    ASSERT_EQ(p_data.get(prop).cast<props>(), props::prop_bool);
     ASSERT_EQ(c_data.get(c).cast<char>(), 'x');
     ASSERT_EQ(c_data.get(c).cast<char>(), 'x');
-    ASSERT_EQ(prop, properties::prop_bool);
+    ASSERT_EQ(prop, props::prop_bool);
     ASSERT_EQ(c, 'x');
     ASSERT_EQ(c, 'x');
 }
 }
 
 
-TEST_F(Meta, SharedProperties) {
-    const auto type = entt::resolve<properties>();
-    const auto prop_bool = type.data("prop_bool"_hs);
-    const auto prop_int = type.data("prop_int"_hs);
+TEST_F(Meta, PropertiesAndCornerCases) {
+    auto type = entt::resolve<props>();
 
 
-    ASSERT_TRUE(prop_bool.prop(properties::prop_int));
-    ASSERT_FALSE(prop_bool.prop(properties::prop_bool));
+    ASSERT_EQ(type.data("prop_bool"_hs).prop(props::prop_int).value().cast<int>(), 0);
+    ASSERT_EQ(type.data("prop_bool"_hs).prop(props::prop_value).value().cast<int>(), 3);
 
 
-    ASSERT_TRUE(prop_int.prop(properties::prop_int));
-    ASSERT_TRUE(prop_int.prop(properties::prop_bool));
-}
-
-TEST_F(Meta, KeyOnlyProperties) {
-    const auto type = entt::resolve<properties>();
-    const auto prop = type.data("key_only"_hs).prop(properties::key_only);
-
-    ASSERT_TRUE(prop);
-    ASSERT_TRUE(prop.key());
-    ASSERT_EQ(prop.key().type(), entt::resolve<properties>());
-    ASSERT_EQ(prop.key().cast<properties>(), properties::key_only);
-    ASSERT_FALSE(prop.value());
-}
-
-TEST_F(Meta, PropertyList) {
-    const auto type = entt::resolve<properties>();
-    const auto prop_list = type.data("prop_list"_hs);
-    const auto prop_bool = prop_list.prop(properties::prop_bool);
-    const auto prop_int =  prop_list.prop(properties::prop_int);
-    const auto key_prop = prop_list.prop(properties::key_only);
-
-    ASSERT_TRUE(prop_bool);
-    ASSERT_EQ(prop_bool.key().type(), entt::resolve<properties>());
-    ASSERT_EQ(prop_bool.key().cast<properties>(), properties::prop_bool);
-    ASSERT_TRUE(prop_bool.value());
-    ASSERT_TRUE(prop_bool.value().try_cast<bool>());
-
-    ASSERT_TRUE(prop_int);
-    ASSERT_EQ(prop_int.key().type(), entt::resolve<properties>());
-    ASSERT_EQ(prop_int.key().cast<properties>(), properties::prop_int);
-    ASSERT_TRUE(prop_int.value());
-    ASSERT_TRUE(prop_int.value().try_cast<int>());
+    ASSERT_EQ(type.data("prop_int"_hs).prop(props::prop_bool).value().cast<bool>(), true);
+    ASSERT_EQ(type.data("prop_int"_hs).prop(props::prop_int).value().cast<int>(), 0);
+    ASSERT_EQ(type.data("prop_int"_hs).prop(props::prop_value).value().cast<int>(), 3);
+    ASSERT_TRUE(type.data("prop_int"_hs).prop(props::key_only));
+    ASSERT_FALSE(type.data("prop_int"_hs).prop(props::key_only).value());
 
 
-    ASSERT_TRUE(key_prop);
-    ASSERT_TRUE(key_prop.key());
-    ASSERT_EQ(key_prop.key().type(), entt::resolve<properties>());
-    ASSERT_EQ(key_prop.key().cast<properties>(), properties::key_only);
-    ASSERT_FALSE(key_prop.value());
+    ASSERT_EQ(type.data("prop_list"_hs).prop(props::prop_bool).value().cast<bool>(), false);
+    ASSERT_EQ(type.data("prop_list"_hs).prop(props::prop_int).value().cast<int>(), 0);
+    ASSERT_EQ(type.data("prop_list"_hs).prop(props::prop_value).value().cast<int>(), 3);
+    ASSERT_TRUE(type.data("prop_list"_hs).prop(props::key_only));
+    ASSERT_FALSE(type.data("prop_list"_hs).prop(props::key_only).value());
 }
 }
 
 
 TEST_F(Meta, Reset) {
 TEST_F(Meta, Reset) {
@@ -2068,7 +2040,7 @@ TEST_F(Meta, Reset) {
     entt::meta<func_type>().reset();
     entt::meta<func_type>().reset();
     entt::meta<array_type>().reset();
     entt::meta<array_type>().reset();
     entt::meta<double>().reset();
     entt::meta<double>().reset();
-    entt::meta<properties>().reset();
+    entt::meta<props>().reset();
     entt::meta<base_type>().reset();
     entt::meta<base_type>().reset();
     entt::meta<derived_type>().reset();
     entt::meta<derived_type>().reset();
     entt::meta<empty_type>().reset();
     entt::meta<empty_type>().reset();
@@ -2103,7 +2075,7 @@ TEST_F(Meta, Reset) {
 
 
     entt::resolve<derived_type>().prop([](auto prop) {
     entt::resolve<derived_type>().prop([](auto prop) {
         ASSERT_TRUE(prop);
         ASSERT_TRUE(prop);
-        ASSERT_EQ(prop.key(), properties::prop_bool);
+        ASSERT_EQ(prop.key(), props::prop_bool);
         ASSERT_FALSE(prop.value().template cast<bool>());
         ASSERT_FALSE(prop.value().template cast<bool>());
     });
     });