stack_check_unqualified.hpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  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_HPP
  19. #define SOL_STACK_CHECK_UNQUALIFIED_HPP
  20. #include <sol/stack_core.hpp>
  21. #include <sol/usertype_traits.hpp>
  22. #include <sol/inheritance.hpp>
  23. #include <memory>
  24. #include <functional>
  25. #include <utility>
  26. #include <cmath>
  27. #include <optional>
  28. #if SOL_IS_ON(SOL_STD_VARIANT)
  29. #include <variant>
  30. #endif // variant shenanigans
  31. namespace sol { namespace stack {
  32. template <typename Handler>
  33. bool loose_table_check(lua_State* L_, int index, Handler&& handler, record& tracking) {
  34. tracking.use(1);
  35. type t = type_of(L_, index);
  36. if (t == type::table) {
  37. return true;
  38. }
  39. if (t != type::userdata) {
  40. handler(L_, index, type::table, t, "value is not a table or a userdata that can behave like one");
  41. return false;
  42. }
  43. return true;
  44. }
  45. namespace stack_detail {
  46. inline bool impl_check_metatable(lua_State* L_, int index, const std::string& metakey, bool poptable) {
  47. luaL_getmetatable(L_, &metakey[0]);
  48. const type expectedmetatabletype = static_cast<type>(lua_type(L_, -1));
  49. if (expectedmetatabletype != type::lua_nil) {
  50. if (lua_rawequal(L_, -1, index) == 1) {
  51. lua_pop(L_, 1 + static_cast<int>(poptable));
  52. return true;
  53. }
  54. }
  55. lua_pop(L_, 1);
  56. return false;
  57. }
  58. template <typename T, bool poptable = true>
  59. inline bool check_metatable(lua_State* L_, int index = -2) {
  60. return impl_check_metatable(L_, index, usertype_traits<T>::metatable(), poptable);
  61. }
  62. template <type expected, int (*check_func)(lua_State*, int)>
  63. struct basic_check {
  64. template <typename Handler>
  65. static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
  66. tracking.use(1);
  67. bool success = check_func(L_, index) == 1;
  68. if (!success) {
  69. // expected type, actual type
  70. handler(L_, index, expected, type_of(L_, index), "");
  71. }
  72. return success;
  73. }
  74. };
  75. } // namespace stack_detail
  76. template <typename T, typename>
  77. struct unqualified_interop_checker {
  78. template <typename Handler>
  79. static bool check(lua_State*, int, type, Handler&&, record&) {
  80. return false;
  81. }
  82. };
  83. template <typename T, typename>
  84. struct qualified_interop_checker {
  85. template <typename Handler>
  86. static bool check(lua_State* L_, int index, type index_type, Handler&& handler, record& tracking) {
  87. return stack_detail::unqualified_interop_check<T>(L_, index, index_type, std::forward<Handler>(handler), tracking);
  88. }
  89. };
  90. template <typename T, type expected, typename>
  91. struct unqualified_checker {
  92. template <typename Handler>
  93. static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
  94. if constexpr (std::is_same_v<T, bool>) {
  95. tracking.use(1);
  96. bool success = lua_isboolean(L_, index) == 1;
  97. if (!success) {
  98. // expected type, actual type
  99. handler(L_, index, expected, type_of(L_, index), "");
  100. }
  101. return success;
  102. }
  103. else if constexpr (meta::any_same_v<T,
  104. char
  105. #if SOL_IS_ON(SOL_CHAR8_T)
  106. ,
  107. char8_t
  108. #endif
  109. ,
  110. char16_t,
  111. char32_t>) {
  112. return stack::check<std::basic_string<T>>(L_, index, std::forward<Handler>(handler), tracking);
  113. }
  114. else if constexpr (std::is_integral_v<T> || std::is_same_v<T, lua_Integer>) {
  115. tracking.use(1);
  116. #if SOL_LUA_VERSION_I_ >= 503
  117. // Lua 5.3 and greater checks for numeric precision
  118. #if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS)
  119. // imprecise, sloppy conversions
  120. int isnum = 0;
  121. lua_tointegerx(L_, index, &isnum);
  122. const bool success = isnum != 0;
  123. if (!success) {
  124. // expected type, actual type
  125. handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string_integral);
  126. }
  127. #elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS)
  128. // this check is precise, do not convert
  129. if (lua_isinteger(L_, index) == 1) {
  130. return true;
  131. }
  132. const bool success = false;
  133. if (!success) {
  134. // expected type, actual type
  135. handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_integral);
  136. }
  137. #else
  138. // Numerics are neither safe nor string-convertible
  139. type t = type_of(L_, index);
  140. const bool success = t == type::number;
  141. #endif
  142. if (!success) {
  143. // expected type, actual type
  144. handler(L_, index, type::number, type_of(L_, index), detail::not_a_number);
  145. }
  146. return success;
  147. #else
  148. // Lua 5.2 and below checks
  149. #if SOL_IS_OFF(SOL_STRINGS_ARE_NUMBERS)
  150. // must pre-check, because it will convert
  151. type t = type_of(L_, index);
  152. if (t != type::number) {
  153. // expected type, actual type
  154. handler(L_, index, type::number, t, detail::not_a_number);
  155. return false;
  156. }
  157. #endif // Do not allow strings to be numbers
  158. #if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS)
  159. int isnum = 0;
  160. const lua_Number v = lua_tonumberx(L_, index, &isnum);
  161. const bool success = isnum != 0 && static_cast<lua_Number>(llround(v)) == v;
  162. #else
  163. const bool success = true;
  164. #endif // Safe numerics and number precision checking
  165. if (!success) {
  166. // Use defines to provide a better error message!
  167. #if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS)
  168. handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string);
  169. #elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS)
  170. handler(L_, index, type::number, t, detail::not_a_number_or_number_string);
  171. #else
  172. handler(L_, index, type::number, t, detail::not_a_number);
  173. #endif
  174. }
  175. return success;
  176. #endif
  177. }
  178. else if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, lua_Number>) {
  179. tracking.use(1);
  180. #if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS)
  181. bool success = lua_isnumber(L_, index) == 1;
  182. if (!success) {
  183. // expected type, actual type
  184. handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string);
  185. }
  186. return success;
  187. #else
  188. type t = type_of(L_, index);
  189. bool success = t == type::number;
  190. if (!success) {
  191. // expected type, actual type
  192. handler(L_, index, type::number, t, detail::not_a_number);
  193. }
  194. return success;
  195. #endif // Strings are Numbers
  196. }
  197. else if constexpr (meta::any_same_v<T, type, this_state, this_main_state, this_environment, variadic_args>) {
  198. (void)L_;
  199. (void)index;
  200. (void)handler;
  201. tracking.use(0);
  202. return true;
  203. }
  204. else if constexpr (is_unique_usertype_v<T>) {
  205. using element = unique_usertype_element_t<T>;
  206. using actual = unique_usertype_actual_t<T>;
  207. const type indextype = type_of(L_, index);
  208. tracking.use(1);
  209. if (indextype != type::userdata) {
  210. handler(L_, index, type::userdata, indextype, "value is not a userdata");
  211. return false;
  212. }
  213. if (lua_getmetatable(L_, index) == 0) {
  214. return true;
  215. }
  216. int metatableindex = lua_gettop(L_);
  217. if (stack_detail::check_metatable<d::u<element>>(L_, metatableindex)) {
  218. void* memory = lua_touserdata(L_, index);
  219. memory = detail::align_usertype_unique_destructor(memory);
  220. detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
  221. bool success = &detail::usertype_unique_alloc_destroy<element, actual> == pdx;
  222. if (!success) {
  223. memory = detail::align_usertype_unique_tag<true>(memory);
  224. #if 0
  225. // New version, one day
  226. #else
  227. const char*& name_tag = *static_cast<const char**>(memory);
  228. success = usertype_traits<T>::qualified_name() == name_tag;
  229. #endif
  230. if (!success) {
  231. handler(L_, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
  232. }
  233. }
  234. return success;
  235. }
  236. lua_pop(L_, 1);
  237. handler(L_, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)");
  238. return false;
  239. }
  240. else if constexpr (meta::any_same_v<T, lua_nil_t, std::nullopt_t, nullopt_t>) {
  241. bool success = lua_isnil(L_, index);
  242. if (success) {
  243. tracking.use(1);
  244. return success;
  245. }
  246. tracking.use(0);
  247. success = lua_isnone(L_, index);
  248. if (!success) {
  249. // expected type, actual type
  250. handler(L_, index, expected, type_of(L_, index), "");
  251. }
  252. return success;
  253. }
  254. else if constexpr (std::is_same_v<T, env_key_t>) {
  255. tracking.use(1);
  256. type t = type_of(L_, index);
  257. if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) {
  258. return true;
  259. }
  260. handler(L_, index, type::table, t, "value cannot not have a valid environment");
  261. return true;
  262. }
  263. else if constexpr (std::is_same_v<T, detail::non_lua_nil_t>) {
  264. return !stack::unqualified_check<lua_nil_t>(L_, index, std::forward<Handler>(handler), tracking);
  265. }
  266. else if constexpr (meta::is_specialization_of_v<T, basic_lua_table>) {
  267. tracking.use(1);
  268. type t = type_of(L_, index);
  269. if (t != type::table) {
  270. handler(L_, index, type::table, t, "value is not a table");
  271. return false;
  272. }
  273. return true;
  274. }
  275. else if constexpr (meta::is_specialization_of_v<T, basic_bytecode>) {
  276. tracking.use(1);
  277. type t = type_of(L_, index);
  278. if (t != type::function) {
  279. handler(L_, index, type::function, t, "value is not a function that can be dumped");
  280. return false;
  281. }
  282. return true;
  283. }
  284. else if constexpr (meta::is_specialization_of_v<T, basic_environment>) {
  285. tracking.use(1);
  286. if (lua_getmetatable(L_, index) == 0) {
  287. return true;
  288. }
  289. type t = type_of(L_, -1);
  290. if (t == type::table || t == type::none || t == type::lua_nil) {
  291. lua_pop(L_, 1);
  292. return true;
  293. }
  294. if (t != type::userdata) {
  295. lua_pop(L_, 1);
  296. handler(L_, index, type::table, t, "value does not have a valid metatable");
  297. return false;
  298. }
  299. return true;
  300. }
  301. else if constexpr (std::is_same_v<T, metatable_key_t>) {
  302. tracking.use(1);
  303. if (lua_getmetatable(L_, index) == 0) {
  304. return true;
  305. }
  306. type t = type_of(L_, -1);
  307. if (t == type::table || t == type::none || t == type::lua_nil) {
  308. lua_pop(L_, 1);
  309. return true;
  310. }
  311. if (t != type::userdata) {
  312. lua_pop(L_, 1);
  313. handler(L_, index, expected, t, "value does not have a valid metatable");
  314. return false;
  315. }
  316. return true;
  317. }
  318. else if constexpr (std::is_same_v<T, luaL_Stream*> || std::is_same_v<T, luaL_Stream>) {
  319. if (lua_getmetatable(L_, index) == 0) {
  320. type t = type_of(L_, index);
  321. handler(L_, index, expected, t, "value is not a valid luaL_Stream (has no metatable/is not a valid value)");
  322. return false;
  323. }
  324. luaL_getmetatable(L_, LUA_FILEHANDLE);
  325. if (type_of(L_, index) != type::table) {
  326. type t = type_of(L_, index);
  327. lua_pop(L_, 1);
  328. handler(L_,
  329. index,
  330. expected,
  331. t,
  332. "value is not a valid luaL_Stream (there is no metatable for luaL_Stream -- did you forget to "
  333. "my_lua_state.open_libraries(sol::lib::state) or equivalent?)");
  334. return false;
  335. }
  336. int is_stream_table = lua_compare(L_, -1, -2, LUA_OPEQ);
  337. lua_pop(L_, 2);
  338. if (is_stream_table == 0) {
  339. type t = type_of(L_, index);
  340. handler(L_, index, expected, t, "value is not a valid luaL_Stream (incorrect metatable)");
  341. return false;
  342. }
  343. return true;
  344. }
  345. else if constexpr (meta::is_optional_v<T>) {
  346. using ValueType = typename T::value_type;
  347. (void)handler;
  348. type t = type_of(L_, index);
  349. if (t == type::none) {
  350. tracking.use(0);
  351. return true;
  352. }
  353. if (t == type::lua_nil) {
  354. tracking.use(1);
  355. return true;
  356. }
  357. return stack::unqualified_check<ValueType>(L_, index, &no_panic, tracking);
  358. }
  359. #if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE)
  360. else if constexpr (std::is_function_v<T> || (std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t<T>>)) {
  361. return stack_detail::check_function_pointer<std::remove_pointer_t<T>>(L_, index, std::forward<Handler>(handler), tracking);
  362. }
  363. #endif
  364. else if constexpr (expected == type::userdata) {
  365. if constexpr (meta::any_same_v<T, userdata_value> || meta::is_specialization_of_v<T, basic_userdata>) {
  366. tracking.use(1);
  367. type t = type_of(L_, index);
  368. bool success = t == type::userdata;
  369. if (!success) {
  370. // expected type, actual type
  371. handler(L_, index, type::userdata, t, "");
  372. }
  373. return success;
  374. }
  375. else if constexpr (meta::is_specialization_of_v<T, user>) {
  376. unqualified_checker<lightuserdata_value, type::userdata> c;
  377. (void)c;
  378. return c.check(L_, index, std::forward<Handler>(handler), tracking);
  379. }
  380. else {
  381. if constexpr (std::is_pointer_v<T>) {
  382. return check_usertype<T>(L_, index, std::forward<Handler>(handler), tracking);
  383. }
  384. else if constexpr (meta::is_specialization_of_v<T, std::reference_wrapper>) {
  385. using T_internal = typename T::type;
  386. return stack::check<T_internal>(L_, index, std::forward<Handler>(handler), tracking);
  387. }
  388. else {
  389. return check_usertype<T>(L_, index, std::forward<Handler>(handler), tracking);
  390. }
  391. }
  392. }
  393. else if constexpr (expected == type::poly) {
  394. tracking.use(1);
  395. bool success = is_lua_reference_v<T> || !lua_isnone(L_, index);
  396. if (!success) {
  397. // expected type, actual type
  398. handler(L_, index, type::poly, type_of(L_, index), "");
  399. }
  400. return success;
  401. }
  402. else if constexpr (expected == type::lightuserdata) {
  403. tracking.use(1);
  404. type t = type_of(L_, index);
  405. bool success = t == type::userdata || t == type::lightuserdata;
  406. if (!success) {
  407. // expected type, actual type
  408. handler(L_, index, type::lightuserdata, t, "");
  409. }
  410. return success;
  411. }
  412. else if constexpr (expected == type::function) {
  413. if constexpr (meta::any_same_v<T, lua_CFunction, std::remove_pointer_t<lua_CFunction>, c_closure>) {
  414. tracking.use(1);
  415. bool success = lua_iscfunction(L_, index) == 1;
  416. if (!success) {
  417. // expected type, actual type
  418. handler(L_, index, expected, type_of(L_, index), "");
  419. }
  420. return success;
  421. }
  422. else {
  423. tracking.use(1);
  424. type t = type_of(L_, index);
  425. if (t == type::lua_nil || t == type::none || t == type::function) {
  426. // allow for lua_nil to be returned
  427. return true;
  428. }
  429. if (t != type::userdata && t != type::table) {
  430. handler(L_, index, type::function, t, "must be a function or table or a userdata");
  431. return false;
  432. }
  433. // Do advanced check for call-style userdata?
  434. static const auto& callkey = to_string(meta_function::call);
  435. if (lua_getmetatable(L_, index) == 0) {
  436. // No metatable, no __call key possible
  437. handler(L_, index, type::function, t, "value is not a function and does not have overriden metatable");
  438. return false;
  439. }
  440. if (lua_isnoneornil(L_, -1)) {
  441. lua_pop(L_, 1);
  442. handler(L_, index, type::function, t, "value is not a function and does not have valid metatable");
  443. return false;
  444. }
  445. lua_getfield(L_, -1, &callkey[0]);
  446. if (lua_isnoneornil(L_, -1)) {
  447. lua_pop(L_, 2);
  448. handler(L_, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type");
  449. return false;
  450. }
  451. // has call, is definitely a function
  452. lua_pop(L_, 2);
  453. return true;
  454. }
  455. }
  456. else if constexpr (expected == type::table) {
  457. return stack::loose_table_check(L_, index, std::forward<Handler>(handler), tracking);
  458. }
  459. else {
  460. tracking.use(1);
  461. const type indextype = type_of(L_, index);
  462. bool success = expected == indextype;
  463. if (!success) {
  464. // expected type, actual type, message
  465. handler(L_, index, expected, indextype, "");
  466. }
  467. return success;
  468. }
  469. }
  470. };
  471. template <typename T>
  472. struct unqualified_checker<non_null<T>, type::userdata> : unqualified_checker<T, lua_type_of_v<T>> { };
  473. template <typename T>
  474. struct unqualified_checker<detail::as_value_tag<T>, type::userdata> {
  475. template <typename Handler>
  476. static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
  477. const type indextype = type_of(L_, index);
  478. return check(types<T>(), L_, index, indextype, std::forward<Handler>(handler), tracking);
  479. }
  480. template <typename U, typename Handler>
  481. static bool check(types<U>, lua_State* L_, int index, type indextype, Handler&& handler, record& tracking) {
  482. if constexpr (
  483. std::is_same_v<T,
  484. lightuserdata_value> || std::is_same_v<T, userdata_value> || std::is_same_v<T, userdata> || std::is_same_v<T, lightuserdata>) {
  485. tracking.use(1);
  486. if (indextype != type::userdata) {
  487. handler(L_, index, type::userdata, indextype, "value is not a valid userdata");
  488. return false;
  489. }
  490. return true;
  491. }
  492. else {
  493. #if SOL_IS_ON(SOL_USE_INTEROP)
  494. if (stack_detail::interop_check<U>(L_, index, indextype, handler, tracking)) {
  495. return true;
  496. }
  497. #endif // interop extensibility
  498. tracking.use(1);
  499. #if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE)
  500. if (lua_iscfunction(L_, index) != 0) {
  501. // a potential match...
  502. return true;
  503. }
  504. #endif
  505. if (indextype != type::userdata) {
  506. handler(L_, index, type::userdata, indextype, "value is not a valid userdata");
  507. return false;
  508. }
  509. if (lua_getmetatable(L_, index) == 0) {
  510. return true;
  511. }
  512. int metatableindex = lua_gettop(L_);
  513. if (stack_detail::check_metatable<U>(L_, metatableindex))
  514. return true;
  515. if (stack_detail::check_metatable<U*>(L_, metatableindex))
  516. return true;
  517. if (stack_detail::check_metatable<d::u<U>>(L_, metatableindex))
  518. return true;
  519. if (stack_detail::check_metatable<as_container_t<U>>(L_, metatableindex))
  520. return true;
  521. bool success = false;
  522. bool has_derived = derive<T>::value || weak_derive<T>::value;
  523. if (has_derived) {
  524. #if SOL_IS_ON(SOL_SAFE_STACK_CHECK)
  525. luaL_checkstack(L_, 1, detail::not_enough_stack_space_string);
  526. #endif // make sure stack doesn't overflow
  527. auto pn = stack::pop_n(L_, 1);
  528. lua_pushstring(L_, &detail::base_class_check_key()[0]);
  529. lua_rawget(L_, metatableindex);
  530. if (type_of(L_, -1) != type::lua_nil) {
  531. void* basecastdata = lua_touserdata(L_, -1);
  532. detail::inheritance_check_function ic = reinterpret_cast<detail::inheritance_check_function>(basecastdata);
  533. success = ic(usertype_traits<T>::qualified_name());
  534. }
  535. }
  536. lua_pop(L_, 1);
  537. if (!success) {
  538. handler(L_, index, type::userdata, indextype, "value at this index does not properly reflect the desired type");
  539. return false;
  540. }
  541. return true;
  542. }
  543. }
  544. };
  545. template <typename T>
  546. struct unqualified_checker<detail::as_pointer_tag<T>, type::userdata> {
  547. template <typename Handler>
  548. static bool check(lua_State* L_, int index, type indextype, Handler&& handler, record& tracking) {
  549. if (indextype == type::lua_nil) {
  550. tracking.use(1);
  551. return true;
  552. }
  553. return check_usertype<std::remove_pointer_t<T>>(L_, index, std::forward<Handler>(handler), tracking);
  554. }
  555. template <typename Handler>
  556. static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
  557. const type indextype = type_of(L_, index);
  558. return check(L_, index, indextype, std::forward<Handler>(handler), tracking);
  559. }
  560. };
  561. template <typename T, std::size_t N, type expect>
  562. struct unqualified_checker<exhaustive_until<T, N>, expect> {
  563. template <typename K, typename V, typename Handler>
  564. static bool check_two(types<K, V>, lua_State* arg_L, int relindex, type indextype, Handler&& handler, record& tracking) {
  565. tracking.use(1);
  566. #if SOL_IS_ON(SOL_SAFE_STACK_CHECK)
  567. luaL_checkstack(arg_L, 3, detail::not_enough_stack_space_generic);
  568. #endif // make sure stack doesn't overflow
  569. int index = lua_absindex(arg_L, relindex);
  570. lua_pushnil(arg_L);
  571. while (lua_next(arg_L, index) != 0) {
  572. const bool is_key_okay = stack::check<K>(arg_L, -2, std::forward<Handler>(handler), tracking);
  573. if (!is_key_okay) {
  574. lua_pop(arg_L, 2);
  575. return false;
  576. }
  577. const bool is_value_okay = stack::check<V>(arg_L, -1, std::forward<Handler>(handler), tracking);
  578. if (!is_value_okay) {
  579. lua_pop(arg_L, 2);
  580. return false;
  581. }
  582. lua_pop(arg_L, 1);
  583. }
  584. return true;
  585. }
  586. template <typename V, typename Handler>
  587. static bool check_one(types<V>, lua_State* arg_L, int relindex, type, Handler&& handler, record& tracking) {
  588. tracking.use(1);
  589. size_t index = lua_absindex(arg_L, relindex);
  590. // Zzzz slower but necessary thanks to the lower version API and missing functions qq
  591. std::size_t idx = 0;
  592. int vi = 0;
  593. for (lua_Integer i = 0;; (void)(i += lua_size<V>::value), lua_pop(arg_L, static_cast<int>(vi))) {
  594. vi = 0;
  595. if (idx >= N) {
  596. return true;
  597. }
  598. #if SOL_IS_ON(SOL_SAFE_STACK_CHECK)
  599. luaL_checkstack(arg_L, 2, detail::not_enough_stack_space_generic);
  600. #endif // make sure stack doesn't overflow
  601. bool isnil = false;
  602. for (; vi < static_cast<int>(lua_size<V>::value); ++vi) {
  603. lua_pushinteger(arg_L, i);
  604. lua_gettable(arg_L, static_cast<int>(index));
  605. type vt = type_of(arg_L, -1);
  606. isnil = vt == type::lua_nil;
  607. if (isnil) {
  608. if (i == 0) {
  609. vi += 1;
  610. goto loop_continue;
  611. }
  612. lua_pop(arg_L, static_cast<int>(vi + 1));
  613. return true;
  614. }
  615. }
  616. if (!stack::check<V>(arg_L, -lua_size<V>::value, std::forward<Handler>(handler), tracking)) {
  617. lua_pop(arg_L, lua_size<V>::value);
  618. return false;
  619. }
  620. ++idx;
  621. loop_continue:;
  622. }
  623. }
  624. template <typename Handler>
  625. static bool check(lua_State* arg_L, int index, Handler&& handler, record& tracking) {
  626. using Tu = meta::unqualified_t<T>;
  627. if constexpr (is_container_v<Tu>) {
  628. if constexpr (meta::is_associative<Tu>::value) {
  629. typedef typename Tu::value_type P;
  630. typedef typename P::first_type K;
  631. typedef typename P::second_type V;
  632. return check_two(types<K, V>(), arg_L, index, expect, std::forward<Handler>(handler), tracking);
  633. }
  634. else {
  635. typedef typename Tu::value_type V;
  636. return check_one(types<V>(), arg_L, index, expect, std::forward<Handler>(handler), tracking);
  637. }
  638. }
  639. else {
  640. unqualified_checker<Tu, expect> c {};
  641. return c.check(arg_L, index, std::forward<Handler>(handler), tracking);
  642. }
  643. }
  644. };
  645. template <typename T, type expect>
  646. struct unqualified_checker<non_exhaustive<T>, expect> {
  647. template <typename Handler>
  648. static bool check(lua_State* arg_L, int index, Handler&& handler, record& tracking) {
  649. return stack::check<T>(arg_L, index, std::forward<Handler>(handler), tracking);
  650. }
  651. };
  652. template <typename... Args>
  653. struct unqualified_checker<std::tuple<Args...>, type::poly> {
  654. template <typename Handler>
  655. static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
  656. return stack::multi_check<Args...>(L_, index, std::forward<Handler>(handler), tracking);
  657. }
  658. };
  659. template <typename A, typename B>
  660. struct unqualified_checker<std::pair<A, B>, type::poly> {
  661. template <typename Handler>
  662. static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
  663. return stack::multi_check<A, B>(L_, index, std::forward<Handler>(handler), tracking);
  664. }
  665. };
  666. #if SOL_IS_ON(SOL_STD_VARIANT)
  667. template <typename... Tn>
  668. struct unqualified_checker<std::variant<Tn...>, type::poly> {
  669. typedef std::variant<Tn...> V;
  670. typedef std::variant_size<V> V_size;
  671. typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
  672. template <typename Handler>
  673. static bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L_, int index, Handler&& handler, record& tracking) {
  674. if constexpr (V_is_empty::value) {
  675. if (lua_isnone(L_, index)) {
  676. return true;
  677. }
  678. }
  679. tracking.use(1);
  680. handler(L_, index, type::poly, type_of(L_, index), "value does not fit any type present in the variant");
  681. return false;
  682. }
  683. template <std::size_t I, typename Handler>
  684. static bool is_one(std::integral_constant<std::size_t, I>, lua_State* L_, int index, Handler&& handler, record& tracking) {
  685. typedef std::variant_alternative_t<I - 1, V> T;
  686. record temp_tracking = tracking;
  687. if (stack::check<T>(L_, index, &no_panic, temp_tracking)) {
  688. tracking = temp_tracking;
  689. return true;
  690. }
  691. return is_one(std::integral_constant<std::size_t, I - 1>(), L_, index, std::forward<Handler>(handler), tracking);
  692. }
  693. template <typename Handler>
  694. static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
  695. return is_one(std::integral_constant<std::size_t, V_size::value>(), L_, index, std::forward<Handler>(handler), tracking);
  696. }
  697. };
  698. #endif // variant shenanigans
  699. }} // namespace sol::stack
  700. #endif // SOL_STACK_CHECK_UNQUALIFIED_HPP