stack_check_get_unqualified.hpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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_UNQUALIFIED_GET_HPP
  19. #define SOL_STACK_CHECK_UNQUALIFIED_GET_HPP
  20. #include <sol/stack_core.hpp>
  21. #include <sol/stack_get.hpp>
  22. #include <sol/stack_check.hpp>
  23. #include <sol/optional.hpp>
  24. #include <cstdlib>
  25. #include <cmath>
  26. #include <optional>
  27. #if SOL_IS_ON(SOL_STD_VARIANT)
  28. #include <variant>
  29. #endif // variant shenanigans (thanks, Mac OSX)
  30. namespace sol { namespace stack {
  31. template <typename T, typename>
  32. struct unqualified_check_getter {
  33. typedef decltype(stack_detail::unchecked_unqualified_get<T>(nullptr, -1, std::declval<record&>())) R;
  34. template <typename Optional, typename Handler>
  35. static Optional get_using(lua_State* L, int index, Handler&& handler, record& tracking) {
  36. if constexpr (!meta::meta_detail::is_adl_sol_lua_check_v<T> && !meta::meta_detail::is_adl_sol_lua_get_v<T>) {
  37. if constexpr (is_lua_reference_v<T>) {
  38. if constexpr (is_global_table_v<T>) {
  39. (void)L;
  40. (void)index;
  41. (void)handler;
  42. tracking.use(1);
  43. return true;
  44. }
  45. else {
  46. // actually check if it's none here, otherwise
  47. // we'll have a none object inside an optional!
  48. bool success = lua_isnoneornil(L, index) == 0 && stack::check<T>(L, index, &no_panic);
  49. if (!success) {
  50. // expected type, actual type
  51. tracking.use(static_cast<int>(success));
  52. handler(L, index, type::poly, type_of(L, index), "");
  53. return detail::associated_nullopt_v<Optional>;
  54. }
  55. return stack_detail::unchecked_get<T>(L, index, tracking);
  56. }
  57. }
  58. else if constexpr ((std::is_integral_v<T> || std::is_same_v<T, lua_Integer>)&&!std::is_same_v<T, bool>) {
  59. #if SOL_LUA_VERSION_I_ >= 503
  60. if (lua_isinteger(L, index) != 0) {
  61. tracking.use(1);
  62. return static_cast<T>(lua_tointeger(L, index));
  63. }
  64. #endif
  65. int isnum = 0;
  66. const lua_Number value = lua_tonumberx(L, index, &isnum);
  67. if (isnum != 0) {
  68. #if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS)
  69. const auto integer_value = llround(value);
  70. if (static_cast<lua_Number>(integer_value) == value) {
  71. tracking.use(1);
  72. return static_cast<T>(integer_value);
  73. }
  74. #else
  75. tracking.use(1);
  76. return static_cast<T>(value);
  77. #endif
  78. }
  79. const type t = type_of(L, index);
  80. tracking.use(static_cast<int>(t != type::none));
  81. handler(L, index, type::number, t, "not an integer");
  82. return detail::associated_nullopt_v<Optional>;
  83. }
  84. else if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, lua_Number>) {
  85. int isnum = 0;
  86. lua_Number value = lua_tonumberx(L, index, &isnum);
  87. if (isnum == 0) {
  88. type t = type_of(L, index);
  89. tracking.use(static_cast<int>(t != type::none));
  90. handler(L, index, type::number, t, "not a valid floating point number");
  91. return detail::associated_nullopt_v<Optional>;
  92. }
  93. tracking.use(1);
  94. return static_cast<T>(value);
  95. }
  96. else if constexpr (std::is_enum_v<T> && !meta::any_same_v<T, meta_function, type>) {
  97. int isnum = 0;
  98. lua_Integer value = lua_tointegerx(L, index, &isnum);
  99. if (isnum == 0) {
  100. type t = type_of(L, index);
  101. tracking.use(static_cast<int>(t != type::none));
  102. handler(L, index, type::number, t, "not a valid enumeration value");
  103. return detail::associated_nullopt_v<Optional>;
  104. }
  105. tracking.use(1);
  106. return static_cast<T>(value);
  107. }
  108. else {
  109. if (!unqualified_check<T>(L, index, std::forward<Handler>(handler))) {
  110. tracking.use(static_cast<int>(!lua_isnone(L, index)));
  111. return detail::associated_nullopt_v<Optional>;
  112. }
  113. return stack_detail::unchecked_unqualified_get<T>(L, index, tracking);
  114. }
  115. }
  116. else {
  117. if (!unqualified_check<T>(L, index, std::forward<Handler>(handler))) {
  118. tracking.use(static_cast<int>(!lua_isnone(L, index)));
  119. return detail::associated_nullopt_v<Optional>;
  120. }
  121. return stack_detail::unchecked_unqualified_get<T>(L, index, tracking);
  122. }
  123. }
  124. template <typename Handler>
  125. static optional<R> get(lua_State* L, int index, Handler&& handler, record& tracking) {
  126. return get_using<optional<R>>(L, index, std::forward<Handler>(handler), tracking);
  127. }
  128. };
  129. #if SOL_IS_ON(SOL_STD_VARIANT)
  130. template <typename... Tn, typename C>
  131. struct unqualified_check_getter<std::variant<Tn...>, C> {
  132. typedef std::variant<Tn...> V;
  133. typedef std::variant_size<V> V_size;
  134. typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
  135. template <typename Handler>
  136. static optional<V> get_empty(std::true_type, lua_State*, int, Handler&&, record&) {
  137. return nullopt;
  138. }
  139. template <typename Handler>
  140. static optional<V> get_empty(std::false_type, lua_State* L, int index, Handler&& handler, record&) {
  141. // This should never be reached...
  142. // please check your code and understand what you did to bring yourself here
  143. // maybe file a bug report, or 5
  144. handler(
  145. L, index, type::poly, type_of(L, index), "this variant code should never be reached: if it has, you have done something so terribly wrong");
  146. return nullopt;
  147. }
  148. template <typename Handler>
  149. static optional<V> get_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) {
  150. return get_empty(V_is_empty(), L, index, std::forward<Handler>(handler), tracking);
  151. }
  152. template <std::size_t I, typename Handler>
  153. static optional<V> get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) {
  154. typedef std::variant_alternative_t<I - 1, V> T;
  155. if (stack::check<T>(L, index, &no_panic, tracking)) {
  156. return V(std::in_place_index<I - 1>, stack::get<T>(L, index));
  157. }
  158. return get_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking);
  159. }
  160. template <typename Handler>
  161. static optional<V> get(lua_State* L, int index, Handler&& handler, record& tracking) {
  162. return get_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking);
  163. }
  164. };
  165. #endif // standard variant
  166. }} // namespace sol::stack
  167. #endif // SOL_STACK_CHECK_UNQUALIFIED_GET_HPP