1 // sol2 2 3 // The MIT License (MIT) 4 5 // Copyright (c) 2013-2018 Rapptz, ThePhD and contributors 6 7 // Permission is hereby granted, free of charge, to any person obtaining a copy of 8 // this software and associated documentation files (the "Software"), to deal in 9 // the Software without restriction, including without limitation the rights to 10 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 // the Software, and to permit persons to whom the Software is furnished to do so, 12 // subject to the following conditions: 13 14 // The above copyright notice and this permission notice shall be included in all 15 // copies or substantial portions of the Software. 16 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 #ifndef SOL_STACK_CHECK_UNQUALIFIED_HPP 25 #define SOL_STACK_CHECK_UNQUALIFIED_HPP 26 27 #include "stack_core.hpp" 28 #include "usertype_traits.hpp" 29 #include "inheritance.hpp" 30 #include <memory> 31 #include <functional> 32 #include <utility> 33 #include <cmath> 34 #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES 35 #include <optional> 36 #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT 37 #include <variant> 38 #endif // SOL_STD_VARIANT 39 #endif // SOL_CXX17_FEATURES 40 41 namespace sol { 42 namespace stack { 43 namespace stack_detail { 44 template <typename T, bool poptable = true> check_metatable(lua_State * L,int index=-2)45 inline bool check_metatable(lua_State* L, int index = -2) { 46 const auto& metakey = usertype_traits<T>::metatable(); 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 59 template <type expected, int (*check_func)(lua_State*, int)> 60 struct basic_check { 61 template <typename Handler> checksol::stack::stack_detail::basic_check62 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 63 tracking.use(1); 64 bool success = check_func(L, index) == 1; 65 if (!success) { 66 // expected type, actual type 67 handler(L, index, expected, type_of(L, index), ""); 68 } 69 return success; 70 } 71 }; 72 } // namespace stack_detail 73 74 template <typename T, typename> 75 struct userdata_checker { 76 template <typename Handler> checksol::stack::userdata_checker77 static bool check(lua_State*, int, type, Handler&&, record&) { 78 return false; 79 } 80 }; 81 82 template <typename T, type expected, typename> 83 struct checker { 84 template <typename Handler> checksol::stack::checker85 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 86 tracking.use(1); 87 const type indextype = type_of(L, index); 88 bool success = expected == indextype; 89 if (!success) { 90 // expected type, actual type, message 91 handler(L, index, expected, indextype, ""); 92 } 93 return success; 94 } 95 }; 96 97 template <typename T, type expected, typename C> 98 struct qualified_checker : checker<meta::unqualified_t<T>, lua_type_of<meta::unqualified_t<T>>::value, C> {}; 99 100 template <typename T> 101 struct checker<T, type::number, std::enable_if_t<std::is_integral<T>::value>> { 102 template <typename Handler> checksol::stack::checker103 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 104 tracking.use(1); 105 #if SOL_LUA_VERSION >= 503 106 #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS 107 int isnum = 0; 108 lua_tointegerx(L, index, &isnum); 109 const bool success = isnum != 0; 110 if (!success) { 111 // expected type, actual type 112 handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); 113 } 114 #elif (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) 115 // this check is precise, does not convert 116 if (lua_isinteger(L, index) == 1) { 117 return true; 118 } 119 const bool success = false; 120 if (!success) { 121 // expected type, actual type 122 handler(L, index, type::number, type_of(L, index), "not a numeric (integral) type"); 123 } 124 #else 125 type t = type_of(L, index); 126 const bool success = t == type::number; 127 #endif // If numbers are enabled, use the imprecise check 128 if (!success) { 129 // expected type, actual type 130 handler(L, index, type::number, type_of(L, index), "not a numeric type"); 131 } 132 return success; 133 #else 134 #if !defined(SOL_STRINGS_ARE_NUMBERS) || !SOL_STRINGS_ARE_NUMBERS 135 // must pre-check, because it will convert 136 type t = type_of(L, index); 137 if (t != type::number) { 138 // expected type, actual type 139 handler(L, index, type::number, t, "not a numeric type"); 140 return false; 141 } 142 #endif // Do not allow strings to be numbers 143 #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) 144 int isnum = 0; 145 const lua_Number v = lua_tonumberx(L, index, &isnum); 146 const bool success = isnum != 0 && static_cast<lua_Number>(llround(v)) == v; 147 #else 148 const bool success = true; 149 #endif // Safe numerics and number precision checking 150 if (!success) { 151 // expected type, actual type 152 #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS 153 handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); 154 #else 155 handler(L, index, type::number, t, "not a numeric type"); 156 #endif 157 } 158 return success; 159 #endif // Lua Version 5.3 versus others 160 } 161 }; 162 163 template <typename T> 164 struct checker<T, type::number, std::enable_if_t<std::is_floating_point<T>::value>> { 165 template <typename Handler> checksol::stack::checker166 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 167 tracking.use(1); 168 #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS 169 bool success = lua_isnumber(L, index) == 1; 170 if (!success) { 171 // expected type, actual type 172 handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); 173 } 174 return success; 175 #else 176 type t = type_of(L, index); 177 bool success = t == type::number; 178 if (!success) { 179 // expected type, actual type 180 handler(L, index, type::number, t, "not a numeric type"); 181 } 182 return success; 183 #endif // Strings are Numbers 184 } 185 }; 186 187 template <type expected, typename C> 188 struct checker<lua_nil_t, expected, C> { 189 template <typename Handler> checksol::stack::checker190 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 191 bool success = lua_isnil(L, index); 192 if (success) { 193 tracking.use(1); 194 return success; 195 } 196 tracking.use(0); 197 success = lua_isnone(L, index); 198 if (!success) { 199 // expected type, actual type 200 handler(L, index, expected, type_of(L, index), ""); 201 } 202 return success; 203 } 204 }; 205 206 template <typename C> 207 struct checker<detail::non_lua_nil_t, type::poly, C> { 208 template <typename Handler> checksol::stack::checker209 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 210 return !stack::unqualified_check<lua_nil_t>(L, index, std::forward<Handler>(handler), tracking); 211 } 212 }; 213 214 template <type expected, typename C> 215 struct checker<nullopt_t, expected, C> : checker<lua_nil_t> {}; 216 217 template <typename C> 218 struct checker<this_state, type::poly, C> { 219 template <typename Handler> checksol::stack::checker220 static bool check(lua_State*, int, Handler&&, record& tracking) { 221 tracking.use(0); 222 return true; 223 } 224 }; 225 226 template <typename C> 227 struct checker<this_main_state, type::poly, C> { 228 template <typename Handler> checksol::stack::checker229 static bool check(lua_State*, int, Handler&&, record& tracking) { 230 tracking.use(0); 231 return true; 232 } 233 }; 234 235 template <typename C> 236 struct checker<this_environment, type::poly, C> { 237 template <typename Handler> checksol::stack::checker238 static bool check(lua_State*, int, Handler&&, record& tracking) { 239 tracking.use(0); 240 return true; 241 } 242 }; 243 244 template <typename C> 245 struct checker<variadic_args, type::poly, C> { 246 template <typename Handler> checksol::stack::checker247 static bool check(lua_State*, int, Handler&&, record& tracking) { 248 tracking.use(0); 249 return true; 250 } 251 }; 252 253 template <typename C> 254 struct checker<type, type::poly, C> { 255 template <typename Handler> checksol::stack::checker256 static bool check(lua_State*, int, Handler&&, record& tracking) { 257 tracking.use(0); 258 return true; 259 } 260 }; 261 262 template <typename T, typename C> 263 struct checker<T, type::poly, C> { 264 template <typename Handler> checksol::stack::checker265 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 266 tracking.use(1); 267 bool success = is_lua_reference<T>::value || !lua_isnone(L, index); 268 if (!success) { 269 // expected type, actual type 270 handler(L, index, type::poly, type_of(L, index), ""); 271 } 272 return success; 273 } 274 }; 275 276 template <typename T, typename C> 277 struct checker<T, type::lightuserdata, C> { 278 template <typename Handler> checksol::stack::checker279 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 280 tracking.use(1); 281 type t = type_of(L, index); 282 bool success = t == type::userdata || t == type::lightuserdata; 283 if (!success) { 284 // expected type, actual type 285 handler(L, index, type::lightuserdata, t, ""); 286 } 287 return success; 288 } 289 }; 290 291 template <typename C> 292 struct checker<userdata_value, type::userdata, C> { 293 template <typename Handler> checksol::stack::checker294 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 295 tracking.use(1); 296 type t = type_of(L, index); 297 bool success = t == type::userdata; 298 if (!success) { 299 // expected type, actual type 300 handler(L, index, type::userdata, t, ""); 301 } 302 return success; 303 } 304 }; 305 306 template <typename B, typename C> 307 struct checker<basic_userdata<B>, type::userdata, C> { 308 template <typename Handler> checksol::stack::checker309 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 310 return stack::check<userdata_value>(L, index, std::forward<Handler>(handler), tracking); 311 } 312 }; 313 314 template <typename T, typename C> 315 struct checker<user<T>, type::userdata, C> : checker<user<T>, type::lightuserdata, C> {}; 316 317 template <typename T, typename C> 318 struct checker<non_null<T>, type::userdata, C> : checker<T, lua_type_of<T>::value, C> {}; 319 320 template <typename C> 321 struct checker<lua_CFunction, type::function, C> : stack_detail::basic_check<type::function, lua_iscfunction> {}; 322 template <typename C> 323 struct checker<std::remove_pointer_t<lua_CFunction>, type::function, C> : checker<lua_CFunction, type::function, C> {}; 324 template <typename C> 325 struct checker<c_closure, type::function, C> : checker<lua_CFunction, type::function, C> {}; 326 327 template <typename T, typename C> 328 struct checker<T, type::function, C> { 329 template <typename Handler> checksol::stack::checker330 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 331 tracking.use(1); 332 type t = type_of(L, index); 333 if (t == type::lua_nil || t == type::none || t == type::function) { 334 // allow for lua_nil to be returned 335 return true; 336 } 337 if (t != type::userdata && t != type::table) { 338 handler(L, index, type::function, t, "must be a function or table or a userdata"); 339 return false; 340 } 341 // Do advanced check for call-style userdata? 342 static const auto& callkey = to_string(meta_function::call); 343 if (lua_getmetatable(L, index) == 0) { 344 // No metatable, no __call key possible 345 handler(L, index, type::function, t, "value is not a function and does not have overriden metatable"); 346 return false; 347 } 348 if (lua_isnoneornil(L, -1)) { 349 lua_pop(L, 1); 350 handler(L, index, type::function, t, "value is not a function and does not have valid metatable"); 351 return false; 352 } 353 lua_getfield(L, -1, &callkey[0]); 354 if (lua_isnoneornil(L, -1)) { 355 lua_pop(L, 2); 356 handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type"); 357 return false; 358 } 359 // has call, is definitely a function 360 lua_pop(L, 2); 361 return true; 362 } 363 }; 364 365 template <typename T, typename C> 366 struct checker<T, type::table, C> { 367 template <typename Handler> checksol::stack::checker368 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 369 tracking.use(1); 370 type t = type_of(L, index); 371 if (t == type::table) { 372 return true; 373 } 374 if (t != type::userdata) { 375 handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one"); 376 return false; 377 } 378 return true; 379 } 380 }; 381 382 template <type expected, typename C> 383 struct checker<metatable_t, expected, C> { 384 template <typename Handler> checksol::stack::checker385 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 386 tracking.use(1); 387 if (lua_getmetatable(L, index) == 0) { 388 return true; 389 } 390 type t = type_of(L, -1); 391 if (t == type::table || t == type::none || t == type::lua_nil) { 392 lua_pop(L, 1); 393 return true; 394 } 395 if (t != type::userdata) { 396 lua_pop(L, 1); 397 handler(L, index, expected, t, "value does not have a valid metatable"); 398 return false; 399 } 400 return true; 401 } 402 }; 403 404 template <typename C> 405 struct checker<env_t, type::poly, C> { 406 template <typename Handler> checksol::stack::checker407 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 408 tracking.use(1); 409 type t = type_of(L, index); 410 if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) { 411 return true; 412 } 413 handler(L, index, type::table, t, "value cannot not have a valid environment"); 414 return true; 415 } 416 }; 417 418 template <typename E, typename C> 419 struct checker<basic_environment<E>, type::poly, C> { 420 template <typename Handler> checksol::stack::checker421 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 422 tracking.use(1); 423 if (lua_getmetatable(L, index) == 0) { 424 return true; 425 } 426 type t = type_of(L, -1); 427 if (t == type::table || t == type::none || t == type::lua_nil) { 428 lua_pop(L, 1); 429 return true; 430 } 431 if (t != type::userdata) { 432 lua_pop(L, 1); 433 handler(L, index, type::table, t, "value does not have a valid metatable"); 434 return false; 435 } 436 return true; 437 } 438 }; 439 440 template <typename T, typename C> 441 struct checker<detail::as_value_tag<T>, type::userdata, C> { 442 template <typename Handler> checksol::stack::checker443 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 444 const type indextype = type_of(L, index); 445 return check(types<T>(), L, index, indextype, handler, tracking); 446 } 447 448 template <typename U, typename Handler> checksol::stack::checker449 static bool check(types<U>, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { 450 #if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP 451 userdata_checker<extensible<T>> uc; 452 (void)uc; 453 if (uc.check(L, index, indextype, handler, tracking)) { 454 return true; 455 } 456 #endif // interop extensibility 457 tracking.use(1); 458 if (indextype != type::userdata) { 459 handler(L, index, type::userdata, indextype, "value is not a valid userdata"); 460 return false; 461 } 462 if (meta::any<std::is_same<T, lightuserdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value) 463 return true; 464 if (lua_getmetatable(L, index) == 0) { 465 return true; 466 } 467 int metatableindex = lua_gettop(L); 468 if (stack_detail::check_metatable<U>(L, metatableindex)) 469 return true; 470 if (stack_detail::check_metatable<U*>(L, metatableindex)) 471 return true; 472 if (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex)) 473 return true; 474 if (stack_detail::check_metatable<as_container_t<U>>(L, metatableindex)) 475 return true; 476 bool success = false; 477 if (detail::has_derived<T>::value) { 478 auto pn = stack::pop_n(L, 1); 479 lua_pushstring(L, &detail::base_class_check_key()[0]); 480 lua_rawget(L, metatableindex); 481 if (type_of(L, -1) != type::lua_nil) { 482 void* basecastdata = lua_touserdata(L, -1); 483 detail::inheritance_check_function ic = reinterpret_cast<detail::inheritance_check_function>(basecastdata); 484 success = ic(usertype_traits<T>::qualified_name()); 485 } 486 } 487 if (!success) { 488 lua_pop(L, 1); 489 handler(L, index, type::userdata, indextype, "value at this index does not properly reflect the desired type"); 490 return false; 491 } 492 lua_pop(L, 1); 493 return true; 494 } 495 }; 496 497 template <typename T, typename C> 498 struct checker<detail::as_pointer_tag<T>, type::userdata, C> { 499 template <typename Handler> checksol::stack::checker500 static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { 501 if (indextype == type::lua_nil) { 502 tracking.use(1); 503 return true; 504 } 505 return stack_detail::check_usertype<T>(std::false_type(), L, index, indextype, std::forward<Handler>(handler), tracking); 506 } 507 508 template <typename Handler> checksol::stack::checker509 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 510 const type indextype = type_of(L, index); 511 return check(L, index, handler, indextype, tracking); 512 } 513 }; 514 515 template <typename T, typename C> 516 struct checker<T, type::userdata, C> { 517 template <typename Handler> checksol::stack::checker518 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 519 return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking); 520 } 521 }; 522 523 template <typename T, typename C> 524 struct checker<T*, type::userdata, C> { 525 template <typename Handler> checksol::stack::checker526 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 527 return check_usertype<T*>(L, index, std::forward<Handler>(handler), tracking); 528 } 529 }; 530 531 template <typename X> 532 struct checker<X, type::userdata, std::enable_if_t<is_unique_usertype<X>::value>> { 533 typedef typename unique_usertype_traits<X>::type T; 534 template <typename Handler> checksol::stack::checker535 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 536 const type indextype = type_of(L, index); 537 tracking.use(1); 538 if (indextype != type::userdata) { 539 handler(L, index, type::userdata, indextype, "value is not a userdata"); 540 return false; 541 } 542 if (lua_getmetatable(L, index) == 0) { 543 return true; 544 } 545 int metatableindex = lua_gettop(L); 546 if (stack_detail::check_metatable<detail::unique_usertype<T>>(L, metatableindex)) { 547 void* memory = lua_touserdata(L, index); 548 memory = detail::align_usertype_unique_destructor(memory); 549 detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory); 550 bool success = &detail::usertype_unique_alloc_destroy<T, X> == pdx; 551 if (!success) { 552 memory = detail::align_usertype_unique_tag<true>(memory); 553 #if 0 554 // New version 555 #else 556 const char*& name_tag = *static_cast<const char**>(memory); 557 success = usertype_traits<X>::qualified_name() == name_tag; 558 #endif 559 if (!success) { 560 handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); 561 } 562 } 563 return success; 564 } 565 lua_pop(L, 1); 566 handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)"); 567 return false; 568 } 569 }; 570 571 template <typename T, typename C> 572 struct checker<std::reference_wrapper<T>, type::userdata, C> { 573 template <typename Handler> checksol::stack::checker574 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 575 return stack::check<T>(L, index, std::forward<Handler>(handler), tracking); 576 } 577 }; 578 579 template <typename... Args, typename C> 580 struct checker<std::tuple<Args...>, type::poly, C> { 581 template <typename Handler> checksol::stack::checker582 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 583 return stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking); 584 } 585 }; 586 587 template <typename A, typename B, typename C> 588 struct checker<std::pair<A, B>, type::poly, C> { 589 template <typename Handler> checksol::stack::checker590 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 591 return stack::multi_check<A, B>(L, index, std::forward<Handler>(handler), tracking); 592 } 593 }; 594 595 template <typename T, typename C> 596 struct checker<optional<T>, type::poly, C> { 597 template <typename Handler> checksol::stack::checker598 static bool check(lua_State* L, int index, Handler&&, record& tracking) { 599 type t = type_of(L, index); 600 if (t == type::none) { 601 tracking.use(0); 602 return true; 603 } 604 if (t == type::lua_nil) { 605 tracking.use(1); 606 return true; 607 } 608 return stack::check<T>(L, index, no_panic, tracking); 609 } 610 }; 611 612 #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES 613 614 template <typename T, typename C> 615 struct checker<std::optional<T>, type::poly, C> { 616 template <typename Handler> checksol::stack::checker617 static bool check(lua_State* L, int index, Handler&&, record& tracking) { 618 type t = type_of(L, index); 619 if (t == type::none) { 620 tracking.use(0); 621 return true; 622 } 623 if (t == type::lua_nil) { 624 tracking.use(1); 625 return true; 626 } 627 return stack::check<T>(L, index, no_panic, tracking); 628 } 629 }; 630 631 #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT 632 633 template <typename... Tn, typename C> 634 struct checker<std::variant<Tn...>, type::poly, C> { 635 typedef std::variant<Tn...> V; 636 typedef std::variant_size<V> V_size; 637 typedef std::integral_constant<bool, V_size::value == 0> V_is_empty; 638 639 template <typename Handler> is_onesol::stack::checker640 static bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) { 641 if (V_is_empty::value && lua_isnone(L, index)) { 642 return true; 643 } 644 tracking.use(1); 645 handler(L, index, type::poly, type_of(L, index), "value does not fit any type present in the variant"); 646 return false; 647 } 648 649 template <std::size_t I, typename Handler> is_onesol::stack::checker650 static bool is_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) { 651 typedef std::variant_alternative_t<I - 1, V> T; 652 record temp_tracking = tracking; 653 if (stack::check<T>(L, index, no_panic, temp_tracking)) { 654 tracking = temp_tracking; 655 return true; 656 } 657 return is_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking); 658 } 659 660 template <typename Handler> checksol::stack::checker661 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { 662 return is_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking); 663 } 664 }; 665 666 #endif // SOL_STD_VARIANT 667 668 #endif // SOL_CXX17_FEATURES 669 } 670 } // namespace sol::stack 671 672 #endif // SOL_STACK_CHECK_UNQUALIFIED_HPP 673