meta: make meta_any::allow_cast work with mutating this pointers
This commit is contained in:
+24
-10
@@ -1393,17 +1393,31 @@ bool meta_any::set(const id_type id, Type &&value) {
|
||||
}
|
||||
|
||||
[[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const {
|
||||
if(const auto &info = type.info(); (node && *node->info == info) || internal::find_by<&internal::meta_type_node::base>(info, node)) {
|
||||
if(const auto &info = type.info(); node && *node->info == info) {
|
||||
return as_ref();
|
||||
} else if(const auto *const conv = internal::find_by<&internal::meta_type_node::conv>(info, node); conv) {
|
||||
return conv->conv(*this);
|
||||
} else if(node && node->conversion_helper && (type.is_arithmetic() || type.is_enum())) {
|
||||
// exploits the fact that arithmetic types and enums are also default constructible
|
||||
auto other = type.construct();
|
||||
ENTT_ASSERT(other.node->conversion_helper, "Conversion helper not found");
|
||||
const auto value = node->conversion_helper(nullptr, storage.data());
|
||||
other.node->conversion_helper(other.storage.data(), &value);
|
||||
return other;
|
||||
} else if(node) {
|
||||
for(auto *it = node->conv; it; it = it->next) {
|
||||
if(*it->type->info == info) {
|
||||
return it->conv(*this);
|
||||
}
|
||||
}
|
||||
|
||||
if(node->conversion_helper && (type.is_arithmetic() || type.is_enum())) {
|
||||
// exploits the fact that arithmetic types and enums are also default constructible
|
||||
auto other = type.construct();
|
||||
ENTT_ASSERT(other.node->conversion_helper, "Conversion helper not found");
|
||||
const auto value = node->conversion_helper(nullptr, storage.data());
|
||||
other.node->conversion_helper(other.storage.data(), &value);
|
||||
return other;
|
||||
}
|
||||
|
||||
for(auto *it = node->base; it; it = it->next) {
|
||||
const auto as_const = it->cast(as_ref());
|
||||
|
||||
if(auto other = as_const.allow_cast(type); other) {
|
||||
return other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
@@ -11,6 +11,11 @@ struct base_1_t {
|
||||
|
||||
struct base_2_t {
|
||||
base_2_t() = default;
|
||||
|
||||
operator int() const {
|
||||
return value_2;
|
||||
}
|
||||
|
||||
int value_2{};
|
||||
};
|
||||
|
||||
@@ -32,6 +37,7 @@ struct MetaBase: ::testing::Test {
|
||||
.data<&base_1_t::value_1>("value_1"_hs);
|
||||
|
||||
entt::meta<base_2_t>()
|
||||
.conv<int>()
|
||||
.data<&base_2_t::value_2>("value_2"_hs);
|
||||
|
||||
entt::meta<base_3_t>()
|
||||
@@ -68,7 +74,7 @@ TEST_F(MetaBase, Functionalities) {
|
||||
ASSERT_EQ(any.cast<const base_1_t &>().value_1, as_derived.cast<const derived_t &>().value_1);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, ThisIsNotThis) {
|
||||
TEST_F(MetaBase, SetGetWithMutatingThis) {
|
||||
using namespace entt::literals;
|
||||
|
||||
derived_t instance;
|
||||
@@ -106,6 +112,44 @@ TEST_F(MetaBase, ThisIsNotThis) {
|
||||
ASSERT_EQ(instance.value_3, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, ConvWithMutatingThis) {
|
||||
entt::meta_any any{derived_t{}};
|
||||
auto as_cref = std::as_const(any).as_ref();
|
||||
any.cast<derived_t &>().value_2 = 42;
|
||||
|
||||
auto conv = std::as_const(any).allow_cast<int>();
|
||||
auto from_cref = std::as_const(as_cref).allow_cast<int>();
|
||||
|
||||
ASSERT_TRUE(conv);
|
||||
ASSERT_TRUE(from_cref);
|
||||
ASSERT_EQ(conv.cast<int>(), 42);
|
||||
ASSERT_EQ(from_cref.cast<int>(), 42);
|
||||
|
||||
ASSERT_TRUE(any.allow_cast<int>());
|
||||
ASSERT_TRUE(as_cref.allow_cast<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 42);
|
||||
ASSERT_EQ(as_cref.cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, OpaqueConvWithMutatingThis) {
|
||||
entt::meta_any any{derived_t{}};
|
||||
auto as_cref = std::as_const(any).as_ref();
|
||||
any.cast<derived_t &>().value_2 = 42;
|
||||
|
||||
auto conv = std::as_const(any).allow_cast(entt::resolve<int>());
|
||||
auto from_cref = std::as_const(as_cref).allow_cast(entt::resolve<int>());
|
||||
|
||||
ASSERT_TRUE(conv);
|
||||
ASSERT_TRUE(from_cref);
|
||||
ASSERT_EQ(conv.cast<int>(), 42);
|
||||
ASSERT_EQ(from_cref.cast<int>(), 42);
|
||||
|
||||
ASSERT_TRUE(any.allow_cast(entt::resolve<int>()));
|
||||
ASSERT_TRUE(as_cref.allow_cast(entt::resolve<int>()));
|
||||
ASSERT_EQ(any.cast<int>(), 42);
|
||||
ASSERT_EQ(as_cref.cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, ReRegistration) {
|
||||
SetUp();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user