Przeglądaj źródła

meta: add meta_type::can_convert (close #1028)

skypjack 2 lat temu
rodzic
commit
73dd3dcc26
3 zmienionych plików z 46 dodań i 0 usunięć
  1. 8 0
      src/entt/meta/meta.hpp
  2. 20 0
      src/entt/meta/node.hpp
  3. 18 0
      test/entt/meta/meta_type.cpp

+ 8 - 0
src/entt/meta/meta.hpp

@@ -1333,6 +1333,14 @@ public:
         return internal::try_cast(internal::meta_context::from(*ctx), node, other.node, this);
     }
 
+    /**
+     * @brief Checks if a type supports conversion it to another type.
+     * @return True if the conversion is allowed, false otherwise.
+     */
+    [[nodiscard]] bool can_convert(const meta_type &other) const noexcept {
+        return internal::can_convert(internal::meta_context::from(*ctx), node, other.node);
+    }
+
     /**
      * @brief Returns a range to visit registered top-level base meta types.
      * @return An iterable range to visit registered top-level base meta types.

+ 20 - 0
src/entt/meta/node.hpp

@@ -159,6 +159,26 @@ template<typename... Args>
     return nullptr;
 }
 
+[[nodiscard]] inline bool can_convert(const meta_context &context, const meta_type_node &from, const meta_type_node &to) noexcept {
+    if((from.info && *from.info == *to.info) || (from.conversion_helper && static_cast<bool>(to.traits & (meta_traits::is_arithmetic | meta_traits::is_enum)))) {
+        return true;
+    }
+
+    if(from.details) {
+        if(auto it = from.details->conv.find(to.info->hash()); it != from.details->conv.cend()) {
+            return true;
+        }
+
+        for(auto &&curr: from.details->base) {
+            if(can_convert(context, curr.second.type(context), to)) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
 [[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept {
     const auto it = context.value.find(info.hash());
     return it != context.value.end() ? &it->second : nullptr;

+ 18 - 0
test/entt/meta/meta_type.cpp

@@ -311,6 +311,24 @@ TEST_F(MetaType, CanCast) {
     ASSERT_TRUE(type.can_cast(entt::resolve<derived_t>()));
 }
 
+TEST_F(MetaType, CanConvert) {
+    auto clazz = entt::resolve<clazz_t>();
+    auto derived = entt::resolve<derived_t>();
+    auto arithmetic = entt::resolve<int>();
+
+    ASSERT_TRUE(clazz.can_convert(entt::resolve<clazz_t>()));
+    ASSERT_TRUE(clazz.can_convert(entt::resolve<int>()));
+
+    ASSERT_TRUE(derived.can_convert(entt::resolve<derived_t>()));
+    ASSERT_TRUE(derived.can_convert(entt::resolve<base_t>()));
+    ASSERT_FALSE(derived.can_convert(entt::resolve<int>()));
+
+    ASSERT_TRUE(arithmetic.can_convert(entt::resolve<int>()));
+    ASSERT_FALSE(arithmetic.can_convert(entt::resolve<clazz_t>()));
+    ASSERT_TRUE(arithmetic.can_convert(entt::resolve<double>()));
+    ASSERT_TRUE(arithmetic.can_convert(entt::resolve<float>()));
+}
+
 TEST_F(MetaType, Base) {
     auto type = entt::resolve<derived_t>();