stack_check_get_qualified.hpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // sol2
  2. // The MIT License (MIT)
  3. // Copyright (c) 2013-2022 Rapptz, ThePhD and contributors
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy of
  5. // this software and associated documentation files (the "Software"), to deal in
  6. // the Software without restriction, including without limitation the rights to
  7. // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  8. // the Software, and to permit persons to whom the Software is furnished to do so,
  9. // subject to the following conditions:
  10. // The above copyright notice and this permission notice shall be included in all
  11. // copies or substantial portions of the Software.
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  14. // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  15. // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  16. // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  17. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. #ifndef SOL_STACK_CHECK_QUALIFIED_GET_HPP
  19. #define SOL_STACK_CHECK_QUALIFIED_GET_HPP
  20. #include <sol/stack_core.hpp>
  21. #include <sol/stack_check_get_unqualified.hpp>
  22. #include <sol/optional.hpp>
  23. namespace sol { namespace stack {
  24. #if SOL_IS_ON(SOL_COMPILER_GCC)
  25. #pragma GCC diagnostic push
  26. #if !SOL_IS_ON(SOL_COMPILER_CLANG)
  27. #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
  28. #endif
  29. #endif
  30. namespace stack_detail {
  31. template <typename OptionalType, typename T, typename Handler>
  32. OptionalType get_optional(lua_State* L, int index, Handler&& handler, record& tracking) {
  33. using Tu = meta::unqualified_t<T>;
  34. if constexpr (is_lua_reference_v<T>) {
  35. if constexpr (is_global_table_v<Tu>) {
  36. (void)L;
  37. (void)index;
  38. (void)handler;
  39. tracking.use(1);
  40. return true;
  41. }
  42. else {
  43. // actually check if it's none here, otherwise
  44. // we'll have a none object inside an optional!
  45. bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, &no_panic);
  46. if (!success) {
  47. // expected type, actual type
  48. tracking.use(static_cast<int>(success));
  49. handler(L, index, type::poly, type_of(L, index), "");
  50. return {};
  51. }
  52. return OptionalType(stack_detail::unchecked_get<T>(L, index, tracking));
  53. }
  54. }
  55. else if constexpr (!std::is_reference_v<T> && is_unique_usertype_v<Tu> && !is_actual_type_rebindable_for_v<Tu>) {
  56. // we can take shortcuts here to save on separate checking, and just return nullopt!
  57. using element = unique_usertype_element_t<Tu>;
  58. using actual = unique_usertype_actual_t<Tu>;
  59. tracking.use(1);
  60. void* memory = lua_touserdata(L, index);
  61. memory = detail::align_usertype_unique_destructor(memory);
  62. detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
  63. if (&detail::usertype_unique_alloc_destroy<element, Tu> == pdx) {
  64. memory = detail::align_usertype_unique_tag<true, false>(memory);
  65. memory = detail::align_usertype_unique<actual, true, false>(memory);
  66. actual* mem = static_cast<actual*>(memory);
  67. return static_cast<actual>(*mem);
  68. }
  69. if constexpr (!derive<element>::value) {
  70. return OptionalType();
  71. }
  72. else {
  73. memory = detail::align_usertype_unique_tag<true, false>(memory);
  74. detail::unique_tag& ic = *reinterpret_cast<detail::unique_tag*>(memory);
  75. memory = detail::align_usertype_unique<actual, true, false>(memory);
  76. string_view ti = usertype_traits<element>::qualified_name();
  77. int cast_operation;
  78. actual r {};
  79. if constexpr (is_actual_type_rebindable_for_v<Tu>) {
  80. using rebound_actual_type = unique_usertype_rebind_actual_t<Tu, void>;
  81. string_view rebind_ti = usertype_traits<rebound_actual_type>::qualified_name();
  82. cast_operation = ic(memory, &r, ti, rebind_ti);
  83. }
  84. else {
  85. string_view rebind_ti("");
  86. cast_operation = ic(memory, &r, ti, rebind_ti);
  87. }
  88. switch (cast_operation) {
  89. case 1: {
  90. // it's a perfect match,
  91. // alias memory directly
  92. actual* mem = static_cast<actual*>(memory);
  93. return OptionalType(*mem);
  94. }
  95. case 2:
  96. // it's a base match, return the
  97. // aliased creation
  98. return OptionalType(std::move(r));
  99. default:
  100. break;
  101. }
  102. return OptionalType();
  103. }
  104. }
  105. else {
  106. if (!check<T>(L, index, std::forward<Handler>(handler))) {
  107. tracking.use(static_cast<int>(!lua_isnone(L, index)));
  108. return OptionalType();
  109. }
  110. return OptionalType(stack_detail::unchecked_get<T>(L, index, tracking));
  111. }
  112. }
  113. } // namespace stack_detail
  114. #if SOL_IS_ON(SOL_COMPILER_GCC)
  115. #pragma GCC diagnostic pop
  116. #endif
  117. template <typename T, typename>
  118. struct qualified_check_getter {
  119. typedef decltype(stack_detail::unchecked_get<T>(nullptr, -1, std::declval<record&>())) R;
  120. template <typename Handler>
  121. optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) {
  122. return stack_detail::get_optional<optional<R>, T>(L, index, std::forward<Handler>(handler), tracking);
  123. }
  124. };
  125. template <typename Optional>
  126. struct qualified_getter<Optional, std::enable_if_t<meta::is_optional_v<Optional>>> {
  127. static Optional get(lua_State* L, int index, record& tracking) {
  128. using T = typename meta::unqualified_t<Optional>::value_type;
  129. return stack_detail::get_optional<Optional, T>(L, index, &no_panic, tracking);
  130. }
  131. };
  132. }} // namespace sol::stack
  133. #endif // SOL_STACK_CHECK_QUALIFIED_GET_HPP