meta_factory.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  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. [[nodiscard]] 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. [[nodiscard]] int get_int() const noexcept {
  31. return value;
  32. }
  33. [[nodiscard]] static std::string to_string(const clazz &instance) {
  34. return std::to_string(instance.get_int());
  35. }
  36. [[nodiscard]] 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. ASSERT_TRUE(entt::resolve(entt::type_id<int>()).is_integral());
  65. factory = entt::meta_factory<int>{ctx};
  66. ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
  67. ASSERT_NE(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
  68. ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()).is_integral());
  69. }
  70. TEST_F(MetaFactory, Type) {
  71. using namespace entt::literals;
  72. entt::meta_factory<int> factory{};
  73. ASSERT_EQ(entt::resolve("foo"_hs), entt::meta_type{});
  74. factory.type("foo"_hs);
  75. ASSERT_NE(entt::resolve("foo"_hs), entt::meta_type{});
  76. ASSERT_EQ(entt::resolve<int>().id(), "foo"_hs);
  77. factory.type("bar"_hs);
  78. ASSERT_EQ(entt::resolve("foo"_hs), entt::meta_type{});
  79. ASSERT_NE(entt::resolve("bar"_hs), entt::meta_type{});
  80. ASSERT_EQ(entt::resolve<int>().id(), "bar"_hs);
  81. }
  82. ENTT_DEBUG_TEST_F(MetaFactoryDeathTest, Type) {
  83. using namespace entt::literals;
  84. entt::meta_factory<int> factory{};
  85. entt::meta_factory<double> other{};
  86. factory.type("foo"_hs);
  87. ASSERT_DEATH(other.type("foo"_hs);, "");
  88. }
  89. TEST_F(MetaFactory, Base) {
  90. entt::meta_factory<clazz> factory{};
  91. decltype(std::declval<entt::meta_type>().base()) range{};
  92. ASSERT_NE(entt::resolve(entt::type_id<clazz>()), entt::meta_type{});
  93. ASSERT_EQ(entt::resolve(entt::type_id<base>()), entt::meta_type{});
  94. range = entt::resolve<clazz>().base();
  95. ASSERT_EQ(range.begin(), range.end());
  96. factory.base<base>();
  97. range = entt::resolve<clazz>().base();
  98. ASSERT_EQ(entt::resolve(entt::type_id<base>()), entt::meta_type{});
  99. ASSERT_NE(range.begin(), range.end());
  100. ASSERT_EQ(std::distance(range.begin(), range.end()), 1);
  101. ASSERT_EQ(range.begin()->first, entt::type_id<base>().hash());
  102. ASSERT_EQ(range.begin()->second.info(), entt::type_id<base>());
  103. }
  104. TEST_F(MetaFactory, Conv) {
  105. const clazz instance{3};
  106. entt::meta_factory<clazz> factory{};
  107. const entt::meta_any any = entt::forward_as_meta(instance);
  108. ASSERT_FALSE(any.allow_cast<int>());
  109. ASSERT_FALSE(any.allow_cast<std::string>());
  110. factory.conv<int>().conv<&clazz::to_string>();
  111. ASSERT_TRUE(any.allow_cast<int>());
  112. ASSERT_TRUE(any.allow_cast<std::string>());
  113. ASSERT_EQ(any.allow_cast<int>().cast<int>(), instance.get_int());
  114. ASSERT_EQ(any.allow_cast<std::string>().cast<std::string>(), clazz::to_string(instance));
  115. }
  116. TEST_F(MetaFactory, Ctor) {
  117. const std::array values{1, 3};
  118. entt::meta_factory<clazz> factory{};
  119. ASSERT_FALSE(entt::resolve<clazz>().construct(values[0u]));
  120. ASSERT_FALSE(entt::resolve<clazz>().construct(std::to_string(values[1u])));
  121. factory.ctor<int>().ctor<&clazz::from_string>();
  122. const auto instance = entt::resolve<clazz>().construct(values[0u]);
  123. const auto other = entt::resolve<clazz>().construct(std::to_string(values[1u]));
  124. ASSERT_TRUE(instance);
  125. ASSERT_TRUE(other);
  126. ASSERT_TRUE(instance.allow_cast<clazz>());
  127. ASSERT_TRUE(other.allow_cast<clazz>());
  128. ASSERT_EQ(instance.cast<const clazz &>().get_int(), values[0u]);
  129. ASSERT_EQ(other.cast<const clazz &>().get_int(), values[1u]);
  130. }
  131. TEST_F(MetaFactory, Dtor) {
  132. bool check = false;
  133. entt::meta_factory<dtor_callback> factory{};
  134. entt::meta_any any{std::in_place_type<dtor_callback>, check};
  135. any.reset();
  136. ASSERT_FALSE(check);
  137. factory.dtor<&dtor_callback::on_destroy>();
  138. any.emplace<dtor_callback>(check);
  139. any.reset();
  140. ASSERT_TRUE(check);
  141. }
  142. TEST_F(MetaFactory, DataMemberObject) {
  143. using namespace entt::literals;
  144. base instance{'c'};
  145. entt::meta_factory<base> factory{};
  146. entt::meta_type type = entt::resolve<base>();
  147. ASSERT_FALSE(type.data("member"_hs));
  148. factory.data<&base::member>("member"_hs);
  149. type = entt::resolve<base>();
  150. ASSERT_TRUE(type.data("member"_hs));
  151. ASSERT_EQ(type.get("member"_hs, std::as_const(instance)), instance.member);
  152. ASSERT_EQ(type.get("member"_hs, instance), instance.member);
  153. ASSERT_FALSE(type.set("member"_hs, std::as_const(instance), instance.member));
  154. ASSERT_TRUE(type.set("member"_hs, instance, instance.member));
  155. }
  156. TEST_F(MetaFactory, DataPointer) {
  157. using namespace entt::literals;
  158. entt::meta_factory<int> factory{};
  159. entt::meta_type type = entt::resolve<int>();
  160. ASSERT_FALSE(type.data("value"_hs));
  161. static int value = 1;
  162. factory.data<&value>("value"_hs);
  163. type = entt::resolve<int>();
  164. ASSERT_TRUE(type.data("value"_hs));
  165. ASSERT_EQ(type.get("value"_hs, {}), value);
  166. ASSERT_TRUE(type.set("value"_hs, {}, value));
  167. }
  168. TEST_F(MetaFactory, DataValue) {
  169. using namespace entt::literals;
  170. constexpr int value = 1;
  171. entt::meta_factory<int> factory{};
  172. entt::meta_type type = entt::resolve<int>();
  173. ASSERT_FALSE(type.data("value"_hs));
  174. factory.data<value>("value"_hs);
  175. type = entt::resolve<int>();
  176. ASSERT_TRUE(type.data("value"_hs));
  177. ASSERT_EQ(type.get("value"_hs, {}), value);
  178. ASSERT_FALSE(type.set("value"_hs, {}, value));
  179. }
  180. TEST_F(MetaFactory, DataGetterOnly) {
  181. using namespace entt::literals;
  182. clazz instance{1};
  183. entt::meta_factory<clazz> factory{};
  184. entt::meta_type type = entt::resolve<clazz>();
  185. ASSERT_FALSE(type.data("value"_hs));
  186. factory.data<nullptr, &clazz::get_int>("value"_hs);
  187. type = entt::resolve<clazz>();
  188. ASSERT_TRUE(type.data("value"_hs));
  189. ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int());
  190. ASSERT_EQ(type.get("value"_hs, instance), instance.get_int());
  191. ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int()));
  192. ASSERT_FALSE(type.set("value"_hs, instance, instance.get_int()));
  193. }
  194. TEST_F(MetaFactory, DataSetterGetter) {
  195. using namespace entt::literals;
  196. clazz instance{1};
  197. entt::meta_factory<clazz> factory{};
  198. entt::meta_type type = entt::resolve<clazz>();
  199. ASSERT_FALSE(type.data("value"_hs));
  200. factory.data<&clazz::set_int, &clazz::get_int>("value"_hs);
  201. type = entt::resolve<clazz>();
  202. ASSERT_TRUE(type.data("value"_hs));
  203. ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int());
  204. ASSERT_EQ(type.get("value"_hs, instance), instance.get_int());
  205. ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int()));
  206. ASSERT_TRUE(type.set("value"_hs, instance, instance.get_int()));
  207. }
  208. TEST_F(MetaFactory, DataOverwrite) {
  209. using namespace entt::literals;
  210. entt::meta_factory<clazz> factory{};
  211. entt::meta_type type = entt::resolve<clazz>();
  212. ASSERT_FALSE(type.data("value"_hs));
  213. factory.data<nullptr, &clazz::get_int>("value"_hs);
  214. type = entt::resolve<clazz>();
  215. ASSERT_TRUE(type.data("value"_hs));
  216. ASSERT_TRUE(type.data("value"_hs).is_const());
  217. factory.data<&clazz::set_int, &clazz::get_int>("value"_hs);
  218. type = entt::resolve<clazz>();
  219. ASSERT_TRUE(type.data("value"_hs));
  220. ASSERT_FALSE(type.data("value"_hs).is_const());
  221. }
  222. TEST_F(MetaFactory, Func) {
  223. using namespace entt::literals;
  224. const clazz instance{1};
  225. entt::meta_factory<clazz> factory{};
  226. entt::meta_type type = entt::resolve<clazz>();
  227. ASSERT_FALSE(type.func("func"_hs));
  228. factory.func<&clazz::get_int>("func"_hs);
  229. type = entt::resolve<clazz>();
  230. ASSERT_TRUE(type.func("func"_hs));
  231. ASSERT_TRUE(type.invoke("func"_hs, instance));
  232. ASSERT_EQ(type.invoke("func"_hs, instance).cast<int>(), instance.get_int());
  233. ASSERT_FALSE(type.invoke("func"_hs, {}));
  234. }
  235. TEST_F(MetaFactory, FuncOverload) {
  236. using namespace entt::literals;
  237. clazz instance{1};
  238. entt::meta_factory<clazz> factory{};
  239. const entt::meta_type type = entt::resolve<clazz>();
  240. ASSERT_FALSE(type.func("func"_hs));
  241. factory.func<&clazz::set_int>("func"_hs);
  242. ASSERT_TRUE(type.func("func"_hs));
  243. ASSERT_FALSE(type.func("func"_hs).next());
  244. factory.func<&clazz::set_boxed_int>("func"_hs);
  245. ASSERT_TRUE(type.func("func"_hs));
  246. ASSERT_TRUE(type.func("func"_hs).next());
  247. ASSERT_FALSE(type.func("func"_hs).next().next());
  248. ASSERT_TRUE(type.invoke("func"_hs, instance, 2));
  249. ASSERT_EQ(instance.get_int(), 2);
  250. ASSERT_TRUE(type.invoke("func"_hs, instance, test::boxed_int{3}));
  251. ASSERT_EQ(instance.get_int(), 3);
  252. }
  253. TEST_F(MetaFactory, Traits) {
  254. using namespace entt::literals;
  255. entt::meta_factory<clazz>{}
  256. .data<&base::member>("member"_hs)
  257. .func<&clazz::set_int>("func"_hs)
  258. .func<&clazz::set_boxed_int>("func"_hs);
  259. entt::meta_type type = entt::resolve<clazz>();
  260. ASSERT_EQ(type.traits<test::meta_traits>(), test::meta_traits::none);
  261. ASSERT_EQ(type.data("member"_hs).traits<test::meta_traits>(), test::meta_traits::none);
  262. ASSERT_EQ(type.func("func"_hs).traits<test::meta_traits>(), test::meta_traits::none);
  263. ASSERT_EQ(type.func("func"_hs).next().traits<test::meta_traits>(), test::meta_traits::none);
  264. entt::meta_factory<clazz>{}
  265. .traits(test::meta_traits::one | test::meta_traits::three)
  266. .data<&base::member>("member"_hs)
  267. .traits(test::meta_traits::one)
  268. .func<&clazz::set_int>("func"_hs)
  269. .traits(test::meta_traits::two)
  270. .func<&clazz::set_boxed_int>("func"_hs)
  271. .traits(test::meta_traits::three);
  272. // traits are copied and never refreshed
  273. type = entt::resolve<clazz>();
  274. ASSERT_EQ(type.traits<test::meta_traits>(), test::meta_traits::one | test::meta_traits::three);
  275. ASSERT_EQ(type.data("member"_hs).traits<test::meta_traits>(), test::meta_traits::one);
  276. ASSERT_EQ(type.func("func"_hs).traits<test::meta_traits>(), test::meta_traits::two);
  277. ASSERT_EQ(type.func("func"_hs).next().traits<test::meta_traits>(), test::meta_traits::three);
  278. }
  279. TEST_F(MetaFactory, Custom) {
  280. using namespace entt::literals;
  281. entt::meta_factory<clazz>{}
  282. .data<&base::member>("member"_hs)
  283. .func<&clazz::set_int>("func"_hs)
  284. .func<&clazz::set_boxed_int>("func"_hs);
  285. entt::meta_type type = entt::resolve<clazz>();
  286. ASSERT_EQ(static_cast<const int *>(type.custom()), nullptr);
  287. ASSERT_EQ(static_cast<const int *>(type.data("member"_hs).custom()), nullptr);
  288. ASSERT_EQ(static_cast<const int *>(type.func("func"_hs).custom()), nullptr);
  289. ASSERT_EQ(static_cast<const int *>(type.func("func"_hs).next().custom()), nullptr);
  290. entt::meta_factory<clazz>{}
  291. .custom<int>(0)
  292. .data<&base::member>("member"_hs)
  293. .custom<int>(1)
  294. .func<&clazz::set_int>("func"_hs)
  295. .custom<int>(2)
  296. .func<&clazz::set_boxed_int>("func"_hs)
  297. .custom<int>(3);
  298. // custom data pointers are copied and never refreshed
  299. type = entt::resolve<clazz>();
  300. ASSERT_EQ(static_cast<int>(type.custom()), 0);
  301. ASSERT_EQ(static_cast<int>(type.data("member"_hs).custom()), 1);
  302. ASSERT_EQ(static_cast<int>(type.func("func"_hs).custom()), 2);
  303. ASSERT_EQ(static_cast<int>(type.func("func"_hs).next().custom()), 3);
  304. }
  305. TEST_F(MetaFactory, Meta) {
  306. entt::meta_ctx ctx{};
  307. ASSERT_EQ(entt::resolve(entt::type_id<int>()), entt::meta_type{});
  308. ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
  309. auto factory = entt::meta<int>();
  310. ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
  311. ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
  312. ASSERT_TRUE(entt::resolve(entt::type_id<int>()).is_integral());
  313. factory = entt::meta<int>(ctx);
  314. ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
  315. ASSERT_NE(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
  316. ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()).is_integral());
  317. }
  318. TEST_F(MetaFactory, MetaReset) {
  319. using namespace entt::literals;
  320. entt::meta_ctx ctx{};
  321. entt::meta_factory<int>{}.type("global"_hs);
  322. entt::meta_factory<int>{ctx}.type("local"_hs);
  323. ASSERT_TRUE(entt::resolve(entt::type_id<int>()));
  324. ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
  325. entt::meta_reset();
  326. ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
  327. ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
  328. entt::meta_reset(ctx);
  329. ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
  330. ASSERT_FALSE(entt::resolve(ctx, entt::type_id<int>()));
  331. entt::meta_factory<int>{}.type("global"_hs);
  332. entt::meta_factory<int>{ctx}.type("local"_hs);
  333. ASSERT_TRUE(entt::resolve(entt::type_id<int>()));
  334. ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
  335. entt::meta_reset<int>();
  336. ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
  337. ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
  338. entt::meta_reset<int>(ctx);
  339. ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
  340. ASSERT_FALSE(entt::resolve(ctx, entt::type_id<int>()));
  341. entt::meta_factory<int>{}.type("global"_hs);
  342. entt::meta_factory<int>{ctx}.type("local"_hs);
  343. ASSERT_TRUE(entt::resolve(entt::type_id<int>()));
  344. ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
  345. entt::meta_reset("global"_hs);
  346. ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
  347. ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
  348. entt::meta_reset(ctx, "local"_hs);
  349. ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
  350. ASSERT_FALSE(entt::resolve(ctx, entt::type_id<int>()));
  351. }