1
0
Эх сурвалжийг харах

meta: support all dereferenceable types (i.e. optional)

skypjack 2 долоо хоног өмнө
parent
commit
737676f23f

+ 5 - 1
src/entt/meta/meta.hpp

@@ -197,7 +197,11 @@ class meta_any {
             }
         } else if constexpr(requires(Type elem) { *elem; }) {
             if(req == internal::meta_traits::is_pointer) {
-                if constexpr(std::is_pointer_v<Type> && !std::is_void_v<std::remove_const_t<std::remove_pointer_t<Type>>>) {
+                if constexpr(std::is_class_v<Type>) {
+                    if(const auto &elem = any_cast<const Type &>(value.storage); elem) {
+                        return (value.storage.policy() == any_policy::cref) ? static_cast<meta_any *>(other)->emplace<decltype(*elem)>(*elem) : static_cast<meta_any *>(other)->emplace<decltype(*const_cast<Type &>(elem))>(*const_cast<Type &>(elem));
+                    }
+                } else if constexpr(!std::is_array_v<Type> && !std::is_void_v<std::remove_const_t<std::remove_pointer_t<Type>>>) {
                     if(auto *pointer = any_cast<Type>(value.storage); pointer) {
                         static_cast<meta_any *>(other)->emplace<std::conditional_t<std::is_function_v<std::remove_const_t<std::remove_pointer_t<Type>>>, Type, std::remove_pointer_t<Type> &>>(*pointer);
                     }

+ 35 - 0
test/entt/meta/meta_dereference.cpp

@@ -1,4 +1,5 @@
 #include <memory>
+#include <optional>
 #include <type_traits>
 #include <utility>
 #include <gtest/gtest.h>
@@ -214,6 +215,40 @@ TEST_F(MetaDereference, SmartPointer) {
     ASSERT_EQ(*value, 3);
 }
 
+TEST_F(MetaDereference, Optional) {
+    auto value = std::optional<int>(0);
+    entt::meta_any any{entt::forward_as_meta(value)};
+
+    ASSERT_FALSE(any.type().is_pointer());
+    ASSERT_FALSE(any.type().is_pointer_like());
+    ASSERT_EQ(any.type(), entt::resolve<std::optional<int>>());
+
+    auto deref = *any;
+
+    ASSERT_TRUE(deref);
+    ASSERT_FALSE(deref.type().is_pointer());
+    ASSERT_FALSE(deref.type().is_pointer_like());
+    ASSERT_EQ(deref.type(), entt::resolve<int>());
+
+    deref.cast<int &>() = 3;
+
+    ASSERT_EQ(*any.cast<std::optional<int>>(), 3);
+    ASSERT_EQ(*value, 3);
+}
+
+TEST_F(MetaDereference, EmptyOptional) {
+    auto value = std::optional<int>();
+    entt::meta_any any{entt::forward_as_meta(value)};
+
+    ASSERT_FALSE(any.type().is_pointer());
+    ASSERT_FALSE(any.type().is_pointer_like());
+    ASSERT_EQ(any.type(), entt::resolve<std::optional<int>>());
+
+    auto deref = *any;
+
+    ASSERT_FALSE(deref);
+}
+
 TEST_F(MetaDereference, PointerToConstMoveOnlyType) {
     const std::unique_ptr<int> instance;
     const entt::meta_any any{&instance};