From dc2493e7525bb7633f697ef10f72b72b46222249 Mon Sep 17 00:00:00 2001 From: Andy Belle-Isle Date: Fri, 30 Aug 2019 00:45:36 -0400 Subject: Forget what I said, I just need to change git attributes to mark for vendor --- lib/sol2/include/sol/stack_check_unqualified.hpp | 606 +++++++++++++++++++++++ 1 file changed, 606 insertions(+) create mode 100644 lib/sol2/include/sol/stack_check_unqualified.hpp (limited to 'lib/sol2/include/sol/stack_check_unqualified.hpp') diff --git a/lib/sol2/include/sol/stack_check_unqualified.hpp b/lib/sol2/include/sol/stack_check_unqualified.hpp new file mode 100644 index 0000000..025961c --- /dev/null +++ b/lib/sol2/include/sol/stack_check_unqualified.hpp @@ -0,0 +1,606 @@ +// sol3 + +// The MIT License (MIT) + +// Copyright (c) 2013-2019 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef SOL_STACK_CHECK_UNQUALIFIED_HPP +#define SOL_STACK_CHECK_UNQUALIFIED_HPP + +#include "stack_core.hpp" +#include "usertype_traits.hpp" +#include "inheritance.hpp" +#include +#include +#include +#include +#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES +#include +#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT +#include +#endif // SOL_STD_VARIANT +#endif // SOL_CXX17_FEATURES + +namespace sol { namespace stack { + namespace stack_detail { + template + inline bool check_metatable(lua_State* L, int index = -2) { + const auto& metakey = usertype_traits::metatable(); + luaL_getmetatable(L, &metakey[0]); + const type expectedmetatabletype = static_cast(lua_type(L, -1)); + if (expectedmetatabletype != type::lua_nil) { + if (lua_rawequal(L, -1, index) == 1) { + lua_pop(L, 1 + static_cast(poptable)); + return true; + } + } + lua_pop(L, 1); + return false; + } + + template + struct basic_check { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + tracking.use(1); + bool success = check_func(L, index) == 1; + if (!success) { + // expected type, actual type + handler(L, index, expected, type_of(L, index), ""); + } + return success; + } + }; + } // namespace stack_detail + + template + struct unqualified_interop_checker { + template + static bool check(lua_State*, int, type, Handler&&, record&) { + return false; + } + }; + + template + struct qualified_interop_checker { + template + static bool check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) { + return stack_detail::unqualified_interop_check(L, index, index_type, std::forward(handler), tracking); + } + }; + + template + struct unqualified_checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + if constexpr (std::is_same_v) { + tracking.use(1); + bool success = lua_isboolean(L, index) == 1; + if (!success) { + // expected type, actual type + handler(L, index, expected, type_of(L, index), ""); + } + return success; + } + else if constexpr (meta::any_same_v) { + return stack::check>(L, index, std::forward(handler), tracking); + } + else if constexpr (std::is_integral_v || std::is_same_v) { + tracking.use(1); +#if SOL_LUA_VERSION >= 503 +#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS + int isnum = 0; + 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); + } +#elif (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) + // this check is precise, does not convert + 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); + } +#else + type t = type_of(L, index); + const bool success = t == type::number; +#endif // If numbers are enabled, use the imprecise check + if (!success) { + // expected type, actual type + handler(L, index, type::number, type_of(L, index), detail::not_a_number); + } + return success; +#else +#if !defined(SOL_STRINGS_ARE_NUMBERS) || !SOL_STRINGS_ARE_NUMBERS + // must pre-check, because it will convert + type t = type_of(L, index); + if (t != type::number) { + // expected type, actual type + handler(L, index, type::number, t, detail::not_a_number); + return false; + } +#endif // Do not allow strings to be numbers +#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) + int isnum = 0; + const lua_Number v = lua_tonumberx(L, index, &isnum); + const bool success = isnum != 0 && static_cast(llround(v)) == v; +#else + const bool success = true; +#endif // Safe numerics and number precision checking + if (!success) { + // expected type, actual type +#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS + handler(L, index, type::number, type_of(L, index), detail::not_a_number_or_number_string); +#elif (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) + handler(L, index, type::number, t, detail::not_a_number_or_number_string); +#else + handler(L, index, type::number, t, detail::not_a_number); +#endif + } + return success; +#endif // Lua Version 5.3 versus others + } + else if constexpr (std::is_floating_point_v || std::is_same_v) { + tracking.use(1); +#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS + 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); + } + return success; +#else + 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); + } + return success; +#endif // Strings are Numbers + } + else if constexpr(meta::any_same_v) { + (void)L; + (void)index; + (void)handler; + tracking.use(0); + return true; + } + else if constexpr (is_unique_usertype_v) { + using proper_T = typename unique_usertype_traits::type; + 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"); + return false; + } + if (lua_getmetatable(L, index) == 0) { + return true; + } + int metatableindex = lua_gettop(L); + if (stack_detail::check_metatable>(L, metatableindex)) { + void* memory = lua_touserdata(L, index); + memory = detail::align_usertype_unique_destructor(memory); + detail::unique_destructor& pdx = *static_cast(memory); + bool success = &detail::usertype_unique_alloc_destroy == pdx; + if (!success) { + memory = detail::align_usertype_unique_tag(memory); +#if 0 + // New version +#else + const char*& name_tag = *static_cast(memory); + success = usertype_traits::qualified_name() == name_tag; +#endif + if (!success) { + 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?)"); + return false; + } + else if constexpr (meta::any_same_v) { + bool success = lua_isnil(L, index); + if (success) { + tracking.use(1); + return success; + } + tracking.use(0); + success = lua_isnone(L, index); + if (!success) { + // expected type, actual type + handler(L, index, expected, type_of(L, index), ""); + } + return success; + } + else if constexpr (std::is_same_v) { + tracking.use(1); + 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"); + return true; + } + else if constexpr (std::is_same_v) { + return !stack::unqualified_check(L, index, std::forward(handler), tracking); + } + else if constexpr (meta::is_specialization_of_v) { + tracking.use(1); + type t = type_of(L, index); + if (t != type::table) { + handler(L, index, type::table, t, "value is not a table"); + return false; + } + return true; + } + else if constexpr (meta::is_specialization_of_v) { + tracking.use(1); + 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"); + return false; + } + return true; + } + else if constexpr(meta::is_specialization_of_v) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::lua_nil) { + 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"); + return false; + } + return true; + } + else if constexpr (std::is_same_v) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::lua_nil) { + 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"); + return false; + } + return true; + } + else if constexpr (expected == type::userdata) { + if constexpr (meta::any_same_v || meta::is_specialization_of_v) { + tracking.use(1); + type t = type_of(L, index); + bool success = t == type::userdata; + if (!success) { + // expected type, actual type + handler(L, index, type::userdata, t, ""); + } + return success; + } + else if constexpr (meta::is_specialization_of_v) { + unqualified_checker c; + (void)c; + return c.check(L, index, std::forward(handler), tracking); + } + else { + if constexpr (std::is_pointer_v) { + return check_usertype(L, index, std::forward(handler), tracking); + } + else if constexpr (meta::is_specialization_of_v) { + using T_internal = typename T::type; + return stack::check(L, index, std::forward(handler), tracking); + } + else { + return check_usertype(L, index, std::forward(handler), tracking); + } + } + } + else if constexpr (expected == type::poly) { + tracking.use(1); + bool success = is_lua_reference_v || !lua_isnone(L, index); + if (!success) { + // expected type, actual type + 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); + bool success = t == type::userdata || t == type::lightuserdata; + if (!success) { + // expected type, actual type + handler(L, index, type::lightuserdata, t, ""); + } + return success; + } + else if constexpr (expected == type::function) { + if constexpr (meta::any_same_v, c_closure>) { + tracking.use(1); + bool success = lua_iscfunction(L, index) == 1; + if (!success) { + // expected type, actual type + handler(L, index, expected, type_of(L, index), ""); + } + return success; + } + else { + tracking.use(1); + 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"); + return false; + } + // Do advanced check for call-style userdata? + static const auto& callkey = to_string(meta_function::call); + 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"); + 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"); + 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"); + return false; + } + // has call, is definitely a function + 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; + } + else { + tracking.use(1); + const type indextype = type_of(L, index); + bool success = expected == indextype; + if (!success) { + // expected type, actual type, message + handler(L, index, expected, indextype, ""); + } + return success; + } + } + }; + + template + struct unqualified_checker, type::userdata> : unqualified_checker> {}; + + template + struct unqualified_checker, type::userdata> { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + const type indextype = type_of(L, index); + return check(types(), L, index, indextype, std::forward(handler), tracking); + } + + template + static bool check(types, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) { + tracking.use(1); + if (indextype != type::userdata) { + handler(L, index, type::userdata, indextype, "value is not a valid userdata"); + return false; + } + return true; + } + else { +#if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP + if (stack_detail::interop_check(L, index, indextype, handler, tracking)) { + return true; + } +#endif // interop extensibility + tracking.use(1); + if (indextype != type::userdata) { + handler(L, index, type::userdata, indextype, "value is not a valid userdata"); + return false; + } + if (lua_getmetatable(L, index) == 0) { + return true; + } + int metatableindex = lua_gettop(L); + if (stack_detail::check_metatable(L, metatableindex)) + return true; + if (stack_detail::check_metatable(L, metatableindex)) + return true; + if (stack_detail::check_metatable>(L, metatableindex)) + return true; + if (stack_detail::check_metatable>(L, metatableindex)) + return true; + bool success = false; + bool has_derived = derive::value || weak_derive::value; + if (has_derived) { + #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + 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); + detail::inheritance_check_function ic = reinterpret_cast(basecastdata); + success = ic(usertype_traits::qualified_name()); + } + } + lua_pop(L, 1); + if (!success) { + handler(L, index, type::userdata, indextype, "value at this index does not properly reflect the desired type"); + return false; + } + return true; + } + } + }; + + template + struct unqualified_checker, type::userdata> { + template + 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>(L, index, std::forward(handler), tracking); + } + + template + 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), tracking); + } + }; + + template + struct unqualified_checker, type::poly> { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + return stack::multi_check(L, index, std::forward(handler), tracking); + } + }; + + template + struct unqualified_checker, type::poly> { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + return stack::multi_check(L, index, std::forward(handler), tracking); + } + }; + + template + struct unqualified_checker, type::poly> { + template + static bool check(lua_State* L, int index, Handler&&, record& tracking) { + type t = type_of(L, index); + if (t == type::none) { + tracking.use(0); + return true; + } + if (t == type::lua_nil) { + tracking.use(1); + return true; + } + return stack::unqualified_check(L, index, no_panic, tracking); + } + }; + +#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES + + template + struct unqualified_checker, type::poly> { + template + static bool check(lua_State* L, int index, Handler&&, record& tracking) { + type t = type_of(L, index); + if (t == type::none) { + tracking.use(0); + return true; + } + if (t == type::lua_nil) { + tracking.use(1); + return true; + } + return stack::check(L, index, no_panic, tracking); + } + }; + +#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT + + template + struct unqualified_checker, type::poly> { + typedef std::variant V; + typedef std::variant_size V_size; + typedef std::integral_constant V_is_empty; + + template + static bool is_one(std::integral_constant, lua_State* L, int index, Handler&& handler, record& tracking) { + if constexpr (V_is_empty::value) { + 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"); + return false; + } + + template + static bool is_one(std::integral_constant, lua_State* L, int index, Handler&& handler, record& tracking) { + typedef std::variant_alternative_t T; + record temp_tracking = tracking; + if (stack::check(L, index, no_panic, temp_tracking)) { + tracking = temp_tracking; + return true; + } + return is_one(std::integral_constant(), L, index, std::forward(handler), tracking); + } + + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + return is_one(std::integral_constant(), L, index, std::forward(handler), tracking); + } + }; + +#endif // SOL_STD_VARIANT + +#endif // SOL_CXX17_FEATURES +}} // namespace sol::stack + +#endif // SOL_STACK_CHECK_UNQUALIFIED_HPP -- cgit v1.2.3