mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
✨ New dedicated loose table check
This commit is contained in:
parent
3b4144c6ec
commit
b43962957f
@ -206,6 +206,8 @@ namespace sol {
|
||||
err = call_status::runtime;
|
||||
}
|
||||
~protected_function_result() {
|
||||
if (L == nullptr)
|
||||
return;
|
||||
stack::remove(L, index, popcount);
|
||||
}
|
||||
};
|
||||
|
@ -42,7 +42,8 @@ namespace sol { namespace stack { namespace stack_detail {
|
||||
return true;
|
||||
}
|
||||
stack::get_field<true, false>(L_, "table");
|
||||
if (!stack::check<table>(L_, -1)) {
|
||||
stack::record tracking{};
|
||||
if (!stack::loose_table_check(L_, -1, &no_panic, tracking)) {
|
||||
return false;
|
||||
}
|
||||
lua_getfield(L_, -1, "next");
|
||||
|
@ -37,34 +37,48 @@
|
||||
#endif // variant shenanigans
|
||||
|
||||
namespace sol { namespace stack {
|
||||
template <typename Handler>
|
||||
bool loose_table_check(lua_State* L_, int index, Handler&& handler, record& tracking) {
|
||||
tracking.use(1);
|
||||
type t = type_of(L_, index);
|
||||
if (t == type::table) {
|
||||
return true;
|
||||
}
|
||||
if (t != type::userdata) {
|
||||
handler(L_, index, type::table, t, "value is not a table or a userdata that can behave like one");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace stack_detail {
|
||||
inline bool impl_check_metatable(lua_State* L, int index, const std::string& metakey, bool poptable) {
|
||||
luaL_getmetatable(L, &metakey[0]);
|
||||
const type expectedmetatabletype = static_cast<type>(lua_type(L, -1));
|
||||
inline bool impl_check_metatable(lua_State* L_, int index, const std::string& metakey, bool poptable) {
|
||||
luaL_getmetatable(L_, &metakey[0]);
|
||||
const type expectedmetatabletype = static_cast<type>(lua_type(L_, -1));
|
||||
if (expectedmetatabletype != type::lua_nil) {
|
||||
if (lua_rawequal(L, -1, index) == 1) {
|
||||
lua_pop(L, 1 + static_cast<int>(poptable));
|
||||
if (lua_rawequal(L_, -1, index) == 1) {
|
||||
lua_pop(L_, 1 + static_cast<int>(poptable));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_pop(L_, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T, bool poptable = true>
|
||||
inline bool check_metatable(lua_State* L, int index = -2) {
|
||||
return impl_check_metatable(L, index, usertype_traits<T>::metatable(), poptable);
|
||||
inline bool check_metatable(lua_State* L_, int index = -2) {
|
||||
return impl_check_metatable(L_, index, usertype_traits<T>::metatable(), poptable);
|
||||
}
|
||||
|
||||
template <type expected, int (*check_func)(lua_State*, int)>
|
||||
struct basic_check {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
|
||||
tracking.use(1);
|
||||
bool success = check_func(L, index) == 1;
|
||||
bool success = check_func(L_, index) == 1;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, expected, type_of(L, index), "");
|
||||
handler(L_, index, expected, type_of(L_, index), "");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@ -82,21 +96,21 @@ namespace sol { namespace stack {
|
||||
template <typename T, typename>
|
||||
struct qualified_interop_checker {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) {
|
||||
return stack_detail::unqualified_interop_check<T>(L, index, index_type, std::forward<Handler>(handler), tracking);
|
||||
static bool check(lua_State* L_, int index, type index_type, Handler&& handler, record& tracking) {
|
||||
return stack_detail::unqualified_interop_check<T>(L_, index, index_type, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, type expected, typename>
|
||||
struct unqualified_checker {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
|
||||
if constexpr (std::is_same_v<T, bool>) {
|
||||
tracking.use(1);
|
||||
bool success = lua_isboolean(L, index) == 1;
|
||||
bool success = lua_isboolean(L_, index) == 1;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, expected, type_of(L, index), "");
|
||||
handler(L_, index, expected, type_of(L_, index), "");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@ -109,7 +123,7 @@ namespace sol { namespace stack {
|
||||
,
|
||||
char16_t,
|
||||
char32_t>) {
|
||||
return stack::check<std::basic_string<T>>(L, index, std::forward<Handler>(handler), tracking);
|
||||
return stack::check<std::basic_string<T>>(L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
else if constexpr (std::is_integral_v<T> || std::is_same_v<T, lua_Integer>) {
|
||||
tracking.use(1);
|
||||
@ -118,47 +132,47 @@ namespace sol { namespace stack {
|
||||
#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS_I_)
|
||||
// imprecise, sloppy conversions
|
||||
int isnum = 0;
|
||||
lua_tointegerx(L, index, &isnum);
|
||||
lua_tointegerx(L_, index, &isnum);
|
||||
const bool success = isnum != 0;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, type::number, type_of(L, index), detail::not_a_number_or_number_string_integral);
|
||||
handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string_integral);
|
||||
}
|
||||
#elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_)
|
||||
// this check is precise, do not convert
|
||||
if (lua_isinteger(L, index) == 1) {
|
||||
if (lua_isinteger(L_, index) == 1) {
|
||||
return true;
|
||||
}
|
||||
const bool success = false;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, type::number, type_of(L, index), detail::not_a_number_integral);
|
||||
handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_integral);
|
||||
}
|
||||
#else
|
||||
// Numerics are neither safe nor string-convertible
|
||||
type t = type_of(L, index);
|
||||
type t = type_of(L_, index);
|
||||
const bool success = t == type::number;
|
||||
#endif
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, type::number, type_of(L, index), detail::not_a_number);
|
||||
handler(L_, index, type::number, type_of(L_, index), detail::not_a_number);
|
||||
}
|
||||
return success;
|
||||
#else
|
||||
// Lua 5.2 and below checks
|
||||
#if SOL_IS_OFF(SOL_STRINGS_ARE_NUMBERS_I_)
|
||||
// must pre-check, because it will convert
|
||||
type t = type_of(L, index);
|
||||
type t = type_of(L_, index);
|
||||
if (t != type::number) {
|
||||
// expected type, actual type
|
||||
handler(L, index, type::number, t, detail::not_a_number);
|
||||
handler(L_, index, type::number, t, detail::not_a_number);
|
||||
return false;
|
||||
}
|
||||
#endif // Do not allow strings to be numbers
|
||||
|
||||
#if SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_)
|
||||
int isnum = 0;
|
||||
const lua_Number v = lua_tonumberx(L, index, &isnum);
|
||||
const lua_Number v = lua_tonumberx(L_, index, &isnum);
|
||||
const bool success = isnum != 0 && static_cast<lua_Number>(llround(v)) == v;
|
||||
#else
|
||||
const bool success = true;
|
||||
@ -166,11 +180,11 @@ namespace sol { namespace stack {
|
||||
if (!success) {
|
||||
// Use defines to provide a better error message!
|
||||
#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS_I_)
|
||||
handler(L, index, type::number, type_of(L, index), detail::not_a_number_or_number_string);
|
||||
handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string);
|
||||
#elif SOL_IS_ON(SOL_NUMBER_PRECISION_CHECKS_I_)
|
||||
handler(L, index, type::number, t, detail::not_a_number_or_number_string);
|
||||
handler(L_, index, type::number, t, detail::not_a_number_or_number_string);
|
||||
#else
|
||||
handler(L, index, type::number, t, detail::not_a_number);
|
||||
handler(L_, index, type::number, t, detail::not_a_number);
|
||||
#endif
|
||||
}
|
||||
return success;
|
||||
@ -179,24 +193,24 @@ namespace sol { namespace stack {
|
||||
else if constexpr (std::is_floating_point_v<T> || std::is_same_v<T, lua_Number>) {
|
||||
tracking.use(1);
|
||||
#if SOL_IS_ON(SOL_STRINGS_ARE_NUMBERS_I_)
|
||||
bool success = lua_isnumber(L, index) == 1;
|
||||
bool success = lua_isnumber(L_, index) == 1;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, type::number, type_of(L, index), detail::not_a_number_or_number_string);
|
||||
handler(L_, index, type::number, type_of(L_, index), detail::not_a_number_or_number_string);
|
||||
}
|
||||
return success;
|
||||
#else
|
||||
type t = type_of(L, index);
|
||||
type t = type_of(L_, index);
|
||||
bool success = t == type::number;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, type::number, t, detail::not_a_number);
|
||||
handler(L_, index, type::number, t, detail::not_a_number);
|
||||
}
|
||||
return success;
|
||||
#endif // Strings are Numbers
|
||||
}
|
||||
else if constexpr (meta::any_same_v<T, type, this_state, this_main_state, this_environment, variadic_args>) {
|
||||
(void)L;
|
||||
(void)L_;
|
||||
(void)index;
|
||||
(void)handler;
|
||||
tracking.use(0);
|
||||
@ -205,18 +219,18 @@ namespace sol { namespace stack {
|
||||
else if constexpr (is_unique_usertype_v<T>) {
|
||||
using element = unique_usertype_element_t<T>;
|
||||
using actual = unique_usertype_actual_t<T>;
|
||||
const type indextype = type_of(L, index);
|
||||
const type indextype = type_of(L_, index);
|
||||
tracking.use(1);
|
||||
if (indextype != type::userdata) {
|
||||
handler(L, index, type::userdata, indextype, "value is not a userdata");
|
||||
handler(L_, index, type::userdata, indextype, "value is not a userdata");
|
||||
return false;
|
||||
}
|
||||
if (lua_getmetatable(L, index) == 0) {
|
||||
if (lua_getmetatable(L_, index) == 0) {
|
||||
return true;
|
||||
}
|
||||
int metatableindex = lua_gettop(L);
|
||||
if (stack_detail::check_metatable<d::u<element>>(L, metatableindex)) {
|
||||
void* memory = lua_touserdata(L, index);
|
||||
int metatableindex = lua_gettop(L_);
|
||||
if (stack_detail::check_metatable<d::u<element>>(L_, metatableindex)) {
|
||||
void* memory = lua_touserdata(L_, index);
|
||||
memory = detail::align_usertype_unique_destructor(memory);
|
||||
detail::unique_destructor& pdx = *static_cast<detail::unique_destructor*>(memory);
|
||||
bool success = &detail::usertype_unique_alloc_destroy<element, actual> == pdx;
|
||||
@ -229,104 +243,104 @@ namespace sol { namespace stack {
|
||||
success = usertype_traits<T>::qualified_name() == name_tag;
|
||||
#endif
|
||||
if (!success) {
|
||||
handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
|
||||
handler(L_, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype");
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)");
|
||||
lua_pop(L_, 1);
|
||||
handler(L_, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)");
|
||||
return false;
|
||||
}
|
||||
else if constexpr (meta::any_same_v<T, lua_nil_t, std::nullopt_t, nullopt_t>) {
|
||||
bool success = lua_isnil(L, index);
|
||||
bool success = lua_isnil(L_, index);
|
||||
if (success) {
|
||||
tracking.use(1);
|
||||
return success;
|
||||
}
|
||||
tracking.use(0);
|
||||
success = lua_isnone(L, index);
|
||||
success = lua_isnone(L_, index);
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, expected, type_of(L, index), "");
|
||||
handler(L_, index, expected, type_of(L_, index), "");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, env_key_t>) {
|
||||
tracking.use(1);
|
||||
type t = type_of(L, index);
|
||||
type t = type_of(L_, index);
|
||||
if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) {
|
||||
return true;
|
||||
}
|
||||
handler(L, index, type::table, t, "value cannot not have a valid environment");
|
||||
handler(L_, index, type::table, t, "value cannot not have a valid environment");
|
||||
return true;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, detail::non_lua_nil_t>) {
|
||||
return !stack::unqualified_check<lua_nil_t>(L, index, std::forward<Handler>(handler), tracking);
|
||||
return !stack::unqualified_check<lua_nil_t>(L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
else if constexpr (meta::is_specialization_of_v<T, basic_lua_table>) {
|
||||
tracking.use(1);
|
||||
type t = type_of(L, index);
|
||||
type t = type_of(L_, index);
|
||||
if (t != type::table) {
|
||||
handler(L, index, type::table, t, "value is not a table");
|
||||
handler(L_, index, type::table, t, "value is not a table");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if constexpr (meta::is_specialization_of_v<T, basic_bytecode>) {
|
||||
tracking.use(1);
|
||||
type t = type_of(L, index);
|
||||
type t = type_of(L_, index);
|
||||
if (t != type::function) {
|
||||
handler(L, index, type::function, t, "value is not a function that can be dumped");
|
||||
handler(L_, index, type::function, t, "value is not a function that can be dumped");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if constexpr (meta::is_specialization_of_v<T, basic_environment>) {
|
||||
tracking.use(1);
|
||||
if (lua_getmetatable(L, index) == 0) {
|
||||
if (lua_getmetatable(L_, index) == 0) {
|
||||
return true;
|
||||
}
|
||||
type t = type_of(L, -1);
|
||||
type t = type_of(L_, -1);
|
||||
if (t == type::table || t == type::none || t == type::lua_nil) {
|
||||
lua_pop(L, 1);
|
||||
lua_pop(L_, 1);
|
||||
return true;
|
||||
}
|
||||
if (t != type::userdata) {
|
||||
lua_pop(L, 1);
|
||||
handler(L, index, type::table, t, "value does not have a valid metatable");
|
||||
lua_pop(L_, 1);
|
||||
handler(L_, index, type::table, t, "value does not have a valid metatable");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, metatable_key_t>) {
|
||||
tracking.use(1);
|
||||
if (lua_getmetatable(L, index) == 0) {
|
||||
if (lua_getmetatable(L_, index) == 0) {
|
||||
return true;
|
||||
}
|
||||
type t = type_of(L, -1);
|
||||
type t = type_of(L_, -1);
|
||||
if (t == type::table || t == type::none || t == type::lua_nil) {
|
||||
lua_pop(L, 1);
|
||||
lua_pop(L_, 1);
|
||||
return true;
|
||||
}
|
||||
if (t != type::userdata) {
|
||||
lua_pop(L, 1);
|
||||
handler(L, index, expected, t, "value does not have a valid metatable");
|
||||
lua_pop(L_, 1);
|
||||
handler(L_, index, expected, t, "value does not have a valid metatable");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, luaL_Stream*> || std::is_same_v<T, luaL_Stream>) {
|
||||
if (lua_getmetatable(L, index) == 0) {
|
||||
type t = type_of(L, index);
|
||||
handler(L, index, expected, t, "value is not a valid luaL_Stream (has no metatable/is not a valid value)");
|
||||
if (lua_getmetatable(L_, index) == 0) {
|
||||
type t = type_of(L_, index);
|
||||
handler(L_, index, expected, t, "value is not a valid luaL_Stream (has no metatable/is not a valid value)");
|
||||
return false;
|
||||
}
|
||||
luaL_getmetatable(L, LUA_FILEHANDLE);
|
||||
if (type_of(L, index) != type::table) {
|
||||
type t = type_of(L, index);
|
||||
lua_pop(L, 1);
|
||||
handler(L,
|
||||
luaL_getmetatable(L_, LUA_FILEHANDLE);
|
||||
if (type_of(L_, index) != type::table) {
|
||||
type t = type_of(L_, index);
|
||||
lua_pop(L_, 1);
|
||||
handler(L_,
|
||||
index,
|
||||
expected,
|
||||
t,
|
||||
@ -334,11 +348,11 @@ namespace sol { namespace stack {
|
||||
"my_lua_state.open_libraries(sol::lib::state) or equivalent?)");
|
||||
return false;
|
||||
}
|
||||
int is_stream_table = lua_compare(L, -1, -2, LUA_OPEQ);
|
||||
lua_pop(L, 2);
|
||||
int is_stream_table = lua_compare(L_, -1, -2, LUA_OPEQ);
|
||||
lua_pop(L_, 2);
|
||||
if (is_stream_table == 0) {
|
||||
type t = type_of(L, index);
|
||||
handler(L, index, expected, t, "value is not a valid luaL_Stream (incorrect metatable)");
|
||||
type t = type_of(L_, index);
|
||||
handler(L_, index, expected, t, "value is not a valid luaL_Stream (incorrect metatable)");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -346,7 +360,7 @@ namespace sol { namespace stack {
|
||||
else if constexpr (meta::is_optional_v<T>) {
|
||||
using ValueType = typename T::value_type;
|
||||
(void)handler;
|
||||
type t = type_of(L, index);
|
||||
type t = type_of(L_, index);
|
||||
if (t == type::none) {
|
||||
tracking.use(0);
|
||||
return true;
|
||||
@ -355,124 +369,115 @@ namespace sol { namespace stack {
|
||||
tracking.use(1);
|
||||
return true;
|
||||
}
|
||||
return stack::unqualified_check<ValueType>(L, index, &no_panic, tracking);
|
||||
return stack::unqualified_check<ValueType>(L_, index, &no_panic, tracking);
|
||||
}
|
||||
#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_)
|
||||
else if constexpr (std::is_function_v<T> || (std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t<T>>)) {
|
||||
return stack_detail::check_function_pointer<std::remove_pointer_t<T>>(L, index, std::forward<Handler>(handler), tracking);
|
||||
return stack_detail::check_function_pointer<std::remove_pointer_t<T>>(L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
#endif
|
||||
else if constexpr (expected == type::userdata) {
|
||||
if constexpr (meta::any_same_v<T, userdata_value> || meta::is_specialization_of_v<T, basic_userdata>) {
|
||||
tracking.use(1);
|
||||
type t = type_of(L, index);
|
||||
type t = type_of(L_, index);
|
||||
bool success = t == type::userdata;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, type::userdata, t, "");
|
||||
handler(L_, index, type::userdata, t, "");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
else if constexpr (meta::is_specialization_of_v<T, user>) {
|
||||
unqualified_checker<lightuserdata_value, type::userdata> c;
|
||||
(void)c;
|
||||
return c.check(L, index, std::forward<Handler>(handler), tracking);
|
||||
return c.check(L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
else {
|
||||
if constexpr (std::is_pointer_v<T>) {
|
||||
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
|
||||
return check_usertype<T>(L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
else if constexpr (meta::is_specialization_of_v<T, std::reference_wrapper>) {
|
||||
using T_internal = typename T::type;
|
||||
return stack::check<T_internal>(L, index, std::forward<Handler>(handler), tracking);
|
||||
return stack::check<T_internal>(L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
else {
|
||||
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
|
||||
return check_usertype<T>(L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (expected == type::poly) {
|
||||
tracking.use(1);
|
||||
bool success = is_lua_reference_v<T> || !lua_isnone(L, index);
|
||||
bool success = is_lua_reference_v<T> || !lua_isnone(L_, index);
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, type::poly, type_of(L, index), "");
|
||||
handler(L_, index, type::poly, type_of(L_, index), "");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
else if constexpr (expected == type::lightuserdata) {
|
||||
tracking.use(1);
|
||||
type t = type_of(L, index);
|
||||
type t = type_of(L_, index);
|
||||
bool success = t == type::userdata || t == type::lightuserdata;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, type::lightuserdata, t, "");
|
||||
handler(L_, index, type::lightuserdata, t, "");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
else if constexpr (expected == type::function) {
|
||||
if constexpr (meta::any_same_v<T, lua_CFunction, std::remove_pointer_t<lua_CFunction>, c_closure>) {
|
||||
tracking.use(1);
|
||||
bool success = lua_iscfunction(L, index) == 1;
|
||||
bool success = lua_iscfunction(L_, index) == 1;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, expected, type_of(L, index), "");
|
||||
handler(L_, index, expected, type_of(L_, index), "");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
else {
|
||||
tracking.use(1);
|
||||
type t = type_of(L, index);
|
||||
type t = type_of(L_, index);
|
||||
if (t == type::lua_nil || t == type::none || t == type::function) {
|
||||
// allow for lua_nil to be returned
|
||||
return true;
|
||||
}
|
||||
if (t != type::userdata && t != type::table) {
|
||||
handler(L, index, type::function, t, "must be a function or table or a userdata");
|
||||
handler(L_, index, type::function, t, "must be a function or table or a userdata");
|
||||
return false;
|
||||
}
|
||||
// Do advanced check for call-style userdata?
|
||||
static const auto& callkey = to_string(meta_function::call);
|
||||
if (lua_getmetatable(L, index) == 0) {
|
||||
if (lua_getmetatable(L_, index) == 0) {
|
||||
// No metatable, no __call key possible
|
||||
handler(L, index, type::function, t, "value is not a function and does not have overriden metatable");
|
||||
handler(L_, index, type::function, t, "value is not a function and does not have overriden metatable");
|
||||
return false;
|
||||
}
|
||||
if (lua_isnoneornil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
handler(L, index, type::function, t, "value is not a function and does not have valid metatable");
|
||||
if (lua_isnoneornil(L_, -1)) {
|
||||
lua_pop(L_, 1);
|
||||
handler(L_, index, type::function, t, "value is not a function and does not have valid metatable");
|
||||
return false;
|
||||
}
|
||||
lua_getfield(L, -1, &callkey[0]);
|
||||
if (lua_isnoneornil(L, -1)) {
|
||||
lua_pop(L, 2);
|
||||
handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type");
|
||||
lua_getfield(L_, -1, &callkey[0]);
|
||||
if (lua_isnoneornil(L_, -1)) {
|
||||
lua_pop(L_, 2);
|
||||
handler(L_, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type");
|
||||
return false;
|
||||
}
|
||||
// has call, is definitely a function
|
||||
lua_pop(L, 2);
|
||||
lua_pop(L_, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if constexpr (expected == type::table) {
|
||||
tracking.use(1);
|
||||
type t = type_of(L, index);
|
||||
if (t == type::table) {
|
||||
return true;
|
||||
}
|
||||
if (t != type::userdata) {
|
||||
handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return stack::loose_table_check(L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
else {
|
||||
tracking.use(1);
|
||||
const type indextype = type_of(L, index);
|
||||
const type indextype = type_of(L_, index);
|
||||
bool success = expected == indextype;
|
||||
if (!success) {
|
||||
// expected type, actual type, message
|
||||
handler(L, index, expected, indextype, "");
|
||||
handler(L_, index, expected, indextype, "");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@ -485,70 +490,70 @@ namespace sol { namespace stack {
|
||||
template <typename T>
|
||||
struct unqualified_checker<detail::as_value_tag<T>, type::userdata> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
const type indextype = type_of(L, index);
|
||||
return check(types<T>(), L, index, indextype, std::forward<Handler>(handler), tracking);
|
||||
static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
|
||||
const type indextype = type_of(L_, index);
|
||||
return check(types<T>(), L_, index, indextype, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <typename U, typename Handler>
|
||||
static bool check(types<U>, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
|
||||
static bool check(types<U>, lua_State* L_, int index, type indextype, Handler&& handler, record& tracking) {
|
||||
if constexpr (
|
||||
std::is_same_v<T,
|
||||
lightuserdata_value> || std::is_same_v<T, userdata_value> || std::is_same_v<T, userdata> || std::is_same_v<T, lightuserdata>) {
|
||||
tracking.use(1);
|
||||
if (indextype != type::userdata) {
|
||||
handler(L, index, type::userdata, indextype, "value is not a valid userdata");
|
||||
handler(L_, index, type::userdata, indextype, "value is not a valid userdata");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
#if SOL_IS_ON(SOL_USE_INTEROP_I_)
|
||||
if (stack_detail::interop_check<U>(L, index, indextype, handler, tracking)) {
|
||||
if (stack_detail::interop_check<U>(L_, index, indextype, handler, tracking)) {
|
||||
return true;
|
||||
}
|
||||
#endif // interop extensibility
|
||||
tracking.use(1);
|
||||
#if SOL_IS_ON(SOL_GET_FUNCTION_POINTER_UNSAFE_I_)
|
||||
if (lua_iscfunction(L, index) != 0) {
|
||||
if (lua_iscfunction(L_, index) != 0) {
|
||||
// a potential match...
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (indextype != type::userdata) {
|
||||
handler(L, index, type::userdata, indextype, "value is not a valid userdata");
|
||||
handler(L_, index, type::userdata, indextype, "value is not a valid userdata");
|
||||
return false;
|
||||
}
|
||||
if (lua_getmetatable(L, index) == 0) {
|
||||
if (lua_getmetatable(L_, index) == 0) {
|
||||
return true;
|
||||
}
|
||||
int metatableindex = lua_gettop(L);
|
||||
if (stack_detail::check_metatable<U>(L, metatableindex))
|
||||
int metatableindex = lua_gettop(L_);
|
||||
if (stack_detail::check_metatable<U>(L_, metatableindex))
|
||||
return true;
|
||||
if (stack_detail::check_metatable<U*>(L, metatableindex))
|
||||
if (stack_detail::check_metatable<U*>(L_, metatableindex))
|
||||
return true;
|
||||
if (stack_detail::check_metatable<d::u<U>>(L, metatableindex))
|
||||
if (stack_detail::check_metatable<d::u<U>>(L_, metatableindex))
|
||||
return true;
|
||||
if (stack_detail::check_metatable<as_container_t<U>>(L, metatableindex))
|
||||
if (stack_detail::check_metatable<as_container_t<U>>(L_, metatableindex))
|
||||
return true;
|
||||
bool success = false;
|
||||
bool has_derived = derive<T>::value || weak_derive<T>::value;
|
||||
if (has_derived) {
|
||||
#if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)
|
||||
luaL_checkstack(L, 1, detail::not_enough_stack_space_string);
|
||||
luaL_checkstack(L_, 1, detail::not_enough_stack_space_string);
|
||||
#endif // make sure stack doesn't overflow
|
||||
auto pn = stack::pop_n(L, 1);
|
||||
lua_pushstring(L, &detail::base_class_check_key()[0]);
|
||||
lua_rawget(L, metatableindex);
|
||||
if (type_of(L, -1) != type::lua_nil) {
|
||||
void* basecastdata = lua_touserdata(L, -1);
|
||||
auto pn = stack::pop_n(L_, 1);
|
||||
lua_pushstring(L_, &detail::base_class_check_key()[0]);
|
||||
lua_rawget(L_, metatableindex);
|
||||
if (type_of(L_, -1) != type::lua_nil) {
|
||||
void* basecastdata = lua_touserdata(L_, -1);
|
||||
detail::inheritance_check_function ic = reinterpret_cast<detail::inheritance_check_function>(basecastdata);
|
||||
success = ic(usertype_traits<T>::qualified_name());
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
lua_pop(L_, 1);
|
||||
if (!success) {
|
||||
handler(L, index, type::userdata, indextype, "value at this index does not properly reflect the desired type");
|
||||
handler(L_, index, type::userdata, indextype, "value at this index does not properly reflect the desired type");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -559,34 +564,34 @@ namespace sol { namespace stack {
|
||||
template <typename T>
|
||||
struct unqualified_checker<detail::as_pointer_tag<T>, type::userdata> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
|
||||
static bool check(lua_State* L_, int index, type indextype, Handler&& handler, record& tracking) {
|
||||
if (indextype == type::lua_nil) {
|
||||
tracking.use(1);
|
||||
return true;
|
||||
}
|
||||
return check_usertype<std::remove_pointer_t<T>>(L, index, std::forward<Handler>(handler), tracking);
|
||||
return check_usertype<std::remove_pointer_t<T>>(L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
const type indextype = type_of(L, index);
|
||||
return check(L, index, indextype, std::forward<Handler>(handler), tracking);
|
||||
static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
|
||||
const type indextype = type_of(L_, index);
|
||||
return check(L_, index, indextype, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
struct unqualified_checker<std::tuple<Args...>, type::poly> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return stack::multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking);
|
||||
static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
|
||||
return stack::multi_check<Args...>(L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
struct unqualified_checker<std::pair<A, B>, type::poly> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return stack::multi_check<A, B>(L, index, std::forward<Handler>(handler), tracking);
|
||||
static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
|
||||
return stack::multi_check<A, B>(L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
@ -599,31 +604,31 @@ namespace sol { namespace stack {
|
||||
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
|
||||
|
||||
template <typename Handler>
|
||||
static bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
static bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L_, int index, Handler&& handler, record& tracking) {
|
||||
if constexpr (V_is_empty::value) {
|
||||
if (lua_isnone(L, index)) {
|
||||
if (lua_isnone(L_, index)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
tracking.use(1);
|
||||
handler(L, index, type::poly, type_of(L, index), "value does not fit any type present in the variant");
|
||||
handler(L_, index, type::poly, type_of(L_, index), "value does not fit any type present in the variant");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <std::size_t I, typename Handler>
|
||||
static bool is_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
static bool is_one(std::integral_constant<std::size_t, I>, lua_State* L_, int index, Handler&& handler, record& tracking) {
|
||||
typedef std::variant_alternative_t<I - 1, V> T;
|
||||
record temp_tracking = tracking;
|
||||
if (stack::check<T>(L, index, &no_panic, temp_tracking)) {
|
||||
if (stack::check<T>(L_, index, &no_panic, temp_tracking)) {
|
||||
tracking = temp_tracking;
|
||||
return true;
|
||||
}
|
||||
return is_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking);
|
||||
return is_one(std::integral_constant<std::size_t, I - 1>(), L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return is_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking);
|
||||
static bool check(lua_State* L_, int index, Handler&& handler, record& tracking) {
|
||||
return is_one(std::integral_constant<std::size_t, V_size::value>(), L_, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
#include <sol/sol.hpp>
|
||||
|
||||
unsigned int regression_1211() {
|
||||
sol::protected_function_result let_die;
|
||||
(void)let_die;
|
||||
return 0;
|
||||
}
|
@ -11,9 +11,18 @@ extern unsigned int regression_1095();
|
||||
extern unsigned int regression_1096();
|
||||
extern unsigned int regression_1149();
|
||||
extern unsigned int regression_1192();
|
||||
extern unsigned int regression_1211();
|
||||
|
||||
static f_ptr* const regression_tests_regressions[]
|
||||
= { ®ression_1008, ®ression_1000, ®ression_1067, ®ression_1072, ®ression_1087, ®ression_1095, ®ression_1096, ®ression_1149, ®ression_1192 };
|
||||
static f_ptr* const regression_tests_regressions[] = { ®ression_1008,
|
||||
®ression_1000,
|
||||
®ression_1067,
|
||||
®ression_1072,
|
||||
®ression_1087,
|
||||
®ression_1095,
|
||||
®ression_1096,
|
||||
®ression_1149,
|
||||
®ression_1192,
|
||||
®ression_1211 };
|
||||
static const int regression_tests_sizeof_regressions = sizeof(regression_tests_regressions) / sizeof(regression_tests_regressions[0]);
|
||||
|
||||
int trampoline(f_ptr* f) {
|
||||
|
@ -547,3 +547,59 @@ TEST_CASE("containers/pointer types", "check that containers with unique usertyp
|
||||
int val2 = b2->get();
|
||||
REQUIRE(val2 == 500);
|
||||
}
|
||||
|
||||
TEST_CASE("containers/keep alive", "containers are kept alive even if they are returned as a temporary") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::table);
|
||||
|
||||
#define PATTERN() 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
lua["get_collection"] = []() {
|
||||
return std::vector<int>({ PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN(),
|
||||
PATTERN() });
|
||||
};
|
||||
#undef PATTERN
|
||||
|
||||
sol::optional<sol::error> maybe_error = lua.safe_script(R"lua(
|
||||
print("LET'S GET IT BAYBEEE!")
|
||||
for i, v in pairs(get_collection()) do
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
local index = i - 1
|
||||
print(i, index, (index % 10), v)
|
||||
assert((index % 10) == v)
|
||||
end
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
print("YEEEAH!")
|
||||
)lua");
|
||||
REQUIRE_FALSE(maybe_error.has_value());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user