meta_factory.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. #include <array>
  2. #include <iterator>
  3. #include <string>
  4. #include <utility>
  5. #include <gtest/gtest.h>
  6. #include <entt/core/type_info.hpp>
  7. #include <entt/meta/context.hpp>
  8. #include <entt/meta/factory.hpp>
  9. #include <entt/meta/meta.hpp>
  10. #include <entt/meta/range.hpp>
  11. #include <entt/meta/resolve.hpp>
  12. #include "../../common/boxed_type.h"
  13. #include "../../common/config.h"
  14. #include "../../common/meta_traits.h"
  15. struct base {
  16. char member{};
  17. };
  18. struct clazz: base {
  19. clazz(int val)
  20. : value{val} {}
  21. explicit operator int() const noexcept {
  22. return get_int();
  23. }
  24. void set_int(int val) noexcept {
  25. value = val;
  26. }
  27. void set_boxed_int(test::boxed_int val) noexcept {
  28. value = val.value;
  29. }
  30. int get_int() const noexcept {
  31. return value;
  32. }
  33. static std::string to_string(const clazz &instance) {
  34. return std::to_string(instance.get_int());
  35. }
  36. static clazz from_string(const std::string &value) {
  37. return clazz{std::stoi(value)};
  38. }
  39. private:
  40. int value{};
  41. };
  42. struct dtor_callback {
  43. dtor_callback(bool &ref)
  44. : cb{&ref} {}
  45. static void on_destroy(dtor_callback &instance) {
  46. *instance.cb = !*instance.cb;
  47. }
  48. private:
  49. bool *cb;
  50. };
  51. struct MetaFactory: ::testing::Test {
  52. void TearDown() override {
  53. entt::meta_reset();
  54. }
  55. };
  56. using MetaFactoryDeathTest = MetaFactory;
  57. TEST_F(MetaFactory, Constructors) {
  58. entt::meta_ctx ctx{};
  59. ASSERT_EQ(entt::resolve(entt::type_id<int>()), entt::meta_type{});
  60. ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
  61. entt::meta_factory<int> factory{};
  62. ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
  63. ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
  64. // this is because of entt::meta, which should be deprecated nowadays
  65. ASSERT_FALSE(entt::resolve(entt::type_id<int>()).is_integral());
  66. factory = entt::meta_factory<int>{ctx};
  67. ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
  68. ASSERT_NE(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
  69. // this is because of entt::meta, which should be deprecated nowadays
  70. ASSERT_FALSE(entt::resolve(ctx, entt::type_id<int>()).is_integral());
  71. }
  72. TEST_F(MetaFactory, Type) {
  73. using namespace entt::literals;
  74. auto factory = entt::meta<int>();
  75. ASSERT_EQ(entt::resolve("foo"_hs), entt::meta_type{});
  76. factory.type("foo"_hs);
  77. ASSERT_NE(entt::resolve("foo"_hs), entt::meta_type{});
  78. ASSERT_EQ(entt::resolve<int>().id(), "foo"_hs);
  79. factory.type("bar"_hs);
  80. ASSERT_EQ(entt::resolve("foo"_hs), entt::meta_type{});
  81. ASSERT_NE(entt::resolve("bar"_hs), entt::meta_type{});
  82. ASSERT_EQ(entt::resolve<int>().id(), "bar"_hs);
  83. }
  84. ENTT_DEBUG_TEST_F(MetaFactoryDeathTest, Type) {
  85. using namespace entt::literals;
  86. auto factory = entt::meta<int>();
  87. auto other = entt::meta<double>();
  88. factory.type("foo"_hs);
  89. ASSERT_DEATH(other.type("foo"_hs);, "");
  90. }
  91. TEST_F(MetaFactory, Base) {
  92. auto factory = entt::meta<clazz>();
  93. decltype(std::declval<entt::meta_type>().base()) range{};
  94. ASSERT_NE(entt::resolve(entt::type_id<clazz>()), entt::meta_type{});
  95. ASSERT_EQ(entt::resolve(entt::type_id<base>()), entt::meta_type{});
  96. range = entt::resolve<clazz>().base();
  97. ASSERT_EQ(range.begin(), range.end());
  98. factory.base<base>();
  99. range = entt::resolve<clazz>().base();
  100. ASSERT_EQ(entt::resolve(entt::type_id<base>()), entt::meta_type{});
  101. ASSERT_NE(range.begin(), range.end());
  102. ASSERT_EQ(std::distance(range.begin(), range.end()), 1);
  103. ASSERT_EQ(range.begin()->first, entt::type_id<base>().hash());
  104. ASSERT_EQ(range.begin()->second.info(), entt::type_id<base>());
  105. }
  106. TEST_F(MetaFactory, Conv) {
  107. const clazz instance{3};
  108. auto factory = entt::meta<clazz>();
  109. const entt::meta_any any = entt::forward_as_meta(instance);
  110. ASSERT_FALSE(any.allow_cast<int>());
  111. ASSERT_FALSE(any.allow_cast<std::string>());
  112. factory.conv<int>().conv<&clazz::to_string>();
  113. ASSERT_TRUE(any.allow_cast<int>());
  114. ASSERT_TRUE(any.allow_cast<std::string>());
  115. ASSERT_EQ(any.allow_cast<int>().cast<int>(), instance.get_int());
  116. ASSERT_EQ(any.allow_cast<std::string>().cast<std::string>(), clazz::to_string(instance));
  117. }
  118. TEST_F(MetaFactory, Ctor) {
  119. const std::array values{1, 3};
  120. auto factory = entt::meta<clazz>();
  121. ASSERT_FALSE(entt::resolve<clazz>().construct(values[0u]));
  122. ASSERT_FALSE(entt::resolve<clazz>().construct(std::to_string(values[1u])));
  123. factory.ctor<int>().ctor<&clazz::from_string>();
  124. const auto instance = entt::resolve<clazz>().construct(values[0u]);
  125. const auto other = entt::resolve<clazz>().construct(std::to_string(values[1u]));
  126. ASSERT_TRUE(instance);
  127. ASSERT_TRUE(other);
  128. ASSERT_TRUE(instance.allow_cast<clazz>());
  129. ASSERT_TRUE(other.allow_cast<clazz>());
  130. ASSERT_EQ(instance.cast<const clazz &>().get_int(), values[0u]);
  131. ASSERT_EQ(other.cast<const clazz &>().get_int(), values[1u]);
  132. }
  133. TEST_F(MetaFactory, Dtor) {
  134. bool check = false;
  135. auto factory = entt::meta<dtor_callback>();
  136. entt::meta_any any{std::in_place_type<dtor_callback>, check};
  137. any.reset();
  138. ASSERT_FALSE(check);
  139. factory.dtor<&dtor_callback::on_destroy>();
  140. any.emplace<dtor_callback>(check);
  141. any.reset();
  142. ASSERT_TRUE(check);
  143. }
  144. TEST_F(MetaFactory, DataMemberObject) {
  145. using namespace entt::literals;
  146. base instance{'c'};
  147. auto factory = entt::meta<base>();
  148. entt::meta_type type = entt::resolve<base>();
  149. ASSERT_FALSE(type.data("member"_hs));
  150. factory.data<&base::member>("member"_hs);
  151. type = entt::resolve<base>();
  152. ASSERT_TRUE(type.data("member"_hs));
  153. ASSERT_EQ(type.get("member"_hs, std::as_const(instance)), instance.member);
  154. ASSERT_EQ(type.get("member"_hs, instance), instance.member);
  155. ASSERT_FALSE(type.set("member"_hs, std::as_const(instance), instance.member));
  156. ASSERT_TRUE(type.set("member"_hs, instance, instance.member));
  157. }
  158. TEST_F(MetaFactory, DataPointer) {
  159. using namespace entt::literals;
  160. auto factory = entt::meta<int>();
  161. entt::meta_type type = entt::resolve<int>();
  162. ASSERT_FALSE(type.data("value"_hs));
  163. static int value = 1;
  164. factory.data<&value>("value"_hs);
  165. type = entt::resolve<int>();
  166. ASSERT_TRUE(type.data("value"_hs));
  167. ASSERT_EQ(type.get("value"_hs, {}), value);
  168. ASSERT_TRUE(type.set("value"_hs, {}, value));
  169. }
  170. TEST_F(MetaFactory, DataValue) {
  171. using namespace entt::literals;
  172. constexpr int value = 1;
  173. auto factory = entt::meta<int>();
  174. entt::meta_type type = entt::resolve<int>();
  175. ASSERT_FALSE(type.data("value"_hs));
  176. factory.data<value>("value"_hs);
  177. type = entt::resolve<int>();
  178. ASSERT_TRUE(type.data("value"_hs));
  179. ASSERT_EQ(type.get("value"_hs, {}), value);
  180. ASSERT_FALSE(type.set("value"_hs, {}, value));
  181. }
  182. TEST_F(MetaFactory, DataGetterOnly) {
  183. using namespace entt::literals;
  184. clazz instance{1};
  185. auto factory = entt::meta<clazz>();
  186. entt::meta_type type = entt::resolve<clazz>();
  187. ASSERT_FALSE(type.data("value"_hs));
  188. factory.data<nullptr, &clazz::get_int>("value"_hs);
  189. type = entt::resolve<clazz>();
  190. ASSERT_TRUE(type.data("value"_hs));
  191. ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int());
  192. ASSERT_EQ(type.get("value"_hs, instance), instance.get_int());
  193. ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int()));
  194. ASSERT_FALSE(type.set("value"_hs, instance, instance.get_int()));
  195. }
  196. TEST_F(MetaFactory, DataSetterGetter) {
  197. using namespace entt::literals;
  198. clazz instance{1};
  199. auto factory = entt::meta<clazz>();
  200. entt::meta_type type = entt::resolve<clazz>();
  201. ASSERT_FALSE(type.data("value"_hs));
  202. factory.data<&clazz::set_int, &clazz::get_int>("value"_hs);
  203. type = entt::resolve<clazz>();
  204. ASSERT_TRUE(type.data("value"_hs));
  205. ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int());
  206. ASSERT_EQ(type.get("value"_hs, instance), instance.get_int());
  207. ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int()));
  208. ASSERT_TRUE(type.set("value"_hs, instance, instance.get_int()));
  209. }
  210. TEST_F(MetaFactory, DataMultiSetterGetter) {
  211. using namespace entt::literals;
  212. clazz instance{1};
  213. auto factory = entt::meta<clazz>();
  214. entt::meta_type type = entt::resolve<clazz>();
  215. ASSERT_FALSE(type.data("value"_hs));
  216. factory.data<entt::value_list<&clazz::set_int, &clazz::set_boxed_int>, &clazz::get_int>("value"_hs);
  217. type = entt::resolve<clazz>();
  218. ASSERT_TRUE(type.data("value"_hs));
  219. ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int());
  220. ASSERT_EQ(type.get("value"_hs, instance), instance.get_int());
  221. ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int()));
  222. ASSERT_TRUE(type.set("value"_hs, instance, instance.get_int()));
  223. ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), test::boxed_int{instance.get_int()}));
  224. ASSERT_TRUE(type.set("value"_hs, instance, test::boxed_int{instance.get_int()}));
  225. }
  226. TEST_F(MetaFactory, DataOverwrite) {
  227. using namespace entt::literals;
  228. auto factory = entt::meta<clazz>();
  229. entt::meta_type type = entt::resolve<clazz>();
  230. ASSERT_FALSE(type.data("value"_hs));
  231. factory.data<nullptr, &clazz::get_int>("value"_hs);
  232. type = entt::resolve<clazz>();
  233. ASSERT_TRUE(type.data("value"_hs));
  234. ASSERT_TRUE(type.data("value"_hs).is_const());
  235. factory.data<&clazz::set_int, &clazz::get_int>("value"_hs);
  236. type = entt::resolve<clazz>();
  237. ASSERT_TRUE(type.data("value"_hs));
  238. ASSERT_FALSE(type.data("value"_hs).is_const());
  239. }
  240. TEST_F(MetaFactory, Func) {
  241. using namespace entt::literals;
  242. const clazz instance{1};
  243. auto factory = entt::meta<clazz>();
  244. entt::meta_type type = entt::resolve<clazz>();
  245. ASSERT_FALSE(type.func("func"_hs));
  246. factory.func<&clazz::get_int>("func"_hs);
  247. type = entt::resolve<clazz>();
  248. ASSERT_TRUE(type.func("func"_hs));
  249. ASSERT_TRUE(type.invoke("func"_hs, instance));
  250. ASSERT_EQ(type.invoke("func"_hs, instance).cast<int>(), instance.get_int());
  251. ASSERT_FALSE(type.invoke("func"_hs, {}));
  252. }
  253. TEST_F(MetaFactory, FuncOverload) {
  254. using namespace entt::literals;
  255. clazz instance{1};
  256. auto factory = entt::meta<clazz>();
  257. entt::meta_type type = entt::resolve<clazz>();
  258. ASSERT_FALSE(type.func("func"_hs));
  259. factory.func<&clazz::set_int>("func"_hs);
  260. ASSERT_TRUE(type.func("func"_hs));
  261. ASSERT_FALSE(type.func("func"_hs).next());
  262. factory.func<&clazz::set_boxed_int>("func"_hs);
  263. ASSERT_TRUE(type.func("func"_hs));
  264. ASSERT_TRUE(type.func("func"_hs).next());
  265. ASSERT_FALSE(type.func("func"_hs).next().next());
  266. ASSERT_TRUE(type.invoke("func"_hs, instance, 2));
  267. ASSERT_EQ(instance.get_int(), 2);
  268. ASSERT_TRUE(type.invoke("func"_hs, instance, test::boxed_int{3}));
  269. ASSERT_EQ(instance.get_int(), 3);
  270. }
  271. TEST_F(MetaFactory, Traits) {
  272. using namespace entt::literals;
  273. entt::meta<clazz>()
  274. .data<&base::member>("member"_hs)
  275. .func<&clazz::set_int>("func"_hs)
  276. .func<&clazz::set_boxed_int>("func"_hs);
  277. entt::meta_type type = entt::resolve<clazz>();
  278. ASSERT_EQ(type.traits<test::meta_traits>(), test::meta_traits::none);
  279. ASSERT_EQ(type.data("member"_hs).traits<test::meta_traits>(), test::meta_traits::none);
  280. ASSERT_EQ(type.func("func"_hs).traits<test::meta_traits>(), test::meta_traits::none);
  281. ASSERT_EQ(type.func("func"_hs).next().traits<test::meta_traits>(), test::meta_traits::none);
  282. entt::meta<clazz>()
  283. .traits(test::meta_traits::one | test::meta_traits::three)
  284. .data<&base::member>("member"_hs)
  285. .traits(test::meta_traits::one)
  286. .func<&clazz::set_int>("func"_hs)
  287. .traits(test::meta_traits::two)
  288. .func<&clazz::set_boxed_int>("func"_hs)
  289. .traits(test::meta_traits::three);
  290. // traits are copied and never refreshed
  291. type = entt::resolve<clazz>();
  292. ASSERT_EQ(type.traits<test::meta_traits>(), test::meta_traits::one | test::meta_traits::three);
  293. ASSERT_EQ(type.data("member"_hs).traits<test::meta_traits>(), test::meta_traits::one);
  294. ASSERT_EQ(type.func("func"_hs).traits<test::meta_traits>(), test::meta_traits::two);
  295. ASSERT_EQ(type.func("func"_hs).next().traits<test::meta_traits>(), test::meta_traits::three);
  296. }
  297. TEST_F(MetaFactory, Custom) {
  298. using namespace entt::literals;
  299. entt::meta<clazz>()
  300. .data<&base::member>("member"_hs)
  301. .func<&clazz::set_int>("func"_hs)
  302. .func<&clazz::set_boxed_int>("func"_hs);
  303. entt::meta_type type = entt::resolve<clazz>();
  304. ASSERT_EQ(static_cast<const int *>(type.custom()), nullptr);
  305. ASSERT_EQ(static_cast<const int *>(type.data("member"_hs).custom()), nullptr);
  306. ASSERT_EQ(static_cast<const int *>(type.func("func"_hs).custom()), nullptr);
  307. ASSERT_EQ(static_cast<const int *>(type.func("func"_hs).next().custom()), nullptr);
  308. entt::meta<clazz>()
  309. .custom<int>(0)
  310. .data<&base::member>("member"_hs)
  311. .custom<int>(1)
  312. .func<&clazz::set_int>("func"_hs)
  313. .custom<int>(2)
  314. .func<&clazz::set_boxed_int>("func"_hs)
  315. .custom<int>(3);
  316. // custom data pointers are copied and never refreshed
  317. type = entt::resolve<clazz>();
  318. ASSERT_EQ(static_cast<int>(type.custom()), 0);
  319. ASSERT_EQ(static_cast<int>(type.data("member"_hs).custom()), 1);
  320. ASSERT_EQ(static_cast<int>(type.func("func"_hs).custom()), 2);
  321. ASSERT_EQ(static_cast<int>(type.func("func"_hs).next().custom()), 3);
  322. }
  323. TEST_F(MetaFactory, Meta) {
  324. entt::meta_ctx ctx{};
  325. ASSERT_EQ(entt::resolve(entt::type_id<int>()), entt::meta_type{});
  326. ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
  327. auto factory = entt::meta<int>();
  328. ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
  329. ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
  330. ASSERT_TRUE(entt::resolve(entt::type_id<int>()).is_integral());
  331. factory = entt::meta_factory<int>{ctx};
  332. ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
  333. ASSERT_NE(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
  334. ASSERT_FALSE(entt::resolve(ctx, entt::type_id<int>()).is_integral());
  335. }
  336. TEST_F(MetaFactory, MetaReset) {
  337. // TODO
  338. }