Add lua_table and lua_value abstractions

Improve dump handler, bytecode, and base traits
Fix tolua on bad calls, fix interop handler changes
We are now truly done with all feature requests...
This commit is contained in:
ThePhD 2019-03-18 07:41:51 -04:00
parent 70bc1113cb
commit b63d7af060
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
47 changed files with 2064 additions and 787 deletions

View File

@ -29,8 +29,16 @@ inline bool sol_lua_interop_check(sol::types<T>, lua_State* L, int relindex, sol
(void)handler; (void)handler;
int index = lua_absindex(L, relindex); int index = lua_absindex(L, relindex);
std::string name = sol::detail::short_demangle<T>(); std::string name = sol::detail::short_demangle<T>();
tolua_Error tolua_err; tolua_Error tolua_err{};
return tolua_isusertype(L, index, name.c_str(), 0, &tolua_err); int r = tolua_isusertype(L, index, name.c_str(), 0, &tolua_err);
if (r == 0) {
// tolua seems to leave garbage on the stack
// when the check fails
// thanks, tolua
lua_pop(L, 2);
return false;
}
return true;
} }
void register_sol_stuff(lua_State* L) { void register_sol_stuff(lua_State* L) {

View File

@ -39,7 +39,16 @@ namespace sol {
template <typename T> template <typename T>
using void_t = void; using void_t = void;
template <typename T>
using unqualified = std::remove_cv<std::remove_reference_t<T>>;
template <typename T>
using unqualified_t = typename unqualified<T>::type;
namespace meta_detail { namespace meta_detail {
template <typename T>
struct unqualified_non_alias : unqualified<T> {};
template <template <class...> class Test, class, class... Args> template <template <class...> class Test, class, class... Args>
struct is_detected : std::false_type {}; struct is_detected : std::false_type {};
@ -92,12 +101,6 @@ namespace sol {
template <typename T> template <typename T>
using identity_t = typename identity<T>::type; using identity_t = typename identity<T>::type;
template <typename T>
using is_tuple = is_specialization_of<T, std::tuple>;
template <typename T>
constexpr inline bool is_tuple_v = is_tuple<T>::value;
template <typename T> template <typename T>
using is_builtin_type = std::integral_constant<bool, std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_array<T>::value>; using is_builtin_type = std::integral_constant<bool, std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_array<T>::value>;

View File

@ -38,6 +38,17 @@ namespace sol {
using base_t = std::vector<std::byte, Allocator>; using base_t = std::vector<std::byte, Allocator>;
public: public:
using base_t::allocator_type;
using base_t::const_iterator;
using base_t::const_pointer;
using base_t::const_reference;
using base_t::const_reverse_iterator;
using base_t::difference_type;
using base_t::iterator;
using base_t::pointer;
using base_t::reference;
using base_t::reverse_iterator;
using base_t::size_type;
using base_t::value_type; using base_t::value_type;
using base_t::base_t; using base_t::base_t;
@ -81,11 +92,11 @@ namespace sol {
} }
}; };
using bytecode = basic_bytecode<>; template <typename Container>
inline int basic_insert_dump_writer(lua_State*, const void* memory, size_t memory_size, void* userdata) {
inline int bytecode_dump_writer(lua_State*, const void* memory, size_t memory_size, void* userdata) { using storage_t = Container;
const std::byte* p_code = static_cast<const std::byte*>(memory); const std::byte* p_code = static_cast<const std::byte*>(memory);
bytecode& bc = *static_cast<bytecode*>(userdata); storage_t& bc = *static_cast<storage_t*>(userdata);
try { try {
bc.insert(bc.cend(), p_code, p_code + memory_size); bc.insert(bc.cend(), p_code, p_code + memory_size);
} }
@ -95,6 +106,10 @@ namespace sol {
return 0; return 0;
} }
using bytecode = basic_bytecode<>;
constexpr inline auto bytecode_dump_writer = &basic_insert_dump_writer<bytecode>;
} // namespace sol } // namespace sol
#endif // SOL_BYTECODE_HPP #endif // SOL_BYTECODE_HPP

View File

@ -24,6 +24,8 @@
#ifndef SOL_DUMP_HANDLER_HPP #ifndef SOL_DUMP_HANDLER_HPP
#define SOL_DUMP_HANDLER_HPP #define SOL_DUMP_HANDLER_HPP
#include "compatibility.hpp"
#include <cstdint> #include <cstdint>
#include <exception> #include <exception>
@ -42,19 +44,29 @@ namespace sol {
} }
}; };
inline int dump_pass_on_error(int result_code, lua_Writer writer_function, void* userdata, bool strip) { inline int dump_pass_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) {
(void)L;
(void)writer_function; (void)writer_function;
(void)userdata; (void)userdata;
(void)strip; (void)strip;
return result_code; return result_code;
} }
inline int dump_throw_on_error(int result_code, lua_Writer writer_function, void* userdata, bool strip) { inline int dump_throw_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) {
(void)L;
(void)writer_function; (void)writer_function;
(void)userdata; (void)userdata;
(void)strip; (void)strip;
throw dump_error(result_code); throw dump_error(result_code);
} }
inline int dump_panic_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) {
(void)L;
(void)writer_function;
(void)userdata;
(void)strip;
return luaL_error(L, "a non-zero error code (%d) was returned by the lua_Writer for the dump function", result_code);
}
} // namespace sol } // namespace sol

View File

@ -48,13 +48,15 @@ namespace sol {
template <typename A> template <typename A>
class basic_bytecode; class basic_bytecode;
struct lua_value;
struct proxy_base_tag; struct proxy_base_tag;
template <typename Super> template <typename>
struct proxy_base; struct proxy_base;
template <typename Table, typename Key> template <typename, typename>
struct proxy; struct proxy;
template <bool, typename base_type> template <bool, typename>
class basic_table_core; class basic_table_core;
template <bool b> template <bool b>
using table_core = basic_table_core<b, reference>; using table_core = basic_table_core<b, reference>;
@ -71,6 +73,11 @@ namespace sol {
using stack_table = stack_table_core<false>; using stack_table = stack_table_core<false>;
using stack_global_table = stack_table_core<true>; using stack_global_table = stack_table_core<true>;
template <typename>
struct basic_lua_table;
using lua_table = basic_lua_table<reference>;
using stack_lua_table = basic_lua_table<stack_reference>;
template <typename T, typename base_type> template <typename T, typename base_type>
class basic_usertype; class basic_usertype;
template <typename T> template <typename T>

View File

@ -27,6 +27,7 @@
#include "stack.hpp" #include "stack.hpp"
#include "unsafe_function.hpp" #include "unsafe_function.hpp"
#include "protected_function.hpp" #include "protected_function.hpp"
#include "bytecode.hpp"
#include <functional> #include <functional>
namespace sol { namespace sol {
@ -117,8 +118,7 @@ namespace sol {
} }
static std::function<Signature> get(lua_State* L, int index, record& tracking) { static std::function<Signature> get(lua_State* L, int index, record& tracking) {
tracking.last = 1; tracking.use(1);
tracking.used += 1;
type t = type_of(L, index); type t = type_of(L, index);
if (t == type::none || t == type::lua_nil) { if (t == type::none || t == type::lua_nil) {
return nullptr; return nullptr;
@ -126,6 +126,15 @@ namespace sol {
return get_std_func(return_types(), L, index); return get_std_func(return_types(), L, index);
} }
}; };
template <typename Allocator>
struct unqualified_getter<basic_bytecode<Allocator>> {
static basic_bytecode<Allocator> get(lua_State* L, int index, record& tracking) {
tracking.use(1);
stack_function sf(L, index);
return sf.dump(&dump_panic_on_error);
}
};
} // namespace stack } // namespace stack
} // namespace sol } // namespace sol

View File

@ -114,7 +114,7 @@ namespace sol {
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
else if constexpr (sizeof...(Args) < 2) { else if constexpr (sizeof...(Args) < 2) {
using Tu = typename meta::unqualified<Args...>::type; using Tu = typename meta::meta_detail::unqualified_non_alias<Args...>::type;
constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>; constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>;
if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) { if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<typename Tu::type, Fx, is_yielding>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<typename Tu::type, Fx, is_yielding>::call;

95
include/sol/lua_table.hpp Normal file
View File

@ -0,0 +1,95 @@
// 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_LUA_TABLE_HPP
#define SOL_LUA_TABLE_HPP
#include "table_core.hpp"
namespace sol {
template <typename ref_t>
struct basic_lua_table : basic_table_core<false, ref_t> {
private:
using base_t = basic_table_core<false, ref_t>;
friend class state;
friend class state_view;
public:
using base_t::lua_state;
basic_lua_table() noexcept = default;
basic_lua_table(const basic_lua_table&) = default;
basic_lua_table(basic_lua_table&&) = default;
basic_lua_table& operator=(const basic_lua_table&) = default;
basic_lua_table& operator=(basic_lua_table&&) = default;
basic_lua_table(const stack_reference& r) : basic_lua_table(r.lua_state(), r.stack_index()) {
}
basic_lua_table(stack_reference&& r) : basic_lua_table(r.lua_state(), r.stack_index()) {
}
template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_lua_table(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
auto pp = stack::push_pop(*this);
constructor_handler handler{};
stack::check<basic_lua_table>(lua_state(), -1, handler);
#endif // Safety
}
basic_lua_table(lua_State* L, const new_table& nt) : base_t(L, nt) {
if (!is_stack_based<meta::unqualified_t<ref_t>>::value) {
lua_pop(L, 1);
}
}
basic_lua_table(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
constructor_handler handler{};
stack::check<basic_lua_table>(L, index, handler);
#endif // Safety
}
basic_lua_table(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
auto pp = stack::push_pop(*this);
constructor_handler handler{};
stack::check<basic_lua_table>(lua_state(), -1, handler);
#endif // Safety
}
template <typename T,
meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_lua_table>>, meta::neg<std::is_same<ref_t, stack_reference>>,
meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_lua_table(T&& r) noexcept : basic_lua_table(detail::no_safety, std::forward<T>(r)) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
if (!is_table<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this);
constructor_handler handler{};
stack::check<basic_lua_table>(lua_state(), -1, handler);
}
#endif // Safety
}
basic_lua_table(lua_nil_t r) noexcept : basic_lua_table(detail::no_safety, r) {
}
};
}
#endif // SOL_LUA_TABLE_HPP

130
include/sol/lua_value.hpp Normal file
View File

@ -0,0 +1,130 @@
// 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_LUA_VALUE_HPP
#define SOL_LUA_VALUE_HPP
#include "stack.hpp"
#include "reference.hpp"
#include "make_reference.hpp"
namespace sol {
namespace detail {
template <typename T>
using is_reference_or_lua_value_init_list = meta::any<meta::is_specialization_of<T, std::initializer_list>, std::is_same<T, reference>>;
template <typename T>
using is_lua_value_single_constructible = meta::any<std::is_same<T, lua_value>, is_reference_or_lua_value_init_list<T>>;
}
struct lua_value {
private:
static lua_State*& thread_local_lua_state() {
static thread_local lua_State* L = nullptr;
return L;
}
reference ref_value;
public:
static void set_lua_state(lua_State* L) {
thread_local_lua_state() = L;
}
template <typename T, meta::disable<detail::is_reference_or_lua_value_init_list<meta::unqualified_t<T>>> = meta::enabler>
lua_value(lua_State* L_, T&& value) : lua_value(((set_lua_state(L_)), std::forward<T>(value))) {
}
template <typename T, meta::disable<detail::is_lua_value_single_constructible<meta::unqualified_t<T>>> = meta::enabler>
lua_value(T&& value) : ref_value(make_reference(thread_local_lua_state(), std::forward<T>(value))) {
}
lua_value(lua_State* L_, std::initializer_list<lua_value> il) : lua_value(((set_lua_state(L_)), std::move(il))) {
}
lua_value(std::initializer_list<lua_value> il) : ref_value(make_reference(thread_local_lua_state(), std::move(il))) {
}
lua_value(lua_State* L_, reference r) : lua_value(((thread_local_lua_state() = L_), std::move(r))) {
}
lua_value(reference r) : ref_value(std::move(r)) {
}
lua_value(const lua_value&) noexcept = default;
lua_value(lua_value&&) = default;
lua_value& operator=(const lua_value&) = default;
lua_value& operator=(lua_value&&) = default;
const reference& value() const& {
return ref_value;
}
reference& value() & {
return ref_value;
}
reference&& value() && {
return std::move(ref_value);
}
template <typename T>
decltype(auto) as() const {
ref_value.push();
return stack::pop<T>(ref_value.lua_state());
}
template <typename T>
bool is() const {
int r = ref_value.registry_index();
if (r == LUA_REFNIL)
return meta::any_same<meta::unqualified_t<T>, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false;
if (r == LUA_NOREF)
return false;
auto pp = stack::push_pop(ref_value);
return stack::check<T>(ref_value.lua_state(), -1, no_panic);
}
};
namespace stack {
template <>
struct unqualified_pusher<lua_value> {
static int push(lua_State* L, const lua_value& lv) {
return stack::push(L, lv.value());
}
static int push(lua_State* L, lua_value&& lv) {
return stack::push(L, std::move(lv).value());
}
};
template <>
struct unqualified_getter<lua_value> {
static lua_value get(lua_State* L, int index, record& tracking) {
return lua_value(L, stack::get<reference>(L, index, tracking));
}
};
}
} // namespace sol
#endif // SOL_LUA_VALUE_HPP

View File

@ -265,10 +265,11 @@ namespace sol {
template <typename Fx> template <typename Fx>
int dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const { int dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const {
auto pp = stack::push_pop(*this); this->push();
auto ppn = stack::push_popper_n<false>(this->lua_state(), 1);
int r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0); int r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0);
if (r != 0) { if (r != 0) {
return on_error(r, writer, userdata, strip); return on_error(this->lua_state(), r, writer, userdata, strip);
} }
return r; return r;
} }
@ -277,9 +278,17 @@ namespace sol {
return dump(writer, userdata, strip, &dump_pass_on_error); return dump(writer, userdata, strip, &dump_pass_on_error);
} }
bytecode dump() const { template <typename Container = bytecode>
bytecode bc; Container dump() const {
(void)dump(&bytecode_dump_writer, static_cast<void*>(&bc), false, &dump_throw_on_error); Container bc;
(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, &dump_throw_on_error);
return bc;
}
template <typename Container = bytecode, typename Fx>
Container dump(Fx&& on_error) const {
Container bc;
(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, std::forward<Fx>(on_error));
return bc; return bc;
} }

View File

@ -50,6 +50,7 @@
#include "forward.hpp" #include "forward.hpp"
#include "forward_detail.hpp" #include "forward_detail.hpp"
#include "bytecode.hpp"
#include "stack.hpp" #include "stack.hpp"
#include "object.hpp" #include "object.hpp"
#include "function.hpp" #include "function.hpp"
@ -64,6 +65,7 @@
#include "as_args.hpp" #include "as_args.hpp"
#include "variadic_args.hpp" #include "variadic_args.hpp"
#include "variadic_results.hpp" #include "variadic_results.hpp"
#include "lua_value.hpp"
#if defined(__GNUC__) #if defined(__GNUC__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop

View File

@ -29,7 +29,7 @@
namespace sol { namespace sol {
namespace stack { namespace stack {
template <typename X, type expected = lua_type_of_v<meta::unqualified_t<X>>, typename = void> template <typename X, type expected, typename>
struct qualified_checker { struct qualified_checker {
template <typename Handler> 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) {

View File

@ -86,7 +86,7 @@ namespace sol { namespace stack {
} }
}; };
template <typename T, type expected = lua_type_of_v<T>, typename = void> template <typename T, type expected, typename>
struct unqualified_checker { struct unqualified_checker {
template <typename Handler> 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) {
@ -251,6 +251,24 @@ namespace sol { namespace stack {
else if constexpr (std::is_same_v<T, detail::non_lua_nil_t>) { 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);
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<T, basic_bytecode>) {
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<T, basic_environment>) { else if constexpr(meta::is_specialization_of_v<T, basic_environment>) {
tracking.use(1); tracking.use(1);
if (lua_getmetatable(L, index) == 0) { if (lua_getmetatable(L, index) == 0) {
@ -297,7 +315,7 @@ namespace sol { namespace stack {
return success; return success;
} }
else if constexpr (meta::is_specialization_of_v<T, user>) { else if constexpr (meta::is_specialization_of_v<T, user>) {
unqualified_checker<lightuserdata_value> c; unqualified_checker<lightuserdata_value, type::userdata> c;
(void)c; (void)c;
return c.check(L, index, std::forward<Handler>(handler), tracking); return c.check(L, index, std::forward<Handler>(handler), tracking);
} }
@ -415,51 +433,59 @@ namespace sol { namespace stack {
template <typename U, typename Handler> 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 defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP 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>) {
if (stack_detail::interop_check<U>(L, index, indextype, handler, tracking)) { tracking.use(1);
return true; if (indextype != type::userdata) {
} handler(L, index, type::userdata, indextype, "value is not a valid userdata");
#endif // interop extensibility return false;
tracking.use(1);
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype, "value is not a valid userdata");
return false;
}
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)
return true;
if (lua_getmetatable(L, index) == 0) {
return true;
}
int metatableindex = lua_gettop(L);
if (stack_detail::check_metatable<U>(L, metatableindex))
return true;
if (stack_detail::check_metatable<U*>(L, metatableindex))
return true;
if (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex))
return true;
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 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<detail::inheritance_check_function>(basecastdata);
success = ic(usertype_traits<T>::qualified_name());
} }
return true;
} }
lua_pop(L, 1); else {
if (!success) { #if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP
handler(L, index, type::userdata, indextype, "value at this index does not properly reflect the desired type"); if (stack_detail::interop_check<U>(L, index, indextype, handler, tracking)) {
return false; 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<U>(L, metatableindex))
return true;
if (stack_detail::check_metatable<U*>(L, metatableindex))
return true;
if (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex))
return true;
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 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<detail::inheritance_check_function>(basecastdata);
success = ic(usertype_traits<T>::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;
} }
return true;
} }
}; };

View File

@ -597,9 +597,9 @@ namespace sol {
template <typename T, typename = void> template <typename T, typename = void>
struct unqualified_pusher; struct unqualified_pusher;
template <typename T, type t, typename> template <typename T, type t, typename = void>
struct unqualified_checker; struct unqualified_checker;
template <typename T, type t, typename> template <typename T, type t, typename = void>
struct qualified_checker; struct qualified_checker;
template <typename T, typename = void> template <typename T, typename = void>
@ -925,7 +925,7 @@ namespace sol {
return sol_lua_check(types<Tu>(), L, index, std::forward<Handler>(handler), tracking); return sol_lua_check(types<Tu>(), L, index, std::forward<Handler>(handler), tracking);
} }
else { else {
unqualified_checker<Tu> c; unqualified_checker<Tu, lua_type_of_v<Tu>> c;
// VC++ has a bad warning here: shut it up // VC++ has a bad warning here: shut it up
(void)c; (void)c;
return c.check(L, index, std::forward<Handler>(handler), tracking); return c.check(L, index, std::forward<Handler>(handler), tracking);
@ -950,7 +950,8 @@ namespace sol {
return sol_lua_check(types<T>(), L, index, std::forward<Handler>(handler), tracking); return sol_lua_check(types<T>(), L, index, std::forward<Handler>(handler), tracking);
} }
else { else {
qualified_checker<T> c; using Tu = meta::unqualified_t<T>;
qualified_checker<T, lua_type_of_v<Tu>> c;
// VC++ has a bad warning here: shut it up // VC++ has a bad warning here: shut it up
(void)c; (void)c;
return c.check(L, index, std::forward<Handler>(handler), tracking); return c.check(L, index, std::forward<Handler>(handler), tracking);
@ -1049,6 +1050,11 @@ namespace sol {
namespace stack_detail { namespace stack_detail {
template <typename Handler>
inline bool check_types(lua_State*, int, Handler&&, record&) {
return true;
}
template <typename T, typename... Args, typename Handler> template <typename T, typename... Args, typename Handler>
inline bool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) { inline bool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) {
if (!stack::check<T>(L, firstargument + tracking.used, handler, tracking)) if (!stack::check<T>(L, firstargument + tracking.used, handler, tracking))
@ -1056,13 +1062,8 @@ namespace sol {
return check_types<Args...>(L, firstargument, std::forward<Handler>(handler), tracking); return check_types<Args...>(L, firstargument, std::forward<Handler>(handler), tracking);
} }
template <typename Handler>
static bool check_types(lua_State*, int, Handler&&, record&) {
return true;
}
template <typename... Args, typename Handler> template <typename... Args, typename Handler>
bool check_types(types<Args...>, lua_State* L, int index, Handler&& handler, record& tracking) { inline bool check_types(types<Args...>, lua_State* L, int index, Handler&& handler, record& tracking) {
return check_types<Args...>(L, index, std::forward<Handler>(handler), tracking); return check_types<Args...>(L, index, std::forward<Handler>(handler), tracking);
} }

View File

@ -1146,6 +1146,24 @@ namespace sol {
} }
}; };
template <typename Allocator>
struct unqualified_pusher<basic_bytecode<Allocator>> {
template <typename T>
static int push(lua_State* L, T&& bc, const char* bytecode_name) {
const auto first = bc.data();
const auto bcsize = bc.size();
// pushes either the function, or an error
// if it errors, shit goes south, and people can test that upstream
(void)luaL_loadbuffer(L, reinterpret_cast<const char*>(first), static_cast<std::size_t>(bcsize * (sizeof(*first) / sizeof(const char))), bytecode_name);
return 1;
}
template <typename T>
static int push(lua_State* L, T&& bc) {
return push(L, std::forward<bc>(bc), "bytecode");
}
};
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
template <typename O> template <typename O>
struct unqualified_pusher<std::optional<O>> { struct unqualified_pusher<std::optional<O>> {

View File

@ -28,6 +28,7 @@
#include "stack.hpp" #include "stack.hpp"
#include "function.hpp" #include "function.hpp"
#include "object.hpp" #include "object.hpp"
#include "lua_value.hpp"
#if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS #if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS
#include <iostream> #include <iostream>
@ -97,6 +98,7 @@ namespace sol {
set_default_exception_handler(L, exf); set_default_exception_handler(L, exf);
register_main_thread(L); register_main_thread(L);
stack::luajit_exception_handler(L); stack::luajit_exception_handler(L);
lua_value::set_lua_state(L);
} }
inline std::size_t total_memory_used(lua_State* L) { inline std::size_t total_memory_used(lua_State* L) {

View File

@ -25,6 +25,7 @@
#define SOL_TABLE_HPP #define SOL_TABLE_HPP
#include "table_core.hpp" #include "table_core.hpp"
#include "lua_table.hpp"
#include "usertype.hpp" #include "usertype.hpp"
namespace sol { namespace sol {

View File

@ -25,6 +25,7 @@
#define SOL_TUPLE_HPP #define SOL_TUPLE_HPP
#include "forward.hpp" #include "forward.hpp"
#include "base_traits.hpp"
#include <tuple> #include <tuple>
#include <cstddef> #include <cstddef>
@ -35,6 +36,12 @@ namespace sol {
} // namespace detail } // namespace detail
namespace meta { namespace meta {
template <typename T>
using is_tuple = is_specialization_of<T, std::tuple>;
template <typename T>
constexpr inline bool is_tuple_v = is_tuple<T>::value;
namespace detail { namespace detail {
template <typename... Args> template <typename... Args>
struct tuple_types_ { typedef types<Args...> type; }; struct tuple_types_ { typedef types<Args...> type; };
@ -43,12 +50,6 @@ namespace sol {
struct tuple_types_<std::tuple<Args...>> { typedef types<Args...> type; }; struct tuple_types_<std::tuple<Args...>> { typedef types<Args...> type; };
} // namespace detail } // namespace detail
template <typename T>
struct unqualified : std::remove_cv<std::remove_reference_t<T>> {};
template <typename T>
using unqualified_t = typename unqualified<T>::type;
template <typename... Args> template <typename... Args>
using tuple_types = typename detail::tuple_types_<Args...>::type; using tuple_types = typename detail::tuple_types_<Args...>::type;

View File

@ -1006,6 +1006,9 @@ namespace sol {
template <> template <>
struct lua_type_of<nullopt_t> : std::integral_constant<type, type::lua_nil> {}; struct lua_type_of<nullopt_t> : std::integral_constant<type, type::lua_nil> {};
template <>
struct lua_type_of<lua_value> : std::integral_constant<type, type::poly> {};
template <> template <>
struct lua_type_of<detail::non_lua_nil_t> : std::integral_constant<type, type::poly> {}; struct lua_type_of<detail::non_lua_nil_t> : std::integral_constant<type, type::poly> {};
@ -1018,6 +1021,9 @@ namespace sol {
template <bool b, typename Base> template <bool b, typename Base>
struct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> {}; struct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> {};
template <typename Base>
struct lua_type_of<basic_lua_table<Base>> : std::integral_constant<type, type::table> {};
template <typename Base> template <typename Base>
struct lua_type_of<basic_metatable<Base>> : std::integral_constant<type, type::table> {}; struct lua_type_of<basic_metatable<Base>> : std::integral_constant<type, type::table> {};

View File

@ -124,10 +124,11 @@ namespace sol {
template <typename Fx> template <typename Fx>
int dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const { int dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const {
auto pp = stack::push_pop(*this); this->push();
auto ppn = stack::push_popper_n<false>(this->lua_state(), 1);
int r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0); int r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0);
if (r != 0) { if (r != 0) {
return on_error(r, writer, userdata, strip); return on_error(this->lua_state(), r, writer, userdata, strip);
} }
return r; return r;
} }
@ -136,9 +137,17 @@ namespace sol {
return dump(writer, userdata, strip, &dump_throw_on_error); return dump(writer, userdata, strip, &dump_throw_on_error);
} }
bytecode dump() const { template <typename Container = bytecode>
bytecode bc; Container dump() const {
(void)dump(&bytecode_dump_writer, static_cast<void*>(&bc), strip, &dump_throw_on_error); Container bc;
(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, &dump_panic_on_error);
return bc;
}
template <typename Container = bytecode, typename Fx>
Container dump(Fx&& on_error) const {
Container bc;
(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, std::forward<Fx>(on_error));
return bc; return bc;
} }

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2019-03-14 20:15:14.754895 UTC // Generated 2019-03-18 11:40:51.752769 UTC
// This header was generated with sol v3.0.0 (revision c1a8cb1) // This header was generated with sol v3.0.0 (revision 70bc111)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
@ -264,13 +264,15 @@ namespace sol {
template <typename A> template <typename A>
class basic_bytecode; class basic_bytecode;
struct lua_value;
struct proxy_base_tag; struct proxy_base_tag;
template <typename Super> template <typename>
struct proxy_base; struct proxy_base;
template <typename Table, typename Key> template <typename, typename>
struct proxy; struct proxy;
template <bool, typename base_type> template <bool, typename>
class basic_table_core; class basic_table_core;
template <bool b> template <bool b>
using table_core = basic_table_core<b, reference>; using table_core = basic_table_core<b, reference>;
@ -287,6 +289,11 @@ namespace sol {
using stack_table = stack_table_core<false>; using stack_table = stack_table_core<false>;
using stack_global_table = stack_table_core<true>; using stack_global_table = stack_table_core<true>;
template <typename>
struct basic_lua_table;
using lua_table = basic_lua_table<reference>;
using stack_lua_table = basic_lua_table<stack_reference>;
template <typename T, typename base_type> template <typename T, typename base_type>
class basic_usertype; class basic_usertype;
template <typename T> template <typename T>

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2019-03-14 20:15:14.455770 UTC // Generated 2019-03-18 11:40:51.457664 UTC
// This header was generated with sol v3.0.0 (revision c1a8cb1) // This header was generated with sol v3.0.0 (revision 70bc111)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP #ifndef SOL_SINGLE_INCLUDE_HPP
@ -289,13 +289,15 @@ namespace sol {
template <typename A> template <typename A>
class basic_bytecode; class basic_bytecode;
struct lua_value;
struct proxy_base_tag; struct proxy_base_tag;
template <typename Super> template <typename>
struct proxy_base; struct proxy_base;
template <typename Table, typename Key> template <typename, typename>
struct proxy; struct proxy;
template <bool, typename base_type> template <bool, typename>
class basic_table_core; class basic_table_core;
template <bool b> template <bool b>
using table_core = basic_table_core<b, reference>; using table_core = basic_table_core<b, reference>;
@ -312,6 +314,11 @@ namespace sol {
using stack_table = stack_table_core<false>; using stack_table = stack_table_core<false>;
using stack_global_table = stack_table_core<true>; using stack_global_table = stack_table_core<true>;
template <typename>
struct basic_lua_table;
using lua_table = basic_lua_table<reference>;
using stack_lua_table = basic_lua_table<stack_reference>;
template <typename T, typename base_type> template <typename T, typename base_type>
class basic_usertype; class basic_usertype;
template <typename T> template <typename T>
@ -498,69 +505,6 @@ namespace sol {
// beginning of sol/tuple.hpp // beginning of sol/tuple.hpp
#include <tuple>
#include <cstddef>
namespace sol {
namespace detail {
using swallow = std::initializer_list<int>;
} // namespace detail
namespace meta {
namespace detail {
template <typename... Args>
struct tuple_types_ { typedef types<Args...> type; };
template <typename... Args>
struct tuple_types_<std::tuple<Args...>> { typedef types<Args...> type; };
} // namespace detail
template <typename T>
struct unqualified : std::remove_cv<std::remove_reference_t<T>> {};
template <typename T>
using unqualified_t = typename unqualified<T>::type;
template <typename... Args>
using tuple_types = typename detail::tuple_types_<Args...>::type;
template <typename Arg>
struct pop_front_type;
template <typename Arg>
using pop_front_type_t = typename pop_front_type<Arg>::type;
template <typename... Args>
struct pop_front_type<types<Args...>> {
typedef void front_type;
typedef types<Args...> type;
};
template <typename Arg, typename... Args>
struct pop_front_type<types<Arg, Args...>> {
typedef Arg front_type;
typedef types<Args...> type;
};
template <std::size_t N, typename Tuple>
using tuple_element = std::tuple_element<N, std::remove_reference_t<Tuple>>;
template <std::size_t N, typename Tuple>
using tuple_element_t = std::tuple_element_t<N, std::remove_reference_t<Tuple>>;
template <std::size_t N, typename Tuple>
using unqualified_tuple_element = unqualified<tuple_element_t<N, Tuple>>;
template <std::size_t N, typename Tuple>
using unqualified_tuple_element_t = unqualified_t<tuple_element_t<N, Tuple>>;
} // namespace meta
} // namespace sol
// end of sol/tuple.hpp
// beginning of sol/bind_traits.hpp
// beginning of sol/base_traits.hpp // beginning of sol/base_traits.hpp
namespace sol { namespace sol {
@ -576,7 +520,16 @@ namespace sol {
template <typename T> template <typename T>
using void_t = void; using void_t = void;
template <typename T>
using unqualified = std::remove_cv<std::remove_reference_t<T>>;
template <typename T>
using unqualified_t = typename unqualified<T>::type;
namespace meta_detail { namespace meta_detail {
template <typename T>
struct unqualified_non_alias : unqualified<T> {};
template <template <class...> class Test, class, class... Args> template <template <class...> class Test, class, class... Args>
struct is_detected : std::false_type {}; struct is_detected : std::false_type {};
@ -629,12 +582,6 @@ namespace sol {
template <typename T> template <typename T>
using identity_t = typename identity<T>::type; using identity_t = typename identity<T>::type;
template <typename T>
using is_tuple = is_specialization_of<T, std::tuple>;
template <typename T>
constexpr inline bool is_tuple_v = is_tuple<T>::value;
template <typename T> template <typename T>
using is_builtin_type = std::integral_constant<bool, std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_array<T>::value>; using is_builtin_type = std::integral_constant<bool, std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_array<T>::value>;
@ -643,6 +590,69 @@ namespace sol {
// end of sol/base_traits.hpp // end of sol/base_traits.hpp
#include <tuple>
#include <cstddef>
namespace sol {
namespace detail {
using swallow = std::initializer_list<int>;
} // namespace detail
namespace meta {
template <typename T>
using is_tuple = is_specialization_of<T, std::tuple>;
template <typename T>
constexpr inline bool is_tuple_v = is_tuple<T>::value;
namespace detail {
template <typename... Args>
struct tuple_types_ { typedef types<Args...> type; };
template <typename... Args>
struct tuple_types_<std::tuple<Args...>> { typedef types<Args...> type; };
} // namespace detail
template <typename... Args>
using tuple_types = typename detail::tuple_types_<Args...>::type;
template <typename Arg>
struct pop_front_type;
template <typename Arg>
using pop_front_type_t = typename pop_front_type<Arg>::type;
template <typename... Args>
struct pop_front_type<types<Args...>> {
typedef void front_type;
typedef types<Args...> type;
};
template <typename Arg, typename... Args>
struct pop_front_type<types<Arg, Args...>> {
typedef Arg front_type;
typedef types<Args...> type;
};
template <std::size_t N, typename Tuple>
using tuple_element = std::tuple_element<N, std::remove_reference_t<Tuple>>;
template <std::size_t N, typename Tuple>
using tuple_element_t = std::tuple_element_t<N, std::remove_reference_t<Tuple>>;
template <std::size_t N, typename Tuple>
using unqualified_tuple_element = unqualified<tuple_element_t<N, Tuple>>;
template <std::size_t N, typename Tuple>
using unqualified_tuple_element_t = unqualified_t<tuple_element_t<N, Tuple>>;
} // namespace meta
} // namespace sol
// end of sol/tuple.hpp
// beginning of sol/bind_traits.hpp
namespace sol { namespace sol {
namespace meta { namespace meta {
namespace meta_detail { namespace meta_detail {
@ -2041,13 +2051,7 @@ namespace sol {
#endif // SOL_FORWARD_DETAIL_HPP #endif // SOL_FORWARD_DETAIL_HPP
// end of sol/forward_detail.hpp // end of sol/forward_detail.hpp
// beginning of sol/stack.hpp // beginning of sol/bytecode.hpp
// beginning of sol/trampoline.hpp
// beginning of sol/types.hpp
// beginning of sol/error.hpp
// beginning of sol/compatibility.hpp // beginning of sol/compatibility.hpp
@ -3369,6 +3373,99 @@ COMPAT53_API void luaL_requiref(lua_State *L, const char *modname,
// end of sol/compatibility.hpp // end of sol/compatibility.hpp
#include <vector>
namespace sol {
template <typename Allocator = std::allocator<std::byte>>
class basic_bytecode : private std::vector<std::byte, Allocator> {
private:
using base_t = std::vector<std::byte, Allocator>;
public:
using base_t::allocator_type;
using base_t::const_iterator;
using base_t::const_pointer;
using base_t::const_reference;
using base_t::const_reverse_iterator;
using base_t::difference_type;
using base_t::iterator;
using base_t::pointer;
using base_t::reference;
using base_t::reverse_iterator;
using base_t::size_type;
using base_t::value_type;
using base_t::base_t;
using base_t::operator=;
using base_t::data;
using base_t::empty;
using base_t::max_size;
using base_t::size;
using base_t::at;
using base_t::operator[];
using base_t::back;
using base_t::front;
using base_t::begin;
using base_t::cbegin;
using base_t::cend;
using base_t::end;
using base_t::crbegin;
using base_t::crend;
using base_t::rbegin;
using base_t::rend;
using base_t::swap;
using base_t::get_allocator;
using base_t::emplace;
using base_t::emplace_back;
using base_t::insert;
using base_t::pop_back;
using base_t::push_back;
using base_t::reserve;
using base_t::resize;
using base_t::shrink_to_fit;
string_view as_string_view () const {
return string_view(reinterpret_cast<const char*>(this->data()), this->size());
}
};
template <typename Container>
inline int basic_insert_dump_writer(lua_State*, const void* memory, size_t memory_size, void* userdata) {
using storage_t = Container;
const std::byte* p_code = static_cast<const std::byte*>(memory);
storage_t& bc = *static_cast<storage_t*>(userdata);
try {
bc.insert(bc.cend(), p_code, p_code + memory_size);
}
catch ( ... ) {
return -1;
}
return 0;
}
using bytecode = basic_bytecode<>;
constexpr inline auto bytecode_dump_writer = &basic_insert_dump_writer<bytecode>;
} // namespace sol
// end of sol/bytecode.hpp
// beginning of sol/stack.hpp
// beginning of sol/trampoline.hpp
// beginning of sol/types.hpp
// beginning of sol/error.hpp
#include <stdexcept> #include <stdexcept>
namespace sol { namespace sol {
@ -7017,6 +7114,9 @@ namespace sol {
template <> template <>
struct lua_type_of<nullopt_t> : std::integral_constant<type, type::lua_nil> {}; struct lua_type_of<nullopt_t> : std::integral_constant<type, type::lua_nil> {};
template <>
struct lua_type_of<lua_value> : std::integral_constant<type, type::poly> {};
template <> template <>
struct lua_type_of<detail::non_lua_nil_t> : std::integral_constant<type, type::poly> {}; struct lua_type_of<detail::non_lua_nil_t> : std::integral_constant<type, type::poly> {};
@ -7029,6 +7129,9 @@ namespace sol {
template <bool b, typename Base> template <bool b, typename Base>
struct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> {}; struct lua_type_of<basic_table_core<b, Base>> : std::integral_constant<type, type::table> {};
template <typename Base>
struct lua_type_of<basic_lua_table<Base>> : std::integral_constant<type, type::table> {};
template <typename Base> template <typename Base>
struct lua_type_of<basic_metatable<Base>> : std::integral_constant<type, type::table> {}; struct lua_type_of<basic_metatable<Base>> : std::integral_constant<type, type::table> {};
@ -8917,7 +9020,6 @@ namespace sol {
// end of sol/stack_guard.hpp // end of sol/stack_guard.hpp
#include <vector>
#include <bitset> #include <bitset>
#include <forward_list> #include <forward_list>
#include <algorithm> #include <algorithm>
@ -9476,9 +9578,9 @@ namespace sol {
template <typename T, typename = void> template <typename T, typename = void>
struct unqualified_pusher; struct unqualified_pusher;
template <typename T, type t, typename> template <typename T, type t, typename = void>
struct unqualified_checker; struct unqualified_checker;
template <typename T, type t, typename> template <typename T, type t, typename = void>
struct qualified_checker; struct qualified_checker;
template <typename T, typename = void> template <typename T, typename = void>
@ -9803,7 +9905,7 @@ namespace sol {
return sol_lua_check(types<Tu>(), L, index, std::forward<Handler>(handler), tracking); return sol_lua_check(types<Tu>(), L, index, std::forward<Handler>(handler), tracking);
} }
else { else {
unqualified_checker<Tu> c; unqualified_checker<Tu, lua_type_of_v<Tu>> c;
// VC++ has a bad warning here: shut it up // VC++ has a bad warning here: shut it up
(void)c; (void)c;
return c.check(L, index, std::forward<Handler>(handler), tracking); return c.check(L, index, std::forward<Handler>(handler), tracking);
@ -9828,7 +9930,8 @@ namespace sol {
return sol_lua_check(types<T>(), L, index, std::forward<Handler>(handler), tracking); return sol_lua_check(types<T>(), L, index, std::forward<Handler>(handler), tracking);
} }
else { else {
qualified_checker<T> c; using Tu = meta::unqualified_t<T>;
qualified_checker<T, lua_type_of_v<Tu>> c;
// VC++ has a bad warning here: shut it up // VC++ has a bad warning here: shut it up
(void)c; (void)c;
return c.check(L, index, std::forward<Handler>(handler), tracking); return c.check(L, index, std::forward<Handler>(handler), tracking);
@ -9927,6 +10030,11 @@ namespace sol {
namespace stack_detail { namespace stack_detail {
template <typename Handler>
inline bool check_types(lua_State*, int, Handler&&, record&) {
return true;
}
template <typename T, typename... Args, typename Handler> template <typename T, typename... Args, typename Handler>
inline bool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) { inline bool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) {
if (!stack::check<T>(L, firstargument + tracking.used, handler, tracking)) if (!stack::check<T>(L, firstargument + tracking.used, handler, tracking))
@ -9934,13 +10042,8 @@ namespace sol {
return check_types<Args...>(L, firstargument, std::forward<Handler>(handler), tracking); return check_types<Args...>(L, firstargument, std::forward<Handler>(handler), tracking);
} }
template <typename Handler>
static bool check_types(lua_State*, int, Handler&&, record&) {
return true;
}
template <typename... Args, typename Handler> template <typename... Args, typename Handler>
bool check_types(types<Args...>, lua_State* L, int index, Handler&& handler, record& tracking) { inline bool check_types(types<Args...>, lua_State* L, int index, Handler&& handler, record& tracking) {
return check_types<Args...>(L, index, std::forward<Handler>(handler), tracking); return check_types<Args...>(L, index, std::forward<Handler>(handler), tracking);
} }
@ -10323,7 +10426,7 @@ namespace sol { namespace stack {
} }
}; };
template <typename T, type expected = lua_type_of_v<T>, typename = void> template <typename T, type expected, typename>
struct unqualified_checker { struct unqualified_checker {
template <typename Handler> 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) {
@ -10488,6 +10591,24 @@ namespace sol { namespace stack {
else if constexpr (std::is_same_v<T, detail::non_lua_nil_t>) { 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);
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<T, basic_bytecode>) {
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<T, basic_environment>) { else if constexpr(meta::is_specialization_of_v<T, basic_environment>) {
tracking.use(1); tracking.use(1);
if (lua_getmetatable(L, index) == 0) { if (lua_getmetatable(L, index) == 0) {
@ -10534,7 +10655,7 @@ namespace sol { namespace stack {
return success; return success;
} }
else if constexpr (meta::is_specialization_of_v<T, user>) { else if constexpr (meta::is_specialization_of_v<T, user>) {
unqualified_checker<lightuserdata_value> c; unqualified_checker<lightuserdata_value, type::userdata> c;
(void)c; (void)c;
return c.check(L, index, std::forward<Handler>(handler), tracking); return c.check(L, index, std::forward<Handler>(handler), tracking);
} }
@ -10652,51 +10773,59 @@ namespace sol { namespace stack {
template <typename U, typename Handler> 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 defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP 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>) {
if (stack_detail::interop_check<U>(L, index, indextype, handler, tracking)) { tracking.use(1);
return true; if (indextype != type::userdata) {
} handler(L, index, type::userdata, indextype, "value is not a valid userdata");
#endif // interop extensibility return false;
tracking.use(1);
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype, "value is not a valid userdata");
return false;
}
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)
return true;
if (lua_getmetatable(L, index) == 0) {
return true;
}
int metatableindex = lua_gettop(L);
if (stack_detail::check_metatable<U>(L, metatableindex))
return true;
if (stack_detail::check_metatable<U*>(L, metatableindex))
return true;
if (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex))
return true;
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 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<detail::inheritance_check_function>(basecastdata);
success = ic(usertype_traits<T>::qualified_name());
} }
return true;
} }
lua_pop(L, 1); else {
if (!success) { #if defined(SOL_ENABLE_INTEROP) && SOL_ENABLE_INTEROP
handler(L, index, type::userdata, indextype, "value at this index does not properly reflect the desired type"); if (stack_detail::interop_check<U>(L, index, indextype, handler, tracking)) {
return false; 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<U>(L, metatableindex))
return true;
if (stack_detail::check_metatable<U*>(L, metatableindex))
return true;
if (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex))
return true;
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 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<detail::inheritance_check_function>(basecastdata);
success = ic(usertype_traits<T>::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;
} }
return true;
} }
}; };
@ -10819,7 +10948,7 @@ namespace sol { namespace stack {
namespace sol { namespace sol {
namespace stack { namespace stack {
template <typename X, type expected = lua_type_of_v<meta::unqualified_t<X>>, typename = void> template <typename X, type expected, typename>
struct qualified_checker { struct qualified_checker {
template <typename Handler> 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) {
@ -13537,6 +13666,24 @@ namespace sol {
} }
}; };
template <typename Allocator>
struct unqualified_pusher<basic_bytecode<Allocator>> {
template <typename T>
static int push(lua_State* L, T&& bc, const char* bytecode_name) {
const auto first = bc.data();
const auto bcsize = bc.size();
// pushes either the function, or an error
// if it errors, shit goes south, and people can test that upstream
(void)luaL_loadbuffer(L, reinterpret_cast<const char*>(first), static_cast<std::size_t>(bcsize * (sizeof(*first) / sizeof(const char))), bytecode_name);
return 1;
}
template <typename T>
static int push(lua_State* L, T&& bc) {
return push(L, std::forward<bc>(bc), "bytecode");
}
};
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
template <typename O> template <typename O>
struct unqualified_pusher<std::optional<O>> { struct unqualified_pusher<std::optional<O>> {
@ -17110,7 +17257,7 @@ namespace sol {
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
else if constexpr (sizeof...(Args) < 2) { else if constexpr (sizeof...(Args) < 2) {
using Tu = typename meta::unqualified<Args...>::type; using Tu = typename meta::meta_detail::unqualified_non_alias<Args...>::type;
constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>; constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>;
if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) { if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<typename Tu::type, Fx, is_yielding>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<typename Tu::type, Fx, is_yielding>::call;
@ -17574,76 +17721,6 @@ namespace sol {
// end of sol/function_types.hpp // end of sol/function_types.hpp
// beginning of sol/bytecode.hpp
namespace sol {
template <typename Allocator = std::allocator<std::byte>>
class basic_bytecode : private std::vector<std::byte, Allocator> {
private:
using base_t = std::vector<std::byte, Allocator>;
public:
using base_t::value_type;
using base_t::base_t;
using base_t::operator=;
using base_t::data;
using base_t::empty;
using base_t::max_size;
using base_t::size;
using base_t::at;
using base_t::operator[];
using base_t::back;
using base_t::front;
using base_t::begin;
using base_t::cbegin;
using base_t::cend;
using base_t::end;
using base_t::crbegin;
using base_t::crend;
using base_t::rbegin;
using base_t::rend;
using base_t::swap;
using base_t::get_allocator;
using base_t::emplace;
using base_t::emplace_back;
using base_t::insert;
using base_t::pop_back;
using base_t::push_back;
using base_t::reserve;
using base_t::resize;
using base_t::shrink_to_fit;
string_view as_string_view () const {
return string_view(reinterpret_cast<const char*>(this->data()), this->size());
}
};
using bytecode = basic_bytecode<>;
inline int bytecode_dump_writer(lua_State*, const void* memory, size_t memory_size, void* userdata) {
const std::byte* p_code = static_cast<const std::byte*>(memory);
bytecode& bc = *static_cast<bytecode*>(userdata);
try {
bc.insert(bc.cend(), p_code, p_code + memory_size);
}
catch ( ... ) {
return -1;
}
return 0;
}
} // namespace sol
// end of sol/bytecode.hpp
// beginning of sol/dump_handler.hpp // beginning of sol/dump_handler.hpp
namespace sol { namespace sol {
@ -17661,19 +17738,29 @@ namespace sol {
} }
}; };
inline int dump_pass_on_error(int result_code, lua_Writer writer_function, void* userdata, bool strip) { inline int dump_pass_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) {
(void)L;
(void)writer_function; (void)writer_function;
(void)userdata; (void)userdata;
(void)strip; (void)strip;
return result_code; return result_code;
} }
inline int dump_throw_on_error(int result_code, lua_Writer writer_function, void* userdata, bool strip) { inline int dump_throw_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) {
(void)L;
(void)writer_function; (void)writer_function;
(void)userdata; (void)userdata;
(void)strip; (void)strip;
throw dump_error(result_code); throw dump_error(result_code);
} }
inline int dump_panic_on_error(lua_State* L, int result_code, lua_Writer writer_function, void* userdata, bool strip) {
(void)L;
(void)writer_function;
(void)userdata;
(void)strip;
return luaL_error(L, "a non-zero error code (%d) was returned by the lua_Writer for the dump function", result_code);
}
} // namespace sol } // namespace sol
@ -17770,10 +17857,11 @@ namespace sol {
template <typename Fx> template <typename Fx>
int dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const { int dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const {
auto pp = stack::push_pop(*this); this->push();
auto ppn = stack::push_popper_n<false>(this->lua_state(), 1);
int r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0); int r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0);
if (r != 0) { if (r != 0) {
return on_error(r, writer, userdata, strip); return on_error(this->lua_state(), r, writer, userdata, strip);
} }
return r; return r;
} }
@ -17782,9 +17870,17 @@ namespace sol {
return dump(writer, userdata, strip, &dump_throw_on_error); return dump(writer, userdata, strip, &dump_throw_on_error);
} }
bytecode dump() const { template <typename Container = bytecode>
bytecode bc; Container dump() const {
(void)dump(&bytecode_dump_writer, static_cast<void*>(&bc), strip, &dump_throw_on_error); Container bc;
(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, &dump_panic_on_error);
return bc;
}
template <typename Container = bytecode, typename Fx>
Container dump(Fx&& on_error) const {
Container bc;
(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, std::forward<Fx>(on_error));
return bc; return bc;
} }
@ -18125,10 +18221,11 @@ namespace sol {
template <typename Fx> template <typename Fx>
int dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const { int dump(lua_Writer writer, void* userdata, bool strip, Fx&& on_error) const {
auto pp = stack::push_pop(*this); this->push();
auto ppn = stack::push_popper_n<false>(this->lua_state(), 1);
int r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0); int r = lua_dump(this->lua_state(), writer, userdata, strip ? 1 : 0);
if (r != 0) { if (r != 0) {
return on_error(r, writer, userdata, strip); return on_error(this->lua_state(), r, writer, userdata, strip);
} }
return r; return r;
} }
@ -18137,9 +18234,17 @@ namespace sol {
return dump(writer, userdata, strip, &dump_pass_on_error); return dump(writer, userdata, strip, &dump_pass_on_error);
} }
bytecode dump() const { template <typename Container = bytecode>
bytecode bc; Container dump() const {
(void)dump(&bytecode_dump_writer, static_cast<void*>(&bc), false, &dump_throw_on_error); Container bc;
(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, &dump_throw_on_error);
return bc;
}
template <typename Container = bytecode, typename Fx>
Container dump(Fx&& on_error) const {
Container bc;
(void)dump(static_cast<lua_Writer>(&basic_insert_dump_writer<Container>), static_cast<void*>(&bc), false, std::forward<Fx>(on_error));
return bc; return bc;
} }
@ -18288,8 +18393,7 @@ namespace sol {
} }
static std::function<Signature> get(lua_State* L, int index, record& tracking) { static std::function<Signature> get(lua_State* L, int index, record& tracking) {
tracking.last = 1; tracking.use(1);
tracking.used += 1;
type t = type_of(L, index); type t = type_of(L, index);
if (t == type::none || t == type::lua_nil) { if (t == type::none || t == type::lua_nil) {
return nullptr; return nullptr;
@ -18297,6 +18401,15 @@ namespace sol {
return get_std_func(return_types(), L, index); return get_std_func(return_types(), L, index);
} }
}; };
template <typename Allocator>
struct unqualified_getter<basic_bytecode<Allocator>> {
static basic_bytecode<Allocator> get(lua_State* L, int index, record& tracking) {
tracking.use(1);
stack_function sf(L, index);
return sf.dump(&dump_panic_on_error);
}
};
} // namespace stack } // namespace stack
} // namespace sol } // namespace sol
@ -22479,6 +22592,76 @@ namespace sol {
// beginning of sol/table.hpp // beginning of sol/table.hpp
// beginning of sol/lua_table.hpp
namespace sol {
template <typename ref_t>
struct basic_lua_table : basic_table_core<false, ref_t> {
private:
using base_t = basic_table_core<false, ref_t>;
friend class state;
friend class state_view;
public:
using base_t::lua_state;
basic_lua_table() noexcept = default;
basic_lua_table(const basic_lua_table&) = default;
basic_lua_table(basic_lua_table&&) = default;
basic_lua_table& operator=(const basic_lua_table&) = default;
basic_lua_table& operator=(basic_lua_table&&) = default;
basic_lua_table(const stack_reference& r) : basic_lua_table(r.lua_state(), r.stack_index()) {
}
basic_lua_table(stack_reference&& r) : basic_lua_table(r.lua_state(), r.stack_index()) {
}
template <typename T, meta::enable_any<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_lua_table(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
auto pp = stack::push_pop(*this);
constructor_handler handler{};
stack::check<basic_lua_table>(lua_state(), -1, handler);
#endif // Safety
}
basic_lua_table(lua_State* L, const new_table& nt) : base_t(L, nt) {
if (!is_stack_based<meta::unqualified_t<ref_t>>::value) {
lua_pop(L, 1);
}
}
basic_lua_table(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
constructor_handler handler{};
stack::check<basic_lua_table>(L, index, handler);
#endif // Safety
}
basic_lua_table(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
auto pp = stack::push_pop(*this);
constructor_handler handler{};
stack::check<basic_lua_table>(lua_state(), -1, handler);
#endif // Safety
}
template <typename T,
meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_lua_table>>, meta::neg<std::is_same<ref_t, stack_reference>>,
meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler>
basic_lua_table(T&& r) noexcept : basic_lua_table(detail::no_safety, std::forward<T>(r)) {
#if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES
if (!is_table<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this);
constructor_handler handler{};
stack::check<basic_lua_table>(lua_state(), -1, handler);
}
#endif // Safety
}
basic_lua_table(lua_nil_t r) noexcept : basic_lua_table(detail::no_safety, r) {
}
};
}
// end of sol/lua_table.hpp
namespace sol { namespace sol {
typedef table_core<false> table; typedef table_core<false> table;
@ -22878,6 +23061,109 @@ namespace sol {
// beginning of sol/state_handling.hpp // beginning of sol/state_handling.hpp
// beginning of sol/lua_value.hpp
namespace sol {
namespace detail {
template <typename T>
using is_reference_or_lua_value_init_list = meta::any<meta::is_specialization_of<T, std::initializer_list>, std::is_same<T, reference>>;
template <typename T>
using is_lua_value_single_constructible = meta::any<std::is_same<T, lua_value>, is_reference_or_lua_value_init_list<T>>;
}
struct lua_value {
private:
static lua_State*& thread_local_lua_state() {
static thread_local lua_State* L = nullptr;
return L;
}
reference ref_value;
public:
static void set_lua_state(lua_State* L) {
thread_local_lua_state() = L;
}
template <typename T, meta::disable<detail::is_reference_or_lua_value_init_list<meta::unqualified_t<T>>> = meta::enabler>
lua_value(lua_State* L_, T&& value) : lua_value(((set_lua_state(L_)), std::forward<T>(value))) {
}
template <typename T, meta::disable<detail::is_lua_value_single_constructible<meta::unqualified_t<T>>> = meta::enabler>
lua_value(T&& value) : ref_value(make_reference(thread_local_lua_state(), std::forward<T>(value))) {
}
lua_value(lua_State* L_, std::initializer_list<lua_value> il) : lua_value(((set_lua_state(L_)), std::move(il))) {
}
lua_value(std::initializer_list<lua_value> il) : ref_value(make_reference(thread_local_lua_state(), std::move(il))) {
}
lua_value(lua_State* L_, reference r) : lua_value(((thread_local_lua_state() = L_), std::move(r))) {
}
lua_value(reference r) : ref_value(std::move(r)) {
}
lua_value(const lua_value&) noexcept = default;
lua_value(lua_value&&) = default;
lua_value& operator=(const lua_value&) = default;
lua_value& operator=(lua_value&&) = default;
const reference& value() const& {
return ref_value;
}
reference& value() & {
return ref_value;
}
reference&& value() && {
return std::move(ref_value);
}
template <typename T>
decltype(auto) as() const {
ref_value.push();
return stack::pop<T>(ref_value.lua_state());
}
template <typename T>
bool is() const {
int r = ref_value.registry_index();
if (r == LUA_REFNIL)
return meta::any_same<meta::unqualified_t<T>, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false;
if (r == LUA_NOREF)
return false;
auto pp = stack::push_pop(ref_value);
return stack::check<T>(ref_value.lua_state(), -1, no_panic);
}
};
namespace stack {
template <>
struct unqualified_pusher<lua_value> {
static int push(lua_State* L, const lua_value& lv) {
return stack::push(L, lv.value());
}
static int push(lua_State* L, lua_value&& lv) {
return stack::push(L, std::move(lv).value());
}
};
template <>
struct unqualified_getter<lua_value> {
static lua_value get(lua_State* L, int index, record& tracking) {
return lua_value(L, stack::get<reference>(L, index, tracking));
}
};
}
} // namespace sol
// end of sol/lua_value.hpp
#if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS #if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS
#endif #endif
@ -22945,6 +23231,7 @@ namespace sol {
set_default_exception_handler(L, exf); set_default_exception_handler(L, exf);
register_main_thread(L); register_main_thread(L);
stack::luajit_exception_handler(L); stack::luajit_exception_handler(L);
lua_value::set_lua_state(L);
} }
inline std::size_t total_memory_used(lua_State* L) { inline std::size_t total_memory_used(lua_State* L) {

View File

@ -0,0 +1,26 @@
// 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.
#include "sol_defines.hpp"
#include <sol/lua_table.hpp>

View File

@ -0,0 +1,26 @@
// 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.
#include "sol_defines.hpp"
#include <sol/lua_value.hpp>

View File

@ -255,6 +255,7 @@ end
TEST_CASE("containers/sequence containers", "check all of the functinos for every single container") { TEST_CASE("containers/sequence containers", "check all of the functinos for every single container") {
SECTION("vector") { SECTION("vector") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
std::vector<int> items{ 11, 12, 13, 14, 15 }; std::vector<int> items{ 11, 12, 13, 14, 15 };
@ -263,6 +264,7 @@ TEST_CASE("containers/sequence containers", "check all of the functinos for ever
} }
SECTION("list") { SECTION("list") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
std::list<int> items{ 11, 12, 13, 14, 15 }; std::list<int> items{ 11, 12, 13, 14, 15 };
@ -271,6 +273,7 @@ TEST_CASE("containers/sequence containers", "check all of the functinos for ever
} }
SECTION("forward_list") { SECTION("forward_list") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
std::forward_list<int> items{ 11, 12, 13, 14, 15 }; std::forward_list<int> items{ 11, 12, 13, 14, 15 };
@ -279,6 +282,7 @@ TEST_CASE("containers/sequence containers", "check all of the functinos for ever
} }
SECTION("deque") { SECTION("deque") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
std::deque<int> items{ 11, 12, 13, 14, 15 }; std::deque<int> items{ 11, 12, 13, 14, 15 };
@ -290,6 +294,7 @@ TEST_CASE("containers/sequence containers", "check all of the functinos for ever
TEST_CASE("containers/fixed containers", "check immutable container types") { TEST_CASE("containers/fixed containers", "check immutable container types") {
SECTION("array") { SECTION("array") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
std::array<int, 5> items{ { 11, 12, 13, 14, 15 } }; std::array<int, 5> items{ { 11, 12, 13, 14, 15 } };
@ -298,6 +303,7 @@ TEST_CASE("containers/fixed containers", "check immutable container types") {
} }
SECTION("array ref") { SECTION("array ref") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
std::array<int, 5> items{ { 11, 12, 13, 14, 15 } }; std::array<int, 5> items{ { 11, 12, 13, 14, 15 } };
@ -306,6 +312,7 @@ TEST_CASE("containers/fixed containers", "check immutable container types") {
} }
SECTION("c array") { SECTION("c array") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
int items[5] = { 11, 12, 13, 14, 15 }; int items[5] = { 11, 12, 13, 14, 15 };
@ -314,6 +321,7 @@ TEST_CASE("containers/fixed containers", "check immutable container types") {
} }
SECTION("c array ref") { SECTION("c array ref") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
int items[5] = { 11, 12, 13, 14, 15 }; int items[5] = { 11, 12, 13, 14, 15 };
@ -324,6 +332,7 @@ TEST_CASE("containers/fixed containers", "check immutable container types") {
TEST_CASE("containers/auxiliary functions test", "make sure the manipulation functions are present and usable and working across various container types") { TEST_CASE("containers/auxiliary functions test", "make sure the manipulation functions are present and usable and working across various container types") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(); lua.open_libraries();
auto result1 = lua.safe_script(R"( auto result1 = lua.safe_script(R"(
@ -407,6 +416,8 @@ TEST_CASE("containers/indices test", "test indices on fixed array types") {
#if 0 #if 0
SECTION("zero index test") { SECTION("zero index test") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua["c_arr"] = std::array<int, 5>{ { 2, 4, 6, 8, 10 } }; lua["c_arr"] = std::array<int, 5>{ { 2, 4, 6, 8, 10 } };
auto result = lua.safe_script(R"( auto result = lua.safe_script(R"(
c_arr[0] = 7 c_arr[0] = 7
@ -416,6 +427,8 @@ c_arr[0] = 7
SECTION("negative index test") { SECTION("negative index test") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua["c_arr"] = std::array<int, 5>{ { 2, 4, 6, 8, 10 } }; lua["c_arr"] = std::array<int, 5>{ { 2, 4, 6, 8, 10 } };
auto result = lua.safe_script(R"( auto result = lua.safe_script(R"(
c_arr[-1] = 7 c_arr[-1] = 7

View File

@ -100,6 +100,8 @@ end
)"; )";
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base, sol::lib::coroutine); lua.open_libraries(sol::lib::base, sol::lib::coroutine);
auto result1 = lua.safe_script(script); auto result1 = lua.safe_script(script);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
@ -127,6 +129,8 @@ end
)"; )";
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base, sol::lib::coroutine); lua.open_libraries(sol::lib::base, sol::lib::coroutine);
auto result = lua.safe_script(code, sol::script_pass_on_error); auto result = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(result.valid()); REQUIRE(result.valid());
@ -146,6 +150,8 @@ end
TEST_CASE("coroutines/transfer", "test that things created inside of a coroutine can have their state transferred using lua_xmove constructors") { TEST_CASE("coroutines/transfer", "test that things created inside of a coroutine can have their state transferred using lua_xmove constructors") {
for (std::size_t tries = 0; tries < 200; ++tries) { for (std::size_t tries = 0; tries < 200; ++tries) {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(); lua.open_libraries();
{ {
sol::function f2; sol::function f2;

View File

@ -60,7 +60,7 @@ namespace sol {
namespace stack { namespace stack {
template <> template <>
struct unqualified_checker<two_things> { struct unqualified_checker<two_things, type::poly> {
template <typename Handler> 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) {
bool success = stack::check<int>(L, index, handler) && stack::check<bool>(L, index + 1, handler); bool success = stack::check<int>(L, index, handler) && stack::check<bool>(L, index + 1, handler);
@ -89,7 +89,7 @@ namespace sol {
}; };
template <> template <>
struct unqualified_checker<number_shim> { struct unqualified_checker<number_shim, type::poly> {
template <typename Handler> 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 (!check_usertype<number_shim>(L, index) && !stack::check<double>(L, index)) { if (!check_usertype<number_shim>(L, index) && !stack::check<double>(L, index)) {

View File

@ -25,19 +25,97 @@
#include <catch.hpp> #include <catch.hpp>
TEST_CASE("dump/dump transfer", "test that a function can be transferred from one place to another") { #include <list>
sol::state lua; #include <vector>
sol::state lua2; #include <deque>
lua2.open_libraries(sol::lib::base);
sol::load_result lr = lua.load("a = function (v) print(v) return v end"); int dump_always_fail_number = -32;
REQUIRE(lr.valid());
sol::protected_function target = lr;
sol::bytecode target_bc = target.dump();
auto result2 = lua2.safe_script(target_bc.as_string_view(), sol::script_pass_on_error); int dump_always_fail(lua_State*, const void*, size_t, void*) {
REQUIRE(result2.valid()); return dump_always_fail_number;
sol::protected_function pf = lua2["a"]; }
int v = pf(25557);
REQUIRE(v == 25557); TEST_CASE("dump/dump transfer", "test that a function can be transferred from one place to another") {
SECTION("safe") {
sol::state lua;
sol::state lua2;
lua2.open_libraries(sol::lib::base);
sol::load_result lr = lua.load("a = function (v) print(v) return v end");
REQUIRE(lr.valid());
sol::protected_function target = lr;
sol::bytecode target_bc = target.dump();
auto result2 = lua2.safe_script(target_bc.as_string_view(), sol::script_pass_on_error);
REQUIRE(result2.valid());
sol::protected_function pf = lua2["a"];
int v = pf(25557);
REQUIRE(v == 25557);
}
SECTION("unsafe") {
sol::state lua;
sol::state lua2;
lua2.open_libraries(sol::lib::base);
sol::load_result lr = lua.load("a = function (v) print(v) return v end");
REQUIRE(lr.valid());
sol::unsafe_function target = lr;
sol::bytecode target_bc = target.dump();
auto result2 = lua2.safe_script(target_bc.as_string_view(), sol::script_pass_on_error);
REQUIRE(result2.valid());
sol::unsafe_function pf = lua2["a"];
int v = pf(25557);
REQUIRE(v == 25557);
}
}
TEST_CASE("dump/failure", "test that failure is properly propagated") {
SECTION("safe") {
sol::state lua;
sol::load_result lr = lua.load("a = function (v) print(v) return v end");
REQUIRE(lr.valid());
sol::protected_function target = lr;
int err = target.dump(&dump_always_fail, nullptr, false, sol::dump_pass_on_error);
REQUIRE(err == dump_always_fail_number);
}
SECTION("unsafe") {
sol::state lua;
sol::load_result lr = lua.load("a = function (v) print(v) return v end");
REQUIRE(lr.valid());
sol::unsafe_function target = lr;
int err = target.dump(&dump_always_fail, nullptr, false, sol::dump_pass_on_error);
REQUIRE(err == dump_always_fail_number);
}
}
TEST_CASE("dump/different containers", "test that dump inserter works for various kinds of containers") {
SECTION("safe") {
sol::state lua;
sol::load_result lr = lua.load("a = function (v) print(v) return v end");
REQUIRE(lr.valid());
sol::protected_function target = lr;
sol::bytecode bytecode_dump = target.dump();
std::list<std::byte> list_dump = target.dump<std::list<std::byte>>();
std::vector<std::byte> vector_dump = target.dump<std::vector<std::byte>>();
std::deque<std::byte> deque_dump = target.dump<std::deque<std::byte>>();
REQUIRE(std::equal(bytecode_dump.cbegin(), bytecode_dump.cend(), vector_dump.cbegin(), vector_dump.cend()));
REQUIRE(std::equal(bytecode_dump.cbegin(), bytecode_dump.cend(), list_dump.cbegin(), list_dump.cend()));
REQUIRE(std::equal(bytecode_dump.cbegin(), bytecode_dump.cend(), deque_dump.cbegin(), deque_dump.cend()));
}
SECTION("unsafe") {
sol::state lua;
sol::load_result lr = lua.load("a = function (v) print(v) return v end");
REQUIRE(lr.valid());
sol::unsafe_function target = lr;
sol::bytecode bytecode_dump = target.dump();
std::list<std::byte> list_dump = target.dump<std::list<std::byte>>();
std::vector<std::byte> vector_dump = target.dump<std::vector<std::byte>>();
std::deque<std::byte> deque_dump = target.dump<std::deque<std::byte>>();
REQUIRE(std::equal(bytecode_dump.cbegin(), bytecode_dump.cend(), vector_dump.cbegin(), vector_dump.cend()));
REQUIRE(std::equal(bytecode_dump.cbegin(), bytecode_dump.cend(), list_dump.cbegin(), list_dump.cend()));
REQUIRE(std::equal(bytecode_dump.cbegin(), bytecode_dump.cend(), deque_dump.cbegin(), deque_dump.cend()));
}
} }

View File

@ -30,6 +30,7 @@
TEST_CASE("environments/get", "Envronments can be taken out of things like Lua functions properly") { TEST_CASE("environments/get", "Envronments can be taken out of things like Lua functions properly") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua); sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
auto result1 = lua.safe_script("f = function() return test end", sol::script_pass_on_error); auto result1 = lua.safe_script("f = function() return test end", sol::script_pass_on_error);
@ -62,7 +63,7 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
lua.set_function("check_f_env", lua.set_function("check_f_env",
[&lua, &env_f](sol::object target) { [&lua, &env_f](sol::object target) {
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
sol::environment target_env(sol::env_key, target); sol::environment target_env(sol::env_key, target);
int test_env_f = env_f["test"]; int test_env_f = env_f["test"];
int test_target_env = target_env["test"]; int test_target_env = target_env["test"];
@ -72,7 +73,7 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
}); });
lua.set_function("check_g_env", lua.set_function("check_g_env",
[&lua, &env_g](sol::function target) { [&lua, &env_g](sol::function target) {
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
sol::environment target_env = sol::get_environment(target); sol::environment target_env = sol::get_environment(target);
int test_env_g = env_g["test"]; int test_env_g = env_g["test"];
int test_target_env = target_env["test"]; int test_target_env = target_env["test"];
@ -82,7 +83,7 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
}); });
lua.set_function("check_h_env", lua.set_function("check_h_env",
[&lua](sol::function target) { [&lua](sol::function target) {
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
sol::environment target_env = sol::get_environment(target); sol::environment target_env = sol::get_environment(target);
}); });
@ -97,6 +98,8 @@ TEST_CASE("environments/get", "Envronments can be taken out of things like Lua f
TEST_CASE("environments/shadowing", "Environments can properly shadow and fallback on variables") { TEST_CASE("environments/shadowing", "Environments can properly shadow and fallback on variables") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua["b"] = 2142; lua["b"] = 2142;
SECTION("no fallback") { SECTION("no fallback") {
@ -179,6 +182,7 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
SECTION("basic") { SECTION("basic") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
auto result1 = lua.safe_script("a = function() return 5 end", sol::script_pass_on_error); auto result1 = lua.safe_script("a = function() return 5 end", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
@ -196,6 +200,7 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
} }
SECTION("return environment value") { SECTION("return environment value") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
auto result1 = lua.safe_script("a = function() return test end", sol::script_pass_on_error); auto result1 = lua.safe_script("a = function() return test end", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
@ -212,6 +217,8 @@ TEST_CASE("environments/functions", "see if environments on functions are workin
SECTION("set environment value") { SECTION("set environment value") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
auto result1 = lua.safe_script("a = function() test = 5 end", sol::script_pass_on_error); auto result1 = lua.safe_script("a = function() test = 5 end", sol::script_pass_on_error);
REQUIRE(result1.valid()); REQUIRE(result1.valid());
@ -235,6 +242,7 @@ TEST_CASE("environments/this_environment", "test various situations of pulling o
static std::string code = "return (f(10))"; static std::string code = "return (f(10))";
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua["f"] = [](sol::this_environment te, int x, sol::this_state ts) { lua["f"] = [](sol::this_environment te, int x, sol::this_state ts) {
if (te) { if (te) {

View File

@ -145,6 +145,8 @@ TEST_CASE("functions/tuple returns", "Make sure tuple returns are ordered proper
TEST_CASE("functions/overload resolution", "Check if overloaded function resolution templates compile/work") { TEST_CASE("functions/overload resolution", "Check if overloaded function resolution templates compile/work") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.set_function("non_overloaded", non_overloaded); lua.set_function("non_overloaded", non_overloaded);
@ -188,9 +190,9 @@ TEST_CASE("functions/return order and multi get", "Check if return order is in t
const static std::tuple<int, int, int> triple = std::make_tuple(10, 11, 12); const static std::tuple<int, int, int> triple = std::make_tuple(10, 11, 12);
const static std::tuple<int, float> paired = std::make_tuple(10, 10.f); const static std::tuple<int, float> paired = std::make_tuple(10, 10.f);
sol::state lua; sol::state lua;
lua.set_function("f", [] { sol::stack_guard luasg(lua);
return std::make_tuple(10, 11, 12);
}); lua.set_function("f", [] { return std::make_tuple(10, 11, 12); });
lua.set_function("h", []() { lua.set_function("h", []() {
return std::make_tuple(10, 10.0f); return std::make_tuple(10, 10.0f);
}); });
@ -260,8 +262,9 @@ end )", sol::script_pass_on_error);
TEST_CASE("functions/pair and tuple and proxy tests", "Check if sol::reference and sol::proxy can be passed to functions as arguments") { TEST_CASE("functions/pair and tuple and proxy tests", "Check if sol::reference and sol::proxy can be passed to functions as arguments") {
sol::state lua; sol::state lua;
lua.new_usertype<A>("A", sol::stack_guard luasg(lua);
"bark", &A::bark);
lua.new_usertype<A>("A", "bark", &A::bark);
auto result1 = lua.safe_script(R"( function f (num_value, a) auto result1 = lua.safe_script(R"( function f (num_value, a)
return num_value * 2, a:bark() return num_value * 2, a:bark()
end end
@ -302,6 +305,8 @@ nested = { variables = { no = { problem = 10 } } } )", sol::script_pass_on_error
TEST_CASE("functions/sol::function to std::function", "check if conversion to std::function works properly and calls with correct arguments") { TEST_CASE("functions/sol::function to std::function", "check if conversion to std::function works properly and calls with correct arguments") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.set_function("testFunc", test_free_func); lua.set_function("testFunc", test_free_func);
@ -336,12 +341,14 @@ TEST_CASE("functions/returning functions from C++", "check to see if returning a
} }
TEST_CASE("functions/function_result and protected_function_result", "Function result should be the beefy return type for sol::function that allows for error checking and error handlers") { TEST_CASE("functions/function_result and protected_function_result", "Function result should be the beefy return type for sol::function that allows for error checking and error handlers") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::debug);
static const char unhandlederrormessage[] = "true error message"; static const char unhandlederrormessage[] = "true error message";
static const char handlederrormessage[] = "doodle"; static const char handlederrormessage[] = "doodle";
static const std::string handlederrormessage_s = handlederrormessage; static const std::string handlederrormessage_s = handlederrormessage;
sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base, sol::lib::debug);
// Some function; just using a lambda to be cheap // Some function; just using a lambda to be cheap
auto doomfx = []() { auto doomfx = []() {
throw std::runtime_error(unhandlederrormessage); throw std::runtime_error(unhandlederrormessage);
@ -512,6 +519,7 @@ TEST_CASE("functions/unsafe protected_function_result handlers",
TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure they all compile and work") { TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure they all compile and work") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
struct test_1 { struct test_1 {
int a = 0xA; int a = 0xA;
@ -972,14 +980,14 @@ TEST_CASE("functions/stack atomic", "make sure functions don't impede on the sta
//test protected_function //test protected_function
sol::protected_function Stringtest(lua["stringtest"]); sol::protected_function Stringtest(lua["stringtest"]);
Stringtest.error_handler = lua["ErrorHandler"]; Stringtest.error_handler = lua["ErrorHandler"];
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
{ {
sol::protected_function_result stringresult = Stringtest("protected test"); sol::protected_function_result stringresult = Stringtest("protected test");
REQUIRE(stringresult.valid()); REQUIRE(stringresult.valid());
std::string s = stringresult; std::string s = stringresult;
INFO("Back in C++, protected result is : " << s); INFO("Back in C++, protected result is : " << s);
} }
REQUIRE(sg.check_stack()); REQUIRE(luasg.check_stack());
//test optional //test optional
{ {
@ -994,7 +1002,7 @@ TEST_CASE("functions/stack atomic", "make sure functions don't impede on the sta
INFO("opt_result failed"); INFO("opt_result failed");
} }
} }
REQUIRE(sg.check_stack()); REQUIRE(luasg.check_stack());
{ {
sol::protected_function_result errresult = Stringtest(sol::lua_nil); sol::protected_function_result errresult = Stringtest(sol::lua_nil);
@ -1003,7 +1011,7 @@ TEST_CASE("functions/stack atomic", "make sure functions don't impede on the sta
std::string msg = err.what(); std::string msg = err.what();
INFO("error :" << msg); INFO("error :" << msg);
} }
REQUIRE(sg.check_stack()); REQUIRE(luasg.check_stack());
} }
TEST_CASE("functions/stack multi-return", "Make sure the stack is protected after multi-returns") { TEST_CASE("functions/stack multi-return", "Make sure the stack is protected after multi-returns") {
@ -1011,7 +1019,7 @@ TEST_CASE("functions/stack multi-return", "Make sure the stack is protected afte
lua.safe_script("function f () return 1, 2, 3, 4, 5 end"); lua.safe_script("function f () return 1, 2, 3, 4, 5 end");
{ {
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
sol::stack::push(lua, double(256.78)); sol::stack::push(lua, double(256.78));
{ {
int a, b, c, d, e; int a, b, c, d, e;
@ -1034,7 +1042,7 @@ TEST_CASE("functions/protected stack multi-return", "Make sure the stack is prot
lua.safe_script("function f () return 1, 2, 3, 4, 5 end"); lua.safe_script("function f () return 1, 2, 3, 4, 5 end");
{ {
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
sol::stack::push(lua, double(256.78)); sol::stack::push(lua, double(256.78));
{ {
int a, b, c, d, e; int a, b, c, d, e;
@ -1060,7 +1068,7 @@ TEST_CASE("functions/function_result as arguments", "ensure that function_result
lua.safe_script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end"); lua.safe_script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end");
{ {
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
sol::stack::push(lua, double(256.78)); sol::stack::push(lua, double(256.78));
{ {
int a, b, c, d, e; int a, b, c, d, e;
@ -1089,7 +1097,7 @@ TEST_CASE("functions/protected_function_result as arguments", "ensure that prote
lua.safe_script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end"); lua.safe_script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end");
{ {
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
sol::stack::push(lua, double(256.78)); sol::stack::push(lua, double(256.78));
{ {
int a, b, c, d, e; int a, b, c, d, e;

View File

@ -0,0 +1,310 @@
// 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.
#include "sol_test.hpp"
#include <catch.hpp>
#include <vector>
#include <thread>
#include <mutex>
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#include <string_view>
#include <variant>
#endif // C++17
struct int_entry {
int value;
int_entry() : value(0) {
}
int_entry(int v) : value(v) {
}
bool operator==(const int_entry& e) const {
return value == e.value;
}
};
std::mutex lua_value_construct_require_mutex;
void lua_value_construct_race() {
sol::state lua;
try {
lua.open_libraries();
lua["a"] = sol::lua_value(lua, 24);
int a = lua["a"];
{
std::lock_guard<std::mutex> lg(lua_value_construct_require_mutex);
REQUIRE(a == 24);
}
}
catch (const sol::error& e) {
std::lock_guard<std::mutex> lg(lua_value_construct_require_mutex);
INFO(e.what());
REQUIRE(false);
}
catch (...) {
std::lock_guard<std::mutex> lg(lua_value_construct_require_mutex);
REQUIRE(false);
}
}
TEST_CASE("lua_value/nested", "make nested values can be put in lua_value properly") {
#if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT
using mixed_table_entry = std::variant<int, int_entry, std::string>;
using nested_entry = std::variant<int, int_entry, std::string, std::vector<mixed_table_entry>>;
const std::vector<std::variant<int, int_entry>> mixed_table_truth = { 1, int_entry(2), 3, int_entry(4), 5 };
const std::vector<nested_entry> mixed_nested_table_truth = { 1, int_entry(2), 3, int_entry(4), std::vector<mixed_table_entry>{ 5, 6, int_entry(7), "8" } };
sol::state lua;
sol::lua_value lv_mixed_table(lua, { 1, int_entry(2), 3, int_entry(4), 5 });
sol::lua_value lv_mixed_nested_table(lua, { 1, int_entry(2), 3, int_entry(4), { 5, 6, int_entry(7), "8" } });
REQUIRE(lv_mixed_table.is<sol::table>());
REQUIRE(lv_mixed_nested_table.is<sol::table>());
std::vector<std::variant<int, int_entry>> mixed_table_value_lv = lv_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
std::vector<nested_entry> mixed_nested_table_value_lv = lv_mixed_nested_table.as<std::vector<nested_entry>>();
REQUIRE(mixed_table_truth == mixed_table_value_lv);
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value_lv);
SECTION("type check (object)") {
sol::object obj_mixed_table(lv_mixed_table.value());
sol::object obj_mixed_nested_table(lv_mixed_nested_table.value());
REQUIRE(obj_mixed_table.is<sol::table>());
REQUIRE(obj_mixed_nested_table.is<sol::table>());
std::vector<std::variant<int, int_entry>> mixed_table_value = obj_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
std::vector<nested_entry> mixed_nested_table_value = obj_mixed_nested_table.as<std::vector<nested_entry>>();
REQUIRE(mixed_table_truth == mixed_table_value);
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value);
}
SECTION("pushing/popping") {
lua["obj_mixed_table"] = lv_mixed_table;
lua["obj_mixed_nested_table"] = lv_mixed_nested_table;
sol::lua_value obj_mixed_table = lua["obj_mixed_table"];
sol::lua_value obj_mixed_nested_table = lua["obj_mixed_nested_table"];
REQUIRE(obj_mixed_table.is<sol::table>());
REQUIRE(obj_mixed_nested_table.is<sol::table>());
std::vector<std::variant<int, int_entry>> mixed_table_value = obj_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
std::vector<nested_entry> mixed_nested_table_value = obj_mixed_nested_table.as<std::vector<nested_entry>>();
REQUIRE(mixed_table_truth == mixed_table_value);
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value);
}
SECTION("pushing/popping (object)") {
lua["obj_mixed_table"] = lv_mixed_table;
lua["obj_mixed_nested_table"] = lv_mixed_nested_table;
sol::object obj_mixed_table = lua["obj_mixed_table"];
sol::object obj_mixed_nested_table = lua["obj_mixed_nested_table"];
REQUIRE(obj_mixed_table.is<sol::table>());
REQUIRE(obj_mixed_nested_table.is<sol::table>());
std::vector<std::variant<int, int_entry>> mixed_table_value = obj_mixed_table.as<std::vector<std::variant<int, int_entry>>>();
std::vector<nested_entry> mixed_nested_table_value = obj_mixed_nested_table.as<std::vector<nested_entry>>();
REQUIRE(mixed_table_truth == mixed_table_value);
REQUIRE(mixed_nested_table_truth == mixed_nested_table_value);
}
#else
REQUIRE(true);
#endif // C++17
}
TEST_CASE("lua_value/basic types", "make sure we can stick values and nested values in a lua_value and retrieve them") {
sol::state lua;
const int_entry userdata_truth = int_entry(3);
const std::vector<int> int_table_truth = { 1, 2, 3, 4, 5 };
sol::lua_value lv_int(lua, 1);
sol::lua_value lv_double(lua, 2.0);
sol::lua_value lv_string(lua, "heyo");
sol::lua_value lv_lstring(lua, L"hiyo");
sol::lua_value lv_bool(lua, true);
sol::lua_value lv_nil(lua, sol::lua_nil);
sol::lua_value lv_userdata(lua, int_entry(3));
sol::lua_value lv_int_table(lua, { 1, 2, 3, 4, 5 });
REQUIRE(lv_int.is<int>());
REQUIRE(lv_double.is<double>());
REQUIRE(lv_string.is<std::string>());
REQUIRE(lv_lstring.is<std::string>());
REQUIRE(lv_bool.is<bool>());
REQUIRE(lv_nil.is<sol::lua_nil_t>());
REQUIRE(lv_userdata.is<sol::userdata>());
REQUIRE(lv_userdata.is<int_entry>());
REQUIRE(lv_int_table.is<sol::table>());
REQUIRE(lv_int.as<int>() == 1);
REQUIRE(lv_double.as<double>() == 2.0);
REQUIRE(lv_string.as<std::string>() == "heyo");
REQUIRE(lv_lstring.as<std::string>() == "hiyo");
REQUIRE(lv_lstring.as<std::wstring>() == L"hiyo");
REQUIRE(lv_bool.as<bool>());
REQUIRE(lv_nil.as<sol::lua_nil_t>() == sol::lua_nil);
REQUIRE(lv_userdata.as<int_entry>() == userdata_truth);
std::vector<int> int_table_value_lv = lv_int_table.as<std::vector<int>>();
REQUIRE(int_table_truth == int_table_value_lv);
SECTION("type check (object)") {
sol::object obj_int(lv_int.value());
sol::object obj_double(lv_double.value());
sol::object obj_string(lv_string.value());
sol::object obj_lstring(lv_lstring.value());
sol::object obj_bool(lv_bool.value());
sol::object obj_nil(lv_nil.value());
sol::object obj_userdata(lv_userdata.value());
sol::object obj_int_table(lv_int_table.value());
REQUIRE(obj_int.is<int>());
REQUIRE(obj_double.is<double>());
REQUIRE(obj_string.is<std::string>());
REQUIRE(obj_lstring.is<std::string>());
REQUIRE(obj_bool.is<bool>());
REQUIRE(obj_nil.is<sol::lua_nil_t>());
REQUIRE(obj_userdata.is<sol::userdata>());
REQUIRE(obj_userdata.is<int_entry>());
REQUIRE(obj_int_table.is<sol::table>());
REQUIRE(obj_int.as<int>() == 1);
REQUIRE(obj_double.as<double>() == 2.0);
REQUIRE(obj_string.as<std::string>() == "heyo");
REQUIRE(obj_lstring.as<std::string>() == "hiyo");
REQUIRE(obj_lstring.as<std::wstring>() == L"hiyo");
REQUIRE(obj_bool.as<bool>());
REQUIRE(obj_userdata.as<int_entry>() == userdata_truth);
REQUIRE(obj_nil.as<sol::lua_nil_t>() == sol::lua_nil);
std::vector<int> int_table_value = obj_int_table.as<std::vector<int>>();
REQUIRE(int_table_truth == int_table_value);
}
SECTION("push/popping") {
lua["obj_int"] = lv_int;
lua["obj_double"] = lv_double;
lua["obj_string"] = lv_string;
lua["obj_lstring"] = lv_lstring;
lua["obj_bool"] = lv_bool;
lua["obj_nil"] = lv_nil;
lua["obj_userdata"] = lv_userdata;
lua["obj_int_table"] = lv_int_table;
// these all actually invoke the constructor
// so do one .get<> explicitly to ensure it's
// working correctl for a few cases...
// but it's nice to make sure it's all there now
sol::lua_value obj_int = lua["obj_int"].get<sol::lua_value>();
sol::lua_value obj_double = lua["obj_double"].get<sol::lua_value>();
sol::lua_value obj_string = lua["obj_string"].get<sol::lua_value>();
sol::lua_value obj_lstring = lua["obj_lstring"].get<sol::lua_value>();
sol::lua_value obj_bool = lua["obj_bool"].get<sol::lua_value>();
sol::lua_value obj_nil = lua["obj_nil"];
sol::lua_value obj_userdata = lua["obj_userdata"];
sol::lua_value obj_int_table = lua["obj_int_table"];
REQUIRE(obj_int.is<int>());
REQUIRE(obj_double.is<double>());
REQUIRE(obj_string.is<std::string>());
REQUIRE(obj_lstring.is<std::string>());
REQUIRE(obj_bool.is<bool>());
REQUIRE(obj_nil.is<sol::lua_nil_t>());
REQUIRE(obj_int_table.is<sol::table>());
REQUIRE(obj_int.as<int>() == 1);
REQUIRE(obj_double.as<double>() == 2.0);
REQUIRE(obj_string.as<std::string>() == "heyo");
REQUIRE(obj_lstring.as<std::string>() == "hiyo");
REQUIRE(obj_lstring.as<std::wstring>() == L"hiyo");
REQUIRE(obj_bool.as<bool>());
REQUIRE(obj_nil.as<sol::lua_nil_t>() == sol::lua_nil);
std::vector<int> int_table_value = obj_int_table.as<std::vector<int>>();
REQUIRE(int_table_truth == int_table_value);
}
SECTION("push/popping (object)") {
lua["obj_int"] = lv_int;
lua["obj_double"] = lv_double;
lua["obj_string"] = lv_string;
lua["obj_lstring"] = lv_lstring;
lua["obj_bool"] = lv_bool;
lua["obj_nil"] = lv_nil;
lua["obj_userdata"] = lv_userdata;
lua["obj_int_table"] = lv_int_table;
sol::object obj_int = lua["obj_int"];
sol::object obj_double = lua["obj_double"];
sol::object obj_string = lua["obj_string"];
sol::object obj_lstring = lua["obj_lstring"];
sol::object obj_bool = lua["obj_bool"];
sol::object obj_nil = lua["obj_nil"];
sol::object obj_userdata = lua["obj_userdata"];
sol::object obj_int_table = lua["obj_int_table"];
REQUIRE(obj_int.is<int>());
REQUIRE(obj_double.is<double>());
REQUIRE(obj_string.is<std::string>());
REQUIRE(obj_lstring.is<std::string>());
REQUIRE(obj_bool.is<bool>());
REQUIRE(obj_nil.is<sol::lua_nil_t>());
REQUIRE(obj_userdata.is<sol::userdata>());
REQUIRE(obj_userdata.is<int_entry>());
REQUIRE(obj_int_table.is<sol::table>());
REQUIRE(obj_int.as<int>() == 1);
REQUIRE(obj_double.as<double>() == 2.0);
REQUIRE(obj_string.as<std::string>() == "heyo");
REQUIRE(obj_lstring.as<std::string>() == "hiyo");
REQUIRE(obj_lstring.as<std::wstring>() == L"hiyo");
REQUIRE(obj_bool.as<bool>());
REQUIRE(obj_nil.as<sol::lua_nil_t>() == sol::lua_nil);
REQUIRE(obj_userdata.as<int_entry>() == userdata_truth);
std::vector<int> int_table_value = obj_int_table.as<std::vector<int>>();
REQUIRE(int_table_truth == int_table_value);
}
}
TEST_CASE("lua_value/threading", "test that thread_local in lua_value constructors do not race or clobber") {
REQUIRE_NOTHROW([]() {
std::thread thrds[24];
for (int i = 0; i < 24; i++) {
thrds[i] = std::thread(&lua_value_construct_race);
}
for (int i = 0; i < 24; i++) {
thrds[i].join();
}
}());
}

View File

@ -152,7 +152,7 @@ TEST_CASE("state/require_script", "opening strings as 'requires' clauses") {
std::string code = "return { modfunc = function () return 221 end }"; std::string code = "return { modfunc = function () return 221 end }";
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
sol::table thingy1 = lua.require_script("thingy", code); sol::table thingy1 = lua.require_script("thingy", code);
sol::table thingy2 = lua.require_script("thingy", code); sol::table thingy2 = lua.require_script("thingy", code);
@ -173,7 +173,7 @@ TEST_CASE("state/require", "require using a function") {
}; };
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
sol::table thingy1 = lua.require("thingy", open::open_func); sol::table thingy1 = lua.require("thingy", open::open_func);
sol::table thingy2 = lua.require("thingy", open::open_func); sol::table thingy2 = lua.require("thingy", open::open_func);
@ -344,7 +344,7 @@ return example;
}; };
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
lua.open_libraries(); lua.open_libraries();
lua.set_function("foo", foo); lua.set_function("foo", foo);
@ -369,7 +369,7 @@ TEST_CASE("state/copy and move", "ensure state can be properly copied and moved"
TEST_CASE("state/requires-reload", "ensure that reloading semantics do not cause a crash") { TEST_CASE("state/requires-reload", "ensure that reloading semantics do not cause a crash") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
lua.open_libraries(); lua.open_libraries();
lua.safe_script("require 'io'\nreturn 'test1'"); lua.safe_script("require 'io'\nreturn 'test1'");
lua.require_script("test2", "require 'io'\nreturn 'test2'"); lua.require_script("test2", "require 'io'\nreturn 'test2'");
@ -400,7 +400,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
SECTION("script") { SECTION("script") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
int ar = lua.safe_script(good); int ar = lua.safe_script(good);
int a = lua["a"]; int a = lua["a"];
REQUIRE(a == 21); REQUIRE(a == 21);
@ -409,7 +409,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("unsafe_script") { SECTION("unsafe_script") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
int ar = lua.unsafe_script(good); int ar = lua.unsafe_script(good);
int a = lua["a"]; int a = lua["a"];
REQUIRE(a == 21); REQUIRE(a == 21);
@ -418,7 +418,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("script-handler") { SECTION("script-handler") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
auto errbs = lua.safe_script(bad_syntax, sol::script_pass_on_error); auto errbs = lua.safe_script(bad_syntax, sol::script_pass_on_error);
REQUIRE(!errbs.valid()); REQUIRE(!errbs.valid());
@ -435,7 +435,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("do_string") { SECTION("do_string") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
auto errbs = lua.do_string(bad_syntax); auto errbs = lua.do_string(bad_syntax);
REQUIRE(!errbs.valid()); REQUIRE(!errbs.valid());
@ -452,7 +452,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("load_string") { SECTION("load_string") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
auto errbsload = lua.load(bad_syntax); auto errbsload = lua.load(bad_syntax);
REQUIRE(!errbsload.valid()); REQUIRE(!errbsload.valid());
@ -475,7 +475,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("load") { SECTION("load") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
string_reader_load bssrl(bad_syntax); string_reader_load bssrl(bad_syntax);
void* vpbssrl = static_cast<void*>(&bssrl); void* vpbssrl = static_cast<void*>(&bssrl);
auto errbsload = lua.load(&string_reader, vpbssrl, bad_syntax); auto errbsload = lua.load(&string_reader, vpbssrl, bad_syntax);
@ -504,7 +504,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("load_string (text)") { SECTION("load_string (text)") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
auto errbsload = lua.load(bad_syntax, bad_syntax, sol::load_mode::text); auto errbsload = lua.load(bad_syntax, bad_syntax, sol::load_mode::text);
REQUIRE(!errbsload.valid()); REQUIRE(!errbsload.valid());
@ -527,7 +527,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("load (text)") { SECTION("load (text)") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
string_reader_load bssrl(bad_syntax); string_reader_load bssrl(bad_syntax);
void* vpbssrl = static_cast<void*>(&bssrl); void* vpbssrl = static_cast<void*>(&bssrl);
auto errbsload = lua.load(&string_reader, vpbssrl, bad_syntax, sol::load_mode::text); auto errbsload = lua.load(&string_reader, vpbssrl, bad_syntax, sol::load_mode::text);
@ -556,7 +556,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("script_file") { SECTION("script_file") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
int ar = lua.safe_script_file(file_good); int ar = lua.safe_script_file(file_good);
int a = lua["a"]; int a = lua["a"];
REQUIRE(a == 21); REQUIRE(a == 21);
@ -565,7 +565,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("unsafe_script_file") { SECTION("unsafe_script_file") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
int ar = lua.unsafe_script_file(file_good); int ar = lua.unsafe_script_file(file_good);
int a = lua["a"]; int a = lua["a"];
REQUIRE(a == 21); REQUIRE(a == 21);
@ -574,7 +574,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("script_file-handler") { SECTION("script_file-handler") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
auto errbs = lua.safe_script_file(file_bad_syntax, sol::script_pass_on_error); auto errbs = lua.safe_script_file(file_bad_syntax, sol::script_pass_on_error);
REQUIRE(!errbs.valid()); REQUIRE(!errbs.valid());
@ -591,7 +591,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("safe_script_file-handler") { SECTION("safe_script_file-handler") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
auto errbs = lua.safe_script_file(file_bad_syntax, sol::script_pass_on_error); auto errbs = lua.safe_script_file(file_bad_syntax, sol::script_pass_on_error);
REQUIRE(!errbs.valid()); REQUIRE(!errbs.valid());
@ -608,7 +608,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("do_file") { SECTION("do_file") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
auto errbs = lua.do_file(file_bad_syntax); auto errbs = lua.do_file(file_bad_syntax);
REQUIRE(!errbs.valid()); REQUIRE(!errbs.valid());
@ -625,7 +625,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("load_file") { SECTION("load_file") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
auto errbsload = lua.load_file(file_bad_syntax); auto errbsload = lua.load_file(file_bad_syntax);
REQUIRE(!errbsload.valid()); REQUIRE(!errbsload.valid());
@ -648,7 +648,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
} }
SECTION("load_file (text)") { SECTION("load_file (text)") {
sol::state lua; sol::state lua;
sol::stack_guard sg(lua); sol::stack_guard luasg(lua);
auto errbsload = lua.load_file(file_bad_syntax, sol::load_mode::text); auto errbsload = lua.load_file(file_bad_syntax, sol::load_mode::text);
REQUIRE(!errbsload.valid()); REQUIRE(!errbsload.valid());

View File

@ -36,6 +36,8 @@ end
)"; )";
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
{ {
auto r = lua.safe_script(code, sol::script_pass_on_error); auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());

View File

@ -41,6 +41,7 @@ namespace muh_namespace {
TEST_CASE("stack/strings", "test that strings can be roundtripped") { TEST_CASE("stack/strings", "test that strings can be roundtripped") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
static const char utf8str[] = "\xF0\x9F\x8D\x8C\x20\xE6\x99\xA5\x20\x46\x6F\x6F\x20\xC2\xA9\x20\x62\x61\x72\x20\xF0\x9D\x8C\x86\x20\x62\x61\x7A\x20\xE2\x98\x83\x20\x71\x75\x78"; static const char utf8str[] = "\xF0\x9F\x8D\x8C\x20\xE6\x99\xA5\x20\x46\x6F\x6F\x20\xC2\xA9\x20\x62\x61\x72\x20\xF0\x9D\x8C\x86\x20\x62\x61\x7A\x20\xE2\x98\x83\x20\x71\x75\x78";
static const char16_t utf16str[] = { 0xD83C, 0xDF4C, 0x20, 0x6665, 0x20, 0x46, 0x6F, 0x6F, 0x20, 0xA9, 0x20, 0x62, 0x61, 0x72, 0x20, 0xD834, 0xDF06, 0x20, 0x62, 0x61, 0x7A, 0x20, 0x2603, 0x20, 0x71, 0x75, 0x78, 0x00 }; static const char16_t utf16str[] = { 0xD83C, 0xDF4C, 0x20, 0x6665, 0x20, 0x46, 0x6F, 0x6F, 0x20, 0xA9, 0x20, 0x62, 0x61, 0x72, 0x20, 0xD834, 0xDF06, 0x20, 0x62, 0x61, 0x7A, 0x20, 0x2603, 0x20, 0x71, 0x75, 0x78, 0x00 };

View File

@ -0,0 +1,51 @@
// 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.
#include "sol_test.hpp"
#include <catch.hpp>
struct not_a_table_at_all {};
TEST_CASE("tables/lua_table", "check that lua_table accepts only lua-style tables, and not other types") {
sol::state lua;
lua["f"] = [](sol::lua_table lt) {
int x = lt["a"];
REQUIRE(x == 3);
};
lua["ud"] = not_a_table_at_all{};
auto result0 = lua.safe_script("t = { a = 3 }", sol::script_pass_on_error);
REQUIRE(result0.valid());
auto result1 = lua.safe_script("f(t)", sol::script_pass_on_error);
REQUIRE(result1.valid());
auto result2 = lua.safe_script("f(ud)", sol::script_pass_on_error);
REQUIRE_FALSE(result2.valid());
auto result3 = lua.safe_script("f(24)", sol::script_pass_on_error);
REQUIRE_FALSE(result3.valid());
auto result4 = lua.safe_script("f(nil)", sol::script_pass_on_error);
REQUIRE_FALSE(result4.valid());
auto result5 = lua.safe_script("f('bark')", sol::script_pass_on_error);
REQUIRE_FALSE(result5.valid());
}

View File

@ -42,61 +42,9 @@ struct object {
} }
}; };
int plop_xyz(int x, int y, std::string z) {
INFO(x << " " << y << " " << z);
return 11;
}
TEST_CASE("tables/as enums", "Making sure enums can be put in and gotten out as values") {
enum direction {
up,
down,
left,
right
};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua["direction"] = lua.create_table_with(
"up", direction::up,
"down", direction::down,
"left", direction::left,
"right", direction::right);
sol::object obj = lua["direction"]["up"];
bool isdir = obj.is<direction>();
REQUIRE(isdir);
auto dir = obj.as<direction>();
REQUIRE(dir == direction::up);
}
TEST_CASE("tables/as enum classes", "Making sure enums can be put in and gotten out as values") {
enum class direction {
up,
down,
left,
right
};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua["direction"] = lua.create_table_with(
"up", direction::up,
"down", direction::down,
"left", direction::left,
"right", direction::right);
sol::object obj = lua["direction"]["up"];
bool isdir = obj.is<direction>();
REQUIRE(isdir);
auto dir = obj.as<direction>();
REQUIRE(dir == direction::up);
}
TEST_CASE("tables/cleanup", "make sure tables leave the stack balanced") { TEST_CASE("tables/cleanup", "make sure tables leave the stack balanced") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(); lua.open_libraries();
auto f = [] { return 5; }; auto f = [] { return 5; };
@ -131,222 +79,6 @@ TEST_CASE("tables/nested cleanup", "make sure tables leave the stack balanced")
} }
} }
TEST_CASE("tables/new_enum", "Making sure enums can be put in and gotten out as values") {
enum class direction {
up,
down,
left,
right
};
SECTION("variadics") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_enum("direction",
"up", direction::up,
"down", direction::down,
"left", direction::left,
"right", direction::right);
direction d = lua["direction"]["left"];
REQUIRE(d == direction::left);
auto result = lua.safe_script("direction.left = 50", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
d = lua["direction"]["left"];
REQUIRE(d == direction::left);
}
SECTION("initializer_list") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_enum<direction>("direction", { { "up", direction::up }, { "down", direction::down }, { "left", direction::left }, { "right", direction::right } });
direction d = lua["direction"]["left"];
REQUIRE(d == direction::left);
auto result = lua.safe_script("direction.left = 50", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
d = lua["direction"]["left"];
REQUIRE(d == direction::left);
}
}
TEST_CASE("tables/for_each", "Testing the use of for_each to get values from a lua table") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.safe_script(
"arr = {\n"
"[0] = \"Hi\",\n"
"[1] = 123.45,\n"
"[2] = \"String value\",\n"
// Does nothing
//"[3] = nil,\n"
//"[nil] = 3,\n"
"[\"WOOF\"] = 123,\n"
"}");
sol::table tbl = lua["arr"];
std::size_t tablesize = 4;
std::size_t iterations = 0;
auto fx = [&iterations](sol::object key, sol::object value) {
++iterations;
sol::type keytype = key.get_type();
switch (keytype) {
case sol::type::number:
switch (key.as<int>()) {
case 0:
REQUIRE((value.as<std::string>() == "Hi"));
break;
case 1:
REQUIRE((value.as<double>() == 123.45));
break;
case 2:
REQUIRE((value.as<std::string>() == "String value"));
break;
case 3:
REQUIRE((value.is<sol::lua_nil_t>()));
break;
}
break;
case sol::type::string:
if (key.as<std::string>() == "WOOF") {
REQUIRE((value.as<double>() == 123));
}
break;
case sol::type::lua_nil:
REQUIRE((value.as<double>() == 3));
break;
default:
break;
}
};
auto fxpair = [&fx](std::pair<sol::object, sol::object> kvp) { fx(kvp.first, kvp.second); };
tbl.for_each(fx);
REQUIRE(iterations == tablesize);
iterations = 0;
tbl.for_each(fxpair);
REQUIRE(iterations == tablesize);
}
TEST_CASE("tables/for_each empty", "empty tables should not crash") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.safe_script("arr = {}");
sol::table tbl = lua["arr"];
REQUIRE(tbl.empty());
std::size_t tablesize = 0;
std::size_t iterations = 0;
auto fx = [&iterations](sol::object key, sol::object value) {
++iterations;
sol::type keytype = key.get_type();
switch (keytype) {
case sol::type::number:
switch (key.as<int>()) {
case 0:
REQUIRE((value.as<std::string>() == "Hi"));
break;
case 1:
REQUIRE((value.as<double>() == 123.45));
break;
case 2:
REQUIRE((value.as<std::string>() == "String value"));
break;
case 3:
REQUIRE((value.is<sol::lua_nil_t>()));
break;
}
break;
case sol::type::string:
if (key.as<std::string>() == "WOOF") {
REQUIRE((value.as<double>() == 123));
}
break;
case sol::type::lua_nil:
REQUIRE((value.as<double>() == 3));
break;
default:
break;
}
};
auto fxpair = [&fx](std::pair<sol::object, sol::object> kvp) { fx(kvp.first, kvp.second); };
tbl.for_each(fx);
REQUIRE(iterations == tablesize);
iterations = 0;
tbl.for_each(fxpair);
REQUIRE(iterations == tablesize);
iterations = 0;
for (const auto& kvp : tbl) {
fxpair(kvp);
++iterations;
}
REQUIRE(iterations == tablesize);
}
TEST_CASE("tables/iterators", "Testing the use of iteratrs to get values from a lua table") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.safe_script(
"arr = {\n"
"[0] = \"Hi\",\n"
"[1] = 123.45,\n"
"[2] = \"String value\",\n"
// Does nothing
//"[3] = nil,\n"
//"[nil] = 3,\n"
"[\"WOOF\"] = 123,\n"
"}");
sol::table tbl = lua["arr"];
std::size_t tablesize = 4;
std::size_t iterations = 0;
int begintop = 0;
int endtop = 0;
{
test_stack_guard s(lua.lua_state(), begintop, endtop);
for (auto& kvp : tbl) {
[&iterations](sol::object key, sol::object value) {
++iterations;
sol::type keytype = key.get_type();
switch (keytype) {
case sol::type::number:
switch (key.as<int>()) {
case 0:
REQUIRE((value.as<std::string>() == "Hi"));
break;
case 1:
REQUIRE((value.as<double>() == 123.45));
break;
case 2:
REQUIRE((value.as<std::string>() == "String value"));
break;
case 3:
REQUIRE((value.is<sol::lua_nil_t>()));
break;
}
break;
case sol::type::string:
if (key.as<std::string>() == "WOOF") {
REQUIRE((value.as<double>() == 123));
}
break;
case sol::type::lua_nil:
REQUIRE((value.as<double>() == 3));
break;
default:
break;
}
}(kvp.first, kvp.second);
}
}
REQUIRE(begintop == endtop);
REQUIRE(iterations == tablesize);
}
TEST_CASE("tables/variables", "Check if tables and variables work as intended") { TEST_CASE("tables/variables", "Check if tables and variables work as intended") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::os); lua.open_libraries(sol::lib::base, sol::lib::os);
@ -450,127 +182,6 @@ TEST_CASE("tables/function variables", "Check if tables and function calls work
REQUIRE_NOTHROW(run_script(lua)); REQUIRE_NOTHROW(run_script(lua));
} }
TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works properly") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.safe_script("foo = 20\nbar = \"hello world\"");
// basic retrieval
std::string bar = lua["bar"];
int foo = lua["foo"];
REQUIRE(bar == "hello world");
REQUIRE(foo == 20);
// test operator= for stringification
// errors due to ambiguous operators
bar = lua["bar"];
// basic setting
lua["bar"] = 20.4;
lua["foo"] = "goodbye";
// doesn't modify the actual values obviously.
REQUIRE(bar == "hello world");
REQUIRE(foo == 20);
// function setting
lua["test"] = plop_xyz;
{
auto result = lua.safe_script("assert(test(10, 11, \"hello\") == 11)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
// function retrieval
sol::function test = lua["test"];
REQUIRE(test.call<int>(10, 11, "hello") == 11);
// setting a lambda
lua["lamb"] = [](int x) {
return x * 2;
};
{
auto result = lua.safe_script("assert(lamb(220) == 440)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
// function retrieval of a lambda
sol::function lamb = lua["lamb"];
REQUIRE(lamb.call<int>(220) == 440);
// test const table retrieval
auto assert1 = [](const sol::table& t) {
std::string a = t["foo"];
double b = t["bar"];
REQUIRE(a == "goodbye");
REQUIRE(b == 20.4);
};
REQUIRE_NOTHROW(assert1(lua.globals()));
}
TEST_CASE("tables/operator[] valid", "Test if proxies on tables can lazily evaluate validity") {
sol::state lua;
bool isFullScreen = false;
auto fullscreennopers = lua["fullscreen"]["nopers"];
auto fullscreen = lua["fullscreen"];
REQUIRE_FALSE(fullscreennopers.valid());
REQUIRE_FALSE(fullscreen.valid());
lua["fullscreen"] = true;
REQUIRE_FALSE(fullscreennopers.valid());
REQUIRE(fullscreen.valid());
isFullScreen = lua["fullscreen"];
REQUIRE(isFullScreen);
lua["fullscreen"] = false;
REQUIRE_FALSE(fullscreennopers.valid());
REQUIRE(fullscreen.valid());
isFullScreen = lua["fullscreen"];
REQUIRE_FALSE(isFullScreen);
}
TEST_CASE("tables/operator[] optional", "Test if proxies on tables can lazily evaluate validity") {
sol::state lua;
sol::optional<int> test1 = lua["no_exist_yet"];
bool present = (bool)test1;
REQUIRE_FALSE(present);
lua["no_exist_yet"] = 262;
sol::optional<int> test2 = lua["no_exist_yet"];
present = (bool)test2;
REQUIRE(present);
REQUIRE(test2.value() == 262);
sol::optional<int> nope = lua["nope"]["kek"]["hah"];
auto nope2 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
present = (bool)nope;
REQUIRE_FALSE(present);
present = (bool)nope2;
REQUIRE_FALSE(present);
lua.create_named_table("nope", "kek", lua.create_table_with("hah", 1));
sol::optional<int> non_nope = lua["nope"]["kek"]["hah"].get<sol::optional<int>>();
sol::optional<int> non_nope2 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
present = (bool)non_nope;
REQUIRE(present);
present = (bool)non_nope2;
REQUIRE(present);
REQUIRE(non_nope.value() == 1);
REQUIRE(non_nope2.value() == 1);
INFO("Keys: nope, kek, hah");
lua.set(std::make_tuple("nope", "kek", "hah"), 35);
sol::optional<int> non_nope3 = lua["nope"]["kek"]["hah"].get<sol::optional<int>>();
sol::optional<int> non_nope4 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
present = (bool)non_nope3;
REQUIRE(present);
present = (bool)non_nope4;
REQUIRE(present);
REQUIRE(non_nope3.value() == 35);
REQUIRE(non_nope4.value() == 35);
}
TEST_CASE("tables/add", "Basic test to make sure the 'add' feature works") { TEST_CASE("tables/add", "Basic test to make sure the 'add' feature works") {
static const int sz = 120; static const int sz = 120;

View File

@ -0,0 +1,90 @@
// 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.
#include "sol_test.hpp"
#include <catch.hpp>
enum weak_direction { up, down, left, right };
enum class strong_direction { up, down, left, right };
TEST_CASE("tables/as enums", "Making sure enums can be put in and gotten out as values") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua["strong_direction"]
= lua.create_table_with("up", weak_direction::up, "down", weak_direction::down, "left", weak_direction::left, "right", weak_direction::right);
sol::object obj = lua["strong_direction"]["up"];
bool isdir = obj.is<weak_direction>();
REQUIRE(isdir);
auto dir = obj.as<weak_direction>();
REQUIRE(dir == weak_direction::up);
}
TEST_CASE("tables/as enum classes", "Making sure enums can be put in and gotten out as values") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua["strong_direction"]
= lua.create_table_with("up", strong_direction::up, "down", strong_direction::down, "left", strong_direction::left, "right", strong_direction::right);
sol::object obj = lua["strong_direction"]["up"];
bool isdir = obj.is<strong_direction>();
REQUIRE(isdir);
auto dir = obj.as<strong_direction>();
REQUIRE(dir == strong_direction::up);
}
TEST_CASE("tables/new_enum", "Making sure enums can be put in and gotten out as values") {
enum class strong_direction { up, down, left, right };
SECTION("variadics") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_enum("strong_direction", "up", strong_direction::up, "down", strong_direction::down, "left", strong_direction::left, "right", strong_direction::right);
strong_direction d = lua["strong_direction"]["left"];
REQUIRE(d == strong_direction::left);
auto result = lua.safe_script("strong_direction.left = 50", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
d = lua["strong_direction"]["left"];
REQUIRE(d == strong_direction::left);
}
SECTION("initializer_list") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_enum<strong_direction>(
"strong_direction", { { "up", strong_direction::up }, { "down", strong_direction::down }, { "left", strong_direction::left }, { "right", strong_direction::right } });
strong_direction d = lua["strong_direction"]["left"];
REQUIRE(d == strong_direction::left);
auto result = lua.safe_script("strong_direction.left = 50", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
d = lua["strong_direction"]["left"];
REQUIRE(d == strong_direction::left);
}
}

View File

@ -0,0 +1,151 @@
// 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.
#include "sol_test.hpp"
#include <catch.hpp>
int plop_xyz(int x, int y, std::string z) {
INFO(x << " " << y << " " << z);
return 11;
}
TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works properly") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.safe_script("foo = 20\nbar = \"hello world\"");
// basic retrieval
std::string bar = lua["bar"];
int foo = lua["foo"];
REQUIRE(bar == "hello world");
REQUIRE(foo == 20);
// test operator= for stringification
// errors due to ambiguous operators
bar = lua["bar"];
// basic setting
lua["bar"] = 20.4;
lua["foo"] = "goodbye";
// doesn't modify the actual values obviously.
REQUIRE(bar == "hello world");
REQUIRE(foo == 20);
// function setting
lua["test"] = plop_xyz;
{
auto result = lua.safe_script("assert(test(10, 11, \"hello\") == 11)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
// function retrieval
sol::function test = lua["test"];
REQUIRE(test.call<int>(10, 11, "hello") == 11);
// setting a lambda
lua["lamb"] = [](int x) { return x * 2; };
{
auto result = lua.safe_script("assert(lamb(220) == 440)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
// function retrieval of a lambda
sol::function lamb = lua["lamb"];
REQUIRE(lamb.call<int>(220) == 440);
// test const table retrieval
auto assert1 = [](const sol::table& t) {
std::string a = t["foo"];
double b = t["bar"];
REQUIRE(a == "goodbye");
REQUIRE(b == 20.4);
};
REQUIRE_NOTHROW(assert1(lua.globals()));
}
TEST_CASE("tables/operator[] valid", "Test if proxies on tables can lazily evaluate validity") {
sol::state lua;
bool isFullScreen = false;
auto fullscreennopers = lua["fullscreen"]["nopers"];
auto fullscreen = lua["fullscreen"];
REQUIRE_FALSE(fullscreennopers.valid());
REQUIRE_FALSE(fullscreen.valid());
lua["fullscreen"] = true;
REQUIRE_FALSE(fullscreennopers.valid());
REQUIRE(fullscreen.valid());
isFullScreen = lua["fullscreen"];
REQUIRE(isFullScreen);
lua["fullscreen"] = false;
REQUIRE_FALSE(fullscreennopers.valid());
REQUIRE(fullscreen.valid());
isFullScreen = lua["fullscreen"];
REQUIRE_FALSE(isFullScreen);
}
TEST_CASE("tables/operator[] optional", "Test if proxies on tables can lazily evaluate validity") {
sol::state lua;
sol::optional<int> test1 = lua["no_exist_yet"];
bool present = (bool)test1;
REQUIRE_FALSE(present);
lua["no_exist_yet"] = 262;
sol::optional<int> test2 = lua["no_exist_yet"];
present = (bool)test2;
REQUIRE(present);
REQUIRE(test2.value() == 262);
sol::optional<int> nope = lua["nope"]["kek"]["hah"];
auto nope2 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
present = (bool)nope;
REQUIRE_FALSE(present);
present = (bool)nope2;
REQUIRE_FALSE(present);
lua.create_named_table("nope", "kek", lua.create_table_with("hah", 1));
sol::optional<int> non_nope = lua["nope"]["kek"]["hah"].get<sol::optional<int>>();
sol::optional<int> non_nope2 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
present = (bool)non_nope;
REQUIRE(present);
present = (bool)non_nope2;
REQUIRE(present);
REQUIRE(non_nope.value() == 1);
REQUIRE(non_nope2.value() == 1);
INFO("Keys: nope, kek, hah");
lua.set(std::make_tuple("nope", "kek", "hah"), 35);
sol::optional<int> non_nope3 = lua["nope"]["kek"]["hah"].get<sol::optional<int>>();
sol::optional<int> non_nope4 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
present = (bool)non_nope3;
REQUIRE(present);
present = (bool)non_nope4;
REQUIRE(present);
REQUIRE(non_nope3.value() == 35);
REQUIRE(non_nope4.value() == 35);
}

View File

@ -29,6 +29,7 @@
TEST_CASE("tables/proxy override_value", "allow override_value by way of key") { TEST_CASE("tables/proxy override_value", "allow override_value by way of key") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base, sol::lib::io); lua.open_libraries(sol::lib::base, sol::lib::io);
sol::optional<int> not_there = lua["a"]["b"]["c"]; sol::optional<int> not_there = lua["a"]["b"]["c"];
@ -42,6 +43,7 @@ TEST_CASE("tables/proxy override_value", "allow override_value by way of key") {
TEST_CASE("tables/insertion override", "allow override all non-table values plus final value") { TEST_CASE("tables/insertion override", "allow override all non-table values plus final value") {
SECTION("traverse") { SECTION("traverse") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
sol::optional<int> not_there = lua["a"]["b"]["c"]; sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there)); REQUIRE_FALSE(static_cast<bool>(not_there));
@ -59,6 +61,7 @@ TEST_CASE("tables/insertion override", "allow override all non-table values plus
} }
SECTION("proxy") { SECTION("proxy") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
sol::optional<int> not_there = lua["a"]["b"]["c"]; sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there)); REQUIRE_FALSE(static_cast<bool>(not_there));
@ -76,6 +79,7 @@ TEST_CASE("tables/insertion override", "allow override all non-table values plus
} }
SECTION("complex proxy") { SECTION("complex proxy") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
sol::optional<int> not_there = lua["a"]["b"]["c"]; sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there)); REQUIRE_FALSE(static_cast<bool>(not_there));
@ -91,6 +95,7 @@ TEST_CASE("tables/insertion override", "allow override all non-table values plus
TEST_CASE("tables/insertion update_if_empty", "allow updating a value only if it's missing") { TEST_CASE("tables/insertion update_if_empty", "allow updating a value only if it's missing") {
SECTION("traverse") { SECTION("traverse") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
sol::optional<int> not_there = lua["a"]["b"]["c"]; sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there)); REQUIRE_FALSE(static_cast<bool>(not_there));
@ -101,6 +106,7 @@ TEST_CASE("tables/insertion update_if_empty", "allow updating a value only if it
} }
SECTION("proxy") { SECTION("proxy") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
sol::optional<int> not_there = lua["a"]["b"]["c"]; sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there)); REQUIRE_FALSE(static_cast<bool>(not_there));
@ -116,6 +122,7 @@ TEST_CASE("tables/insertion update_if_empty", "allow updating a value only if it
} }
SECTION("proxy invoker") { SECTION("proxy invoker") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
sol::optional<int> not_there = lua["a"]["b"]["c"]; sol::optional<int> not_there = lua["a"]["b"]["c"];
REQUIRE_FALSE(static_cast<bool>(not_there)); REQUIRE_FALSE(static_cast<bool>(not_there));

View File

@ -0,0 +1,202 @@
// 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.
#include "sol_test.hpp"
#include <catch.hpp>
TEST_CASE("tables/for_each", "Testing the use of for_each to get values from a lua table") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.safe_script(
"arr = {\n"
"[0] = \"Hi\",\n"
"[1] = 123.45,\n"
"[2] = \"String value\",\n"
// Does nothing
//"[3] = nil,\n"
//"[nil] = 3,\n"
"[\"WOOF\"] = 123,\n"
"}");
sol::table tbl = lua["arr"];
std::size_t tablesize = 4;
std::size_t iterations = 0;
auto fx = [&iterations](sol::object key, sol::object value) {
++iterations;
sol::type keytype = key.get_type();
switch (keytype) {
case sol::type::number:
switch (key.as<int>()) {
case 0:
REQUIRE((value.as<std::string>() == "Hi"));
break;
case 1:
REQUIRE((value.as<double>() == 123.45));
break;
case 2:
REQUIRE((value.as<std::string>() == "String value"));
break;
case 3:
REQUIRE((value.is<sol::lua_nil_t>()));
break;
}
break;
case sol::type::string:
if (key.as<std::string>() == "WOOF") {
REQUIRE((value.as<double>() == 123));
}
break;
case sol::type::lua_nil:
REQUIRE((value.as<double>() == 3));
break;
default:
break;
}
};
auto fxpair = [&fx](std::pair<sol::object, sol::object> kvp) { fx(kvp.first, kvp.second); };
tbl.for_each(fx);
REQUIRE(iterations == tablesize);
iterations = 0;
tbl.for_each(fxpair);
REQUIRE(iterations == tablesize);
}
TEST_CASE("tables/for_each empty", "empty tables should not crash") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.safe_script("arr = {}");
sol::table tbl = lua["arr"];
REQUIRE(tbl.empty());
std::size_t tablesize = 0;
std::size_t iterations = 0;
auto fx = [&iterations](sol::object key, sol::object value) {
++iterations;
sol::type keytype = key.get_type();
switch (keytype) {
case sol::type::number:
switch (key.as<int>()) {
case 0:
REQUIRE((value.as<std::string>() == "Hi"));
break;
case 1:
REQUIRE((value.as<double>() == 123.45));
break;
case 2:
REQUIRE((value.as<std::string>() == "String value"));
break;
case 3:
REQUIRE((value.is<sol::lua_nil_t>()));
break;
}
break;
case sol::type::string:
if (key.as<std::string>() == "WOOF") {
REQUIRE((value.as<double>() == 123));
}
break;
case sol::type::lua_nil:
REQUIRE((value.as<double>() == 3));
break;
default:
break;
}
};
auto fxpair = [&fx](std::pair<sol::object, sol::object> kvp) { fx(kvp.first, kvp.second); };
tbl.for_each(fx);
REQUIRE(iterations == tablesize);
iterations = 0;
tbl.for_each(fxpair);
REQUIRE(iterations == tablesize);
iterations = 0;
for (const auto& kvp : tbl) {
fxpair(kvp);
++iterations;
}
REQUIRE(iterations == tablesize);
}
TEST_CASE("tables/iterators", "Testing the use of iteratrs to get values from a lua table") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.safe_script(
"arr = {\n"
"[0] = \"Hi\",\n"
"[1] = 123.45,\n"
"[2] = \"String value\",\n"
// Does nothing
//"[3] = nil,\n"
//"[nil] = 3,\n"
"[\"WOOF\"] = 123,\n"
"}");
sol::table tbl = lua["arr"];
std::size_t tablesize = 4;
std::size_t iterations = 0;
int begintop = 0;
int endtop = 0;
{
test_stack_guard s(lua.lua_state(), begintop, endtop);
for (auto& kvp : tbl) {
[&iterations](sol::object key, sol::object value) {
++iterations;
sol::type keytype = key.get_type();
switch (keytype) {
case sol::type::number:
switch (key.as<int>()) {
case 0:
REQUIRE((value.as<std::string>() == "Hi"));
break;
case 1:
REQUIRE((value.as<double>() == 123.45));
break;
case 2:
REQUIRE((value.as<std::string>() == "String value"));
break;
case 3:
REQUIRE((value.is<sol::lua_nil_t>()));
break;
}
break;
case sol::type::string:
if (key.as<std::string>() == "WOOF") {
REQUIRE((value.as<double>() == 123));
}
break;
case sol::type::lua_nil:
REQUIRE((value.as<double>() == 3));
break;
default:
break;
}
}(kvp.first, kvp.second);
}
}
REQUIRE(begintop == endtop);
REQUIRE(iterations == tablesize);
}

View File

@ -30,6 +30,7 @@
TEST_CASE("usertype/usertype", "Show that we can create classes from usertype and use them") { TEST_CASE("usertype/usertype", "Show that we can create classes from usertype and use them") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
sol::usertype<fuser> lc = lua.new_usertype<fuser>("fuser", "add", &fuser::add, "add2", &fuser::add2); sol::usertype<fuser> lc = lua.new_usertype<fuser>("fuser", "add", &fuser::add, "add2", &fuser::add2);
@ -56,6 +57,7 @@ TEST_CASE("usertype/usertype", "Show that we can create classes from usertype an
TEST_CASE("usertype/usertype fundamentals", "Verify new_usertype registers basic member functions and a constructor") { TEST_CASE("usertype/usertype fundamentals", "Verify new_usertype registers basic member functions and a constructor") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.new_usertype<fuser>("fuser", "add", &fuser::add, "add2", &fuser::add2); lua.new_usertype<fuser>("fuser", "add", &fuser::add, "add2", &fuser::add2);

View File

@ -54,6 +54,7 @@ struct self_test {
TEST_CASE("usertype/self-referential usertype", "usertype classes must play nice when C++ object types are requested for C++ code") { TEST_CASE("usertype/self-referential usertype", "usertype classes must play nice when C++ object types are requested for C++ code") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_usertype<self_test>("test", "g", &self_test::g, "f", &self_test::f); lua.new_usertype<self_test>("test", "g", &self_test::g, "f", &self_test::f);
@ -68,6 +69,7 @@ TEST_CASE("usertype/self-referential usertype", "usertype classes must play nice
TEST_CASE("usertype/nonmember-functions", "let users set non-member functions that take unqualified T as first parameter to usertype") { TEST_CASE("usertype/nonmember-functions", "let users set non-member functions that take unqualified T as first parameter to usertype") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_usertype<giver>("giver", lua.new_usertype<giver>("giver",
@ -97,6 +99,8 @@ TEST_CASE("usertype/nonmember-functions", "let users set non-member functions th
TEST_CASE("usertype/abstract-base-class", "Ensure that abstract base classes and such can be registered") { TEST_CASE("usertype/abstract-base-class", "Ensure that abstract base classes and such can be registered") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.new_usertype<abstract_A>("A", "a", &abstract_A::a); lua.new_usertype<abstract_A>("A", "a", &abstract_A::a);
lua.new_usertype<abstract_B>("B", sol::base_classes, sol::bases<abstract_A>()); lua.new_usertype<abstract_B>("B", sol::base_classes, sol::bases<abstract_A>());
REQUIRE_NOTHROW([&]() { REQUIRE_NOTHROW([&]() {
@ -114,7 +118,9 @@ TEST_CASE("usertype/as_function", "Ensure that variables can be turned into func
}; };
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(); lua.open_libraries();
lua.new_usertype<B>("B", "b", &B::bvar, "f", sol::as_function(&B::bvar)); lua.new_usertype<B>("B", "b", &B::bvar, "f", sol::as_function(&B::bvar));
B b; B b;
@ -137,6 +143,7 @@ TEST_CASE("usertype/call-initializers", "Ensure call constructors with initializ
}; };
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(); lua.open_libraries();
lua.new_usertype<A>("A", lua.new_usertype<A>("A",
@ -153,6 +160,7 @@ TEST_CASE("usertype/missing-key", "make sure a missing key returns nil") {
struct thing {}; struct thing {};
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_usertype<thing>("thing"); lua.new_usertype<thing>("thing");
@ -169,6 +177,7 @@ TEST_CASE("usertype/basic type information", "check that we can query some basic
struct my_thing {}; struct my_thing {};
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_usertype<my_thing>("my_thing"); lua.new_usertype<my_thing>("my_thing");
@ -210,9 +219,8 @@ TEST_CASE("usertype/noexcept-methods", "make sure noexcept functions and methods
}; };
sol::state lua; sol::state lua;
lua.new_usertype<T>("T", sol::stack_guard luasg(lua);
"nf", &T::noexcept_function, lua.new_usertype<T>("T", "nf", &T::noexcept_function, "nm", &T::noexcept_method);
"nm", &T::noexcept_method);
lua.safe_script("t = T.new()"); lua.safe_script("t = T.new()");
lua.safe_script("v1 = t.nf()"); lua.safe_script("v1 = t.nf()");

View File

@ -30,6 +30,7 @@
TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as member variables for usertype") { TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as member variables for usertype") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
sol::constructors<sol::types<float, float, float>> ctor; sol::constructors<sol::types<float, float, float>> ctor;
sol::usertype<Vec> udata sol::usertype<Vec> udata
@ -57,7 +58,6 @@ TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as
sol::function f; sol::function f;
}; };
lua.open_libraries(sol::lib::base);
lua.set("b", breaks()); lua.set("b", breaks());
lua.new_usertype<breaks>("breaks", "f", &breaks::f); lua.new_usertype<breaks>("breaks", "f", &breaks::f);
@ -90,6 +90,8 @@ TEST_CASE("usertype/reference-and-constness", "Make sure constness compiles prop
}; };
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.new_usertype<woof>("woof", "b", &woof::b); lua.new_usertype<woof>("woof", "b", &woof::b);
lua.new_usertype<bark>("bark", "var", &bark::var); lua.new_usertype<bark>("bark", "var", &bark::var);
lua.new_usertype<outer>("outer", "n", &outer::n); lua.new_usertype<outer>("outer", "n", &outer::n);

View File

@ -40,6 +40,7 @@ struct overloading_test {
TEST_CASE("usertype/overloading", "Check if overloading works properly for usertypes") { TEST_CASE("usertype/overloading", "Check if overloading works properly for usertypes") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_usertype<woof>("woof", "var", &woof::var, "func", sol::overload(&woof::func, &woof::func2, &woof::func2s)); lua.new_usertype<woof>("woof", "var", &woof::var, "func", sol::overload(&woof::func, &woof::func2, &woof::func2s));
@ -61,6 +62,7 @@ TEST_CASE("usertype/overloading", "Check if overloading works properly for usert
TEST_CASE("usertype/overloading_values", "ensure overloads handle properly") { TEST_CASE("usertype/overloading_values", "ensure overloads handle properly") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.new_usertype<overloading_test>("overloading_test", lua.new_usertype<overloading_test>("overloading_test",
sol::constructors<>(), sol::constructors<>(),
"print", "print",

View File

@ -105,7 +105,9 @@ TEST_CASE("usertype/properties", "Check if member properties/variables work") {
}; };
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_usertype<bark>("bark", lua.new_usertype<bark>("bark",
"var", "var",
&bark::var, &bark::var,
@ -172,6 +174,8 @@ TEST_CASE("usertype/copyability", "make sure user can write to a class variable
}; };
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.new_usertype<NoCopy>("NoCopy", "val", sol::property(&NoCopy::get, &NoCopy::set)); lua.new_usertype<NoCopy>("NoCopy", "val", sol::property(&NoCopy::get, &NoCopy::set));
REQUIRE_NOTHROW(lua.safe_script(R"__( REQUIRE_NOTHROW(lua.safe_script(R"__(
@ -217,6 +221,7 @@ TEST_CASE("usertype/static-properties", "allow for static functions to get and s
test_t manager; test_t manager;
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.new_usertype<test_t>( lua.new_usertype<test_t>(
"test", "f", std::function<std::size_t()>(std::bind(std::mem_fn(&test_t::func), &manager)), "g", sol::property(&test_t::s_func, &test_t::g_func)); "test", "f", std::function<std::size_t()>(std::bind(std::mem_fn(&test_t::func), &manager)), "g", sol::property(&test_t::s_func, &test_t::g_func));
@ -241,6 +246,7 @@ TEST_CASE("usertype/var-and-property", "make sure const vars are readonly and pr
}; };
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(); lua.open_libraries();
lua.new_usertype<test>( lua.new_usertype<test>(
@ -394,6 +400,8 @@ TEST_CASE("usertype/alignment", "ensure that alignment does not trigger weird al
struct aligned_derived : aligned_base {}; struct aligned_derived : aligned_base {};
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
auto f = [](aligned_base&, float d) { REQUIRE(d == 5.0f); }; auto f = [](aligned_base&, float d) { REQUIRE(d == 5.0f); };
lua.new_usertype<aligned_base>("Base", "x", sol::writeonly_property(weird_aligned_wrapper<aligned_base>(std::ref(f)))); lua.new_usertype<aligned_base>("Base", "x", sol::writeonly_property(weird_aligned_wrapper<aligned_base>(std::ref(f))));
lua.new_usertype<aligned_derived>("Derived", sol::base_classes, sol::bases<aligned_base>()); lua.new_usertype<aligned_derived>("Derived", sol::base_classes, sol::bases<aligned_base>());

View File

@ -29,10 +29,10 @@
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#ifdef SOL_CXX17_FEATURES #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#include <string_view> #include <string_view>
#include <variant> #include <variant>
#endif #endif // C++17
std::mutex basic_init_require_mutex; std::mutex basic_init_require_mutex;
@ -109,6 +109,7 @@ TEST_CASE("utility/variant", "test that variant can be round-tripped") {
TEST_CASE("utility/optional-conversion", "test that regular optional will properly catch certain types") { TEST_CASE("utility/optional-conversion", "test that regular optional will properly catch certain types") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_usertype<vars>("vars"); lua.new_usertype<vars>("vars");
@ -129,6 +130,7 @@ TEST_CASE("utility/std optional", "test that shit optional can be round-tripped"
#ifdef SOL_CXX17_FEATURES #ifdef SOL_CXX17_FEATURES
SECTION("okay") { SECTION("okay") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.set_function("f", [](int v) { lua.set_function("f", [](int v) {
@ -149,6 +151,7 @@ TEST_CASE("utility/std optional", "test that shit optional can be round-tripped"
} }
SECTION("throws") { SECTION("throws") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.set_function("f", [](int v) { lua.set_function("f", [](int v) {
@ -169,6 +172,8 @@ TEST_CASE("utility/std optional", "test that shit optional can be round-tripped"
} }
SECTION("in classes") { SECTION("in classes") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
struct opt_c { struct opt_c {
@ -194,6 +199,7 @@ TEST_CASE("utility/std optional", "test that shit optional can be round-tripped"
TEST_CASE("utility/string_view", "test that string_view can be taken as an argument") { TEST_CASE("utility/string_view", "test that string_view can be taken as an argument") {
#ifdef SOL_CXX17_FEATURES #ifdef SOL_CXX17_FEATURES
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.set_function("f", [](std::string_view v) { lua.set_function("f", [](std::string_view v) {
@ -224,6 +230,8 @@ TEST_CASE("utility/thread", "fire up lots of threads at the same time to make su
TEST_CASE("utility/pointer", "check we can get pointer value from references") { TEST_CASE("utility/pointer", "check we can get pointer value from references") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.set_function("f", [](bool aorb, sol::reference a, sol::stack_reference b) { lua.set_function("f", [](bool aorb, sol::reference a, sol::stack_reference b) {
if (aorb) { if (aorb) {
return a.pointer(); return a.pointer();
@ -259,6 +267,8 @@ TEST_CASE("utility/this_state", "Ensure this_state argument can be gotten anywhe
}; };
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
INFO("created lua state"); INFO("created lua state");
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.new_usertype<bark>("bark", lua.new_usertype<bark>("bark",
@ -290,6 +300,7 @@ TEST_CASE("utility/this_state", "Ensure this_state argument can be gotten anywhe
TEST_CASE("safety/check_stack", "check to make sure that if we overflow the stack in safety mode, we get the appropriate error thrown") { TEST_CASE("safety/check_stack", "check to make sure that if we overflow the stack in safety mode, we get the appropriate error thrown") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua["okay"] = []() { lua["okay"] = []() {

View File

@ -37,7 +37,9 @@ TEST_CASE("variadics/variadic_args", "Check to see we can receive multiple argum
}; };
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.open_libraries(sol::lib::base); lua.open_libraries(sol::lib::base);
lua.set_function("v", [](sol::this_state, sol::variadic_args va) -> structure { lua.set_function("v", [](sol::this_state, sol::variadic_args va) -> structure {
int r = 0; int r = 0;
for (auto v : va) { for (auto v : va) {
@ -83,6 +85,7 @@ TEST_CASE("variadics/required with variadic_args", "Check if a certain number of
TEST_CASE("variadics/variadic_args get type", "Make sure we can inspect types proper from variadic_args") { TEST_CASE("variadics/variadic_args get type", "Make sure we can inspect types proper from variadic_args") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.set_function("f", [](sol::variadic_args va) { lua.set_function("f", [](sol::variadic_args va) {
sol::type types[] = { sol::type types[] = {
@ -108,6 +111,7 @@ TEST_CASE("variadics/variadic_args get type", "Make sure we can inspect types pr
TEST_CASE("variadics/variadic_results", "returning a variable amount of arguments from C++") { TEST_CASE("variadics/variadic_results", "returning a variable amount of arguments from C++") {
SECTION("as_returns - containers") { SECTION("as_returns - containers") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.set_function("f", []() { lua.set_function("f", []() {
std::set<std::string> results{ "arf", "bark", "woof" }; std::set<std::string> results{ "arf", "bark", "woof" };
@ -139,17 +143,17 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument
} }
SECTION("variadic_results - variadic_args") { SECTION("variadic_results - variadic_args") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.set_function("f", [](sol::variadic_args args) { lua.set_function("f", [](sol::variadic_args args) {
return sol::variadic_results(args.cbegin(), args.cend()); return sol::variadic_results(args.cbegin(), args.cend());
}); });
REQUIRE_NOTHROW([&]() { auto result1 = lua.safe_script(R"(
lua.safe_script(R"( v1, v2, v3 = f(1, 'bark', true)
v1, v2, v3 = f(1, 'bark', true) v4, v5 = f(25, 82)
v4, v5 = f(25, 82) )", sol::script_pass_on_error);
)"); REQUIRE(result1.valid());
}());
int v1 = lua["v1"]; int v1 = lua["v1"];
std::string v2 = lua["v2"]; std::string v2 = lua["v2"];
@ -165,6 +169,7 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument
} }
SECTION("variadic_results") { SECTION("variadic_results") {
sol::state lua; sol::state lua;
sol::stack_guard luasg(lua);
lua.set_function("f", [](sol::this_state ts, bool maybe) { lua.set_function("f", [](sol::this_state ts, bool maybe) {
if (maybe) { if (maybe) {
@ -184,12 +189,11 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument
} }
}); });
REQUIRE_NOTHROW([&]() { auto result1 = lua.safe_script(R"(
lua.safe_script(R"( v1, v2, v3 = f(true)
v1, v2, v3 = f(true) v4, v5, v6, v7 = f(false)
v4, v5, v6, v7 = f(false) )", sol::script_pass_on_error);
)"); REQUIRE(result1.valid());
}());
int v1 = lua["v1"]; int v1 = lua["v1"];
int v2 = lua["v2"]; int v2 = lua["v2"];
@ -232,13 +236,15 @@ TEST_CASE("variadics/fallback_constructor", "ensure constructor matching behaves
} }
return res; })); return res; }));
REQUIRE_NOTHROW([&]() { auto result1 = lua.safe_script("v0 = vec2x();", sol::script_pass_on_error);
lua.safe_script("v0 = vec2x();"); auto result2 = lua.safe_script("v1 = vec2x(1);", sol::script_pass_on_error);
lua.safe_script("v1 = vec2x(1);"); auto result3 = lua.safe_script("v2 = vec2x(1, 2);", sol::script_pass_on_error);
lua.safe_script("v2 = vec2x(1, 2);"); auto result4 = lua.safe_script("v3 = vec2x(v2)", sol::script_pass_on_error);
lua.safe_script("v3 = vec2x(v2)"); REQUIRE(result1.valid());
}()); REQUIRE(result2.valid());
REQUIRE(result3.valid());
REQUIRE(result4.valid());
vec2x& v0 = lua["v0"]; vec2x& v0 = lua["v0"];
vec2x& v1 = lua["v1"]; vec2x& v1 = lua["v1"];
vec2x& v2 = lua["v2"]; vec2x& v2 = lua["v2"];