diff --git a/sol/function.hpp b/sol/function.hpp index 5bf3789d..7309e5bf 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -32,22 +32,23 @@ #include namespace sol { -class function : public reference { +template +class basic_function : public base_t { private: void luacall( std::ptrdiff_t argcount, std::ptrdiff_t resultcount ) const { - lua_callk( lua_state( ), static_cast( argcount ), static_cast( resultcount ), 0, nullptr ); + lua_callk( base_t::lua_state( ), static_cast( argcount ), static_cast( resultcount ), 0, nullptr ); } template auto invoke( types, std::index_sequence, std::ptrdiff_t n ) const { luacall( n, sizeof...( Ret ) ); - return stack::pop>( lua_state( ) ); + return stack::pop>( base_t::lua_state( ) ); } template Ret invoke(types, std::index_sequence, std::ptrdiff_t n ) const { luacall( n, 1 ); - return stack::pop( lua_state( ) ); + return stack::pop( base_t::lua_state( ) ); } template @@ -56,21 +57,21 @@ private: } function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n ) const { - int stacksize = lua_gettop( lua_state( ) ); + int stacksize = lua_gettop( base_t::lua_state( ) ); int firstreturn = std::max( 1, stacksize - static_cast( n ) ); luacall(n, LUA_MULTRET); - int poststacksize = lua_gettop( lua_state( ) ); + int poststacksize = lua_gettop( base_t::lua_state( ) ); int returncount = poststacksize - (firstreturn - 1); - return function_result( lua_state( ), firstreturn, returncount ); + return function_result( base_t::lua_state( ), firstreturn, returncount ); } public: - function() = default; - function(const function&) = default; - function& operator=(const function&) = default; - function( function&& ) = default; - function& operator=( function&& ) = default; - function(lua_State* L, int index = -1): reference(L, index) { + basic_function() = default; + basic_function(const basic_function&) = default; + basic_function& operator=(const basic_function&) = default; + basic_function(basic_function&& ) = default; + basic_function& operator=(basic_function&& ) = default; + basic_function(lua_State* L, int index = -1): base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS type_assert(L, index, type::function); #endif // Safety @@ -88,8 +89,8 @@ public: template decltype(auto) call( Args&&... args ) const { - push( ); - int pushcount = stack::multi_push( lua_state( ), std::forward( args )... ); + base_t::push( ); + int pushcount = stack::multi_push( base_t::lua_state( ), std::forward( args )... ); return invoke( types( ), std::make_index_sequence(), pushcount ); } }; diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 4531381e..6c67421f 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -103,7 +103,7 @@ struct pusher> { template static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef meta::Bool, std::reference_wrapper>::value || std::is_pointer::value> is_reference; + typedef meta::Bool>::value || std::is_pointer::value> is_reference; select_reference_member_variable(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); } @@ -141,7 +141,7 @@ struct pusher> { template static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef meta::Bool, std::reference_wrapper>::value || std::is_pointer::value> is_reference; + typedef meta::Bool>::value || std::is_pointer::value> is_reference; select_reference_member_function(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); } diff --git a/sol/function_types_allocator.hpp b/sol/function_types_allocator.hpp index 922197a0..1869b72e 100644 --- a/sol/function_types_allocator.hpp +++ b/sol/function_types_allocator.hpp @@ -45,7 +45,7 @@ struct constructor_match { template int operator()(types, Index, types r, types a, lua_State* L, int, int start) const { default_construct func{}; - return stack::call_into_lua<0, false>(r, a, func, L, start, obj); + return stack::call_into_lua<0, false>(r, a, L, start, func, obj); } }; } // detail @@ -115,7 +115,7 @@ struct usertype_constructor_function : base_function { userdataref.pop(); auto& func = std::get(overloads); - stack::call_into_lua(r, a, func, L, start, function_detail::implicit_wrapper(obj)); + stack::call_into_lua(r, a, L, start, func, function_detail::implicit_wrapper(obj)); userdataref.push(); luaL_getmetatable(L, &meta[0]); diff --git a/sol/function_types_basic.hpp b/sol/function_types_basic.hpp index 23beaf56..3638b575 100644 --- a/sol/function_types_basic.hpp +++ b/sol/function_types_basic.hpp @@ -34,7 +34,7 @@ struct upvalue_free_function { static int real_call(lua_State* L) { auto udata = stack::stack_detail::get_as_upvalues(L); function_type* fx = udata.first; - int r = stack::call_into_lua(meta::tuple_types(), typename traits_type::args_type(), fx, L, 1); + int r = stack::call_into_lua(meta::tuple_types(), typename traits_type::args_type(), L, 1, fx); return r; } @@ -65,7 +65,7 @@ struct upvalue_member_function { auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type { return (item.*memfx)(std::forward(args)...); }; - return stack::call_into_lua(meta::tuple_types(), typename traits_type::args_type(), fx, L, 1); + return stack::call_into_lua(meta::tuple_types(), typename traits_type::args_type(), L, 1, fx); } static int call (lua_State* L) { @@ -124,11 +124,11 @@ struct upvalue_this_member_function { // idx 1...n: verbatim data of member variable pointer auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); function_type& memfx = memberdata.first; - auto fx = [&memfx](lua_State* L, auto&&... args) -> typename traits_type::return_type { + auto fx = [&L, &memfx](auto&&... args) -> typename traits_type::return_type { auto& item = stack::get(L, 1); return (item.*memfx)(std::forward(args)...); }; - int n = stack::call_into_lua<1>(meta::tuple_types(), typename traits_type::args_type(), fx, L, 2, L); + int n = stack::call_into_lua<1>(meta::tuple_types(), typename traits_type::args_type(), L, 2, fx); return n; } diff --git a/sol/function_types_core.hpp b/sol/function_types_core.hpp index 18dc9af3..cb208e96 100644 --- a/sol/function_types_core.hpp +++ b/sol/function_types_core.hpp @@ -97,19 +97,19 @@ struct functor::va } template - void call(types, Arg&& arg) { + void call(Arg&& arg) { T& member = *item; (member.*invocation) = std::forward(arg); } - return_type call(types) { + return_type& call() { T& member = *item; return (member.*invocation); } template - auto operator()(Args&&... args) -> decltype(std::declval().call(types{}, std::forward(args)...)) { - return this->call(types{}, std::forward(args)...); + decltype(auto) operator()(Args&&... args) { + return this->call(std::forward(args)...); } }; diff --git a/sol/function_types_member.hpp b/sol/function_types_member.hpp index 29dd6bd0..ed8cc4ab 100644 --- a/sol/function_types_member.hpp +++ b/sol/function_types_member.hpp @@ -38,7 +38,7 @@ struct functor_function : public base_function { functor_function(Args&&... args): fx(std::forward(args)...) {} int call(lua_State* L) { - return stack::call_into_lua(meta::tuple_types(), args_types(), fx, L, 1); + return stack::call_into_lua(meta::tuple_types(), args_types(), L, 1, fx); } virtual int operator()(lua_State* L) override { @@ -70,7 +70,7 @@ struct member_function : public base_function { member_function(F&& f, Args&&... args) : fx(std::forward(f), std::forward(args)...) {} int call(lua_State* L) { - return stack::call_into_lua(meta::tuple_types(), args_types(), fx, L, 1); + return stack::call_into_lua(meta::tuple_types(), args_types(), L, 1, fx); } virtual int operator()(lua_State* L) override { @@ -86,21 +86,39 @@ struct member_variable : public base_function { typedef typename meta::bind_traits::args_type args_types; function_type var; T member; + typedef std::add_lvalue_reference_t>> M; - template - member_variable(Fx&& fx, Args&&... args): var(std::forward(fx)), member(std::forward(args)...) {} + template + member_variable(V&& v, Args&&... args): var(std::forward(v)), member(std::forward(args)...) {} + + int set_assignable(std::false_type, lua_State* L, M) { + lua_pop(L, 1); + return luaL_error(L, "cannot write to this type: copy assignment/constructor not available"); + } + + int set_assignable(std::true_type, lua_State* L, M mem) { + (mem.*var) = stack::get(L, 1); + lua_pop(L, 1); + return 0; + } + + int set_variable(std::true_type, lua_State* L, M mem) { + return set_assignable(std::is_assignable, return_type>(), L, mem); + } + + int set_variable(std::false_type, lua_State* L, M) { + lua_pop(L, 1); + return luaL_error(L, "cannot write to a const variable"); + } int call(lua_State* L) { - auto& mem = detail::unwrap(detail::deref(member)); + M mem = detail::unwrap(detail::deref(member)); switch (lua_gettop(L)) { - case 0: { + case 0: stack::push(L, (mem.*var)); - return 1; - } + return 1; case 1: - (mem.*var) = stack::get(L, 1); - lua_pop(L, 1); - return 0; + return set_variable(meta::Not>(), L, mem); default: return luaL_error(L, "sol: incorrect number of arguments to member variable function"); } diff --git a/sol/function_types_overload.hpp b/sol/function_types_overload.hpp index e3f73cc0..19295975 100644 --- a/sol/function_types_overload.hpp +++ b/sol/function_types_overload.hpp @@ -92,7 +92,7 @@ struct overloaded_function : base_function { template int call(types, Index, types r, types a, lua_State* L, int, int start) { auto& func = std::get(overloads); - return stack::call_into_lua<0, false>(r, a, func, L, start); + return stack::call_into_lua<0, false>(r, a, L, start, func); } virtual int operator()(lua_State* L) override { @@ -113,7 +113,7 @@ struct usertype_overloaded_function : base_function { int call(types, Index, types r, types a, lua_State* L, int, int start) { auto& func = std::get(overloads); func.item = detail::ptr(stack::get(L, 1)); - return stack::call_into_lua<0, false>(r, a, func, L, start); + return stack::call_into_lua<0, false>(r, a, L, start, func); } virtual int operator()(lua_State* L) override { diff --git a/sol/function_types_templated.hpp b/sol/function_types_templated.hpp index 11efa73f..a209154e 100644 --- a/sol/function_types_templated.hpp +++ b/sol/function_types_templated.hpp @@ -34,6 +34,30 @@ namespace function_detail { return stack::call_into_lua(return_type(), args_type(), fx, L, 1); } + template + inline int call_set_assignable(std::false_type, T&&, lua_State* L) { + lua_pop(L, 2); + return luaL_error(L, "cannot write to this type: copy assignment/constructor not available"); + } + + template + inline int call_set_assignable(std::true_type, lua_State* L, T&& mem) { + (mem.*variable) = stack::get(L, 2); + lua_pop(L, 2); + return 0; + } + + template + inline int call_set_variable(std::false_type, lua_State* L, T&&) { + lua_pop(L, 2); + return luaL_error(L, "cannot write to a const variable"); + } + + template + inline int call_set_variable(std::true_type, lua_State* L, T&& mem) { + return call_set_assignable(std::is_assignable, R>(), L, std::forward(mem)); + } + template inline int call_wrapper_variable(std::true_type, lua_State* L) { typedef meta::bind_traits> traits_type; @@ -41,14 +65,13 @@ namespace function_detail { typedef typename traits_type::return_type R; auto& mem = stack::get(L, 1); switch (lua_gettop(L)) { - case 1: + case 1: { + decltype(auto) r = (mem.*variable); lua_pop(L, 1); - stack::push(L, (mem.*variable)); - return 1; + stack::push_reference(L, std::forward(r)); + return 1; } case 2: - (mem.*variable) = stack::get(L, 2); - lua_pop(L, 2); - return 0; + return call_set_variable(meta::Not>(), L, mem); default: return luaL_error(L, "incorrect number of arguments to member variable function call"); } @@ -70,7 +93,7 @@ namespace function_detail { auto& member = stack::get(L, 1); return (member.*fx)(std::forward(args)...); }; - int n = stack::call_into_lua<1>(return_type_list(), args_type(), mfx, L, 2); + int n = stack::call_into_lua<1>(return_type_list(), args_type(), L, 2, mfx); return n; } diff --git a/sol/function_types_usertype.hpp b/sol/function_types_usertype.hpp index 67c84508..115fcf7a 100644 --- a/sol/function_types_usertype.hpp +++ b/sol/function_types_usertype.hpp @@ -55,17 +55,17 @@ struct usertype_function_core : public base_function { // without allocating an extra userdata, apparently! return 1; } - return stack::push(L, std::forward(r)); + return stack::push_reference(L, std::forward(r)); } template> std::enable_if_t::value, int> push(lua_State* L, Return&& r) { - return stack::push(L, std::forward(r)); + return stack::push_reference(L, std::forward(r)); } template int operator()(types tr, types ta, Index, lua_State* L) { - stack::call(tr, ta, L, static_cast(Start), fx); + stack::call_into_lua(tr, ta, L, static_cast(Start), fx); int nargs = static_cast(sizeof...(Args)); lua_pop(L, nargs); return 0; @@ -113,6 +113,24 @@ struct usertype_variable_function : public usertype_function_core template usertype_variable_function(Args&&... args): base_t(std::forward(args)...) {} + int set_assignable(std::false_type, lua_State* L) { + lua_pop(L, 2); + return luaL_error(L, "cannot write to this type: copy assignment/constructor not available"); + } + + int set_assignable(std::true_type, lua_State* L) { + return static_cast(*this)(meta::tuple_types(), args_type(), Index<3>(), L); + } + + int set_variable(std::false_type, lua_State* L) { + lua_pop(L, 2); + return luaL_error(L, "cannot write to a const variable"); + } + + int set_variable(std::true_type, lua_State* L) { + return set_assignable(std::is_assignable, return_type>(), L); + } + int prelude(lua_State* L) { int argcount = lua_gettop(L); this->fx.item = stack::get(L, 1); @@ -120,7 +138,7 @@ struct usertype_variable_function : public usertype_function_core case 2: return static_cast(*this)(meta::tuple_types(), types<>(), Index<2>(), L); case 3: - return static_cast(*this)(meta::tuple_types(), args_type(), Index<3>(), L); + return set_variable(meta::Not>(), L); default: return luaL_error(L, "sol: cannot get/set userdata member variable with inappropriate number of arguments"); } diff --git a/sol/object.hpp b/sol/object.hpp index eeb8067b..e25d4dfb 100644 --- a/sol/object.hpp +++ b/sol/object.hpp @@ -27,23 +27,46 @@ #include "stack.hpp" namespace sol { -class object : public reference { -public: - using reference::reference; +template +class basic_object : public base_t { +private: + template + decltype(auto) as_stack(std::true_type) const { + return stack::get(lua_state(), base_t::stack_index()); + } template - decltype(auto) as() const { - push(); + decltype(auto) as_stack(std::false_type) const { + base_t::push(); return stack::pop(lua_state()); } template - bool is() const { - if (!valid()) - return false; + bool is_stack(std::true_type) const { + return stack::check(lua_state(), base_t::stack_index(), no_panic); + } + + template + bool is_stack(std::false_type) const { auto pp = stack::push_pop(*this); return stack::check(lua_state(), -1, no_panic); } + +public: + using base_t::base_t; + using base_t::lua_state; + + template + decltype(auto) as() const { + return as_stack( std::is_same() ); + } + + template + bool is() const { + if (!base_t::valid()) + return false; + return is_stack(std::is_same()); + } }; inline bool operator==(const object& lhs, const nil_t&) { diff --git a/sol/protected_function.hpp b/sol/protected_function.hpp index 83e4ce59..981498f1 100644 --- a/sol/protected_function.hpp +++ b/sol/protected_function.hpp @@ -28,7 +28,8 @@ #include namespace sol { -class protected_function : public reference { +template +class basic_protected_function : public base_t { private: static reference& handler_storage() { static sol::reference h; @@ -62,19 +63,19 @@ private: }; int luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, handler& h) const { - return lua_pcallk(lua_state(), static_cast(argcount), static_cast(resultcount), h.stackindex, 0, nullptr); + return lua_pcallk(base_t::lua_state(), static_cast(argcount), static_cast(resultcount), h.stackindex, 0, nullptr); } template auto invoke(types, std::index_sequence, std::ptrdiff_t n, handler& h) const { luacall(n, sizeof...(Ret), h); - return stack::pop>(lua_state()); + return stack::pop>(base_t::lua_state()); } template Ret invoke(types, std::index_sequence, std::ptrdiff_t n, handler& h) const { luacall(n, 1, h); - return stack::pop(lua_state()); + return stack::pop(base_t::lua_state()); } template @@ -83,7 +84,7 @@ private: } protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, handler& h) const { - int stacksize = lua_gettop(lua_state()); + int stacksize = lua_gettop(base_t::lua_state()); int firstreturn = std::max(1, stacksize - static_cast(n) - 1); int returncount = 0; call_status code = call_status::ok; @@ -92,49 +93,49 @@ private: h.stackindex = 0; if (h.target.valid()) { h.target.push(); - stack::push(lua_state(), error); - lua_call(lua_state(), 1, 1); + stack::push(base_t::lua_state(), error); + lua_call(base_t::lua_state(), 1, 1); } else { - stack::push(lua_state(), error); + stack::push(base_t::lua_state(), error); } }; try { #endif // No Exceptions code = static_cast(luacall(n, LUA_MULTRET, h)); - int poststacksize = lua_gettop(lua_state()); + int poststacksize = lua_gettop(base_t::lua_state()); returncount = poststacksize - (stacksize - 1); #ifndef SOL_NO_EXCEPTIONS } // Handle C++ errors thrown from C++ functions bound inside of lua catch (const char* error) { onexcept(error); - firstreturn = lua_gettop(lua_state()); - return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + firstreturn = lua_gettop(base_t::lua_state()); + return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime); } catch (const std::exception& error) { onexcept(error.what()); - firstreturn = lua_gettop(lua_state()); - return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + firstreturn = lua_gettop(base_t::lua_state()); + return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime); } catch (...) { onexcept("caught (...) unknown error during protected_function call"); - firstreturn = lua_gettop(lua_state()); - return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); + firstreturn = lua_gettop(base_t::lua_state()); + return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime); } #endif // No Exceptions - return protected_function_result(lua_state(), firstreturn, returncount, returncount, code); + return protected_function_result(base_t::lua_state(), firstreturn, returncount, returncount, code); } public: reference error_handler; - protected_function() = default; - protected_function(const protected_function&) = default; - protected_function& operator=(const protected_function&) = default; - protected_function( protected_function&& ) = default; - protected_function& operator=( protected_function&& ) = default; - protected_function(lua_State* L, int index = -1): reference(L, index), error_handler(get_default_handler()) { + basic_protected_function() = default; + basic_protected_function(const basic_protected_function&) = default; + basic_protected_function& operator=(const basic_protected_function&) = default; + basic_protected_function(basic_protected_function&& ) = default; + basic_protected_function& operator=(basic_protected_function&& ) = default; + basic_protected_function(lua_State* L, int index = -1): base_t(L, index), error_handler(get_default_handler()) { #ifdef SOL_CHECK_ARGUMENTS type_assert(L, index, type::function); #endif // Safety @@ -153,8 +154,8 @@ public: template decltype(auto) call(Args&&... args) const { handler h(error_handler); - push(); - int pushcount = stack::multi_push(lua_state(), std::forward(args)...); + base_t::push(); + int pushcount = stack::multi_push(base_t::lua_state(), std::forward(args)...); return invoke(types(), std::make_index_sequence(), pushcount, h); } }; diff --git a/sol/proxy.hpp b/sol/proxy.hpp index 985f5eb5..3a9b92bb 100644 --- a/sol/proxy.hpp +++ b/sol/proxy.hpp @@ -32,7 +32,7 @@ namespace sol { template struct proxy : public proxy_base> { private: - typedef meta::If, Key, std::tuple>, Key&, meta::Unqualified>>> key_type; + typedef meta::If, Key, std::tuple>, Key&, meta::Unqualified>>> key_type; template decltype(auto) tuple_get(std::index_sequence) const { diff --git a/sol/reference.hpp b/sol/reference.hpp index 24693c5b..226464ac 100644 --- a/sol/reference.hpp +++ b/sol/reference.hpp @@ -23,6 +23,7 @@ #define SOL_REFERENCE_HPP #include "types.hpp" +#include "stack_reference.hpp" namespace sol { namespace stack { @@ -65,9 +66,14 @@ protected: ref = luaL_ref(L, LUA_REGISTRYINDEX); } + int stack_index() const noexcept { + return -1; + } + public: reference() noexcept = default; - + reference(const stack_reference& r) noexcept : reference(r.lua_state(), r.stack_index()) {} + reference(stack_reference&& r) noexcept : reference(r.lua_state(), r.stack_index()) {} reference(lua_State* L, int index = -1) noexcept : L(L) { lua_pushvalue(L, index); ref = luaL_ref(L, LUA_REGISTRYINDEX); diff --git a/sol/stack.hpp b/sol/stack.hpp index 2812100a..8bdc147e 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -68,7 +68,7 @@ inline std::pair get_as_upvalues(lua_State* L, int index = 1) { } template ::value>> -inline R call(types, types ta, std::index_sequence tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { +inline decltype(auto) call(types, types ta, std::index_sequence tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { check_types{}.check(ta, tai, L, start, type_panic); return fx(std::forward(args)..., stack_detail::unchecked_get(L, start + I)...); } @@ -103,13 +103,13 @@ inline void remove( lua_State* L, int index, int count ) { } template ::value>> -inline R call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { +inline decltype(auto) call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { typedef typename types::indices args_indices; return stack_detail::call(tr, ta, args_indices(), L, start, std::forward(fx), std::forward(args)...); } template ::value>> -inline R call(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { +inline decltype(auto) call(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { return call(tr, ta, L, 1, std::forward(fx), std::forward(args)...); } @@ -125,7 +125,7 @@ inline void call(types tr, types ta, lua_State* L, Fx&& fx, FxArg } template ::value>> -inline R call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { +inline decltype(auto) call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { return call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); } @@ -135,16 +135,16 @@ inline void call_from_top(types tr, types ta, lua_State* L, Fx&& } template -inline int call_into_lua(types tr, types ta, Fx&& fx, lua_State* L, int start, FxArgs&&... fxargs) { - call(tr, ta, L, start, fx, std::forward(fxargs)...); +inline int call_into_lua(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { + call(tr, ta, L, start, std::forward(fx), std::forward(fxargs)...); int nargs = static_cast(sizeof...(Args)) + additionalpop; lua_pop(L, nargs); return 0; } template>::value>> -inline int call_into_lua(types, types ta, Fx&& fx, lua_State* L, int start, FxArgs&&... fxargs) { - decltype(auto) r = call(types>(), ta, L, start, fx, std::forward(fxargs)...); +inline int call_into_lua(types, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { + decltype(auto) r = call(types>(), ta, L, start, std::forward(fx), std::forward(fxargs)...); int nargs = static_cast(sizeof...(Args)) + additionalpop; lua_pop(L, nargs); return push(L, std::forward(r)); diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index 9462f9d7..a7ca4c63 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -182,8 +182,7 @@ struct checker { if (meta::Or, std::is_same>::value) return true; if (lua_getmetatable(L, index) == 0) { - handler(L, index, type::userdata, indextype); - return false; + return true; } if (stack_detail::check_metatable(L)) return true; diff --git a/sol/stack_core.hpp b/sol/stack_core.hpp index e139e5c2..f4e0c180 100644 --- a/sol/stack_core.hpp +++ b/sol/stack_core.hpp @@ -32,6 +32,8 @@ namespace sol { namespace detail { +struct as_reference_tag{}; + using special_destruct_func = void(*)(void*); template @@ -134,6 +136,16 @@ inline int multi_push(lua_State* L, T&& t, Args&&... args) { return pushcount; } +template +inline int push_reference(lua_State* L, T&& t, Args&&... args) { + typedef meta::And< + std::is_lvalue_reference, + meta::Not>, + meta::Not> + > use_reference_tag; + return pusher>>{}.push(L, std::forward(t), std::forward(args)...); +} + template bool check(lua_State* L, int index, Handler&& handler) { typedef meta::Unqualified Tu; diff --git a/sol/stack_get.hpp b/sol/stack_get.hpp index cf4207de..29ef5ef1 100644 --- a/sol/stack_get.hpp +++ b/sol/stack_get.hpp @@ -69,6 +69,13 @@ struct getter::value>> { } }; +template +struct getter::value>> { + static T get(lua_State* L, int index = -1) { + return T(L, index); + } +}; + template<> struct getter { static stack_reference get(lua_State* L, int index = -1) { @@ -143,9 +150,9 @@ struct getter { template<> struct getter { - static c_closure get(lua_State* L, int index = -1) { - return c_closure(lua_tocfunction(L, index), -1); - } + static c_closure get(lua_State* L, int index = -1) { + return c_closure(lua_tocfunction(L, index), -1); + } }; template<> diff --git a/sol/stack_guard.hpp b/sol/stack_guard.hpp index ebfe50f3..a02f1977 100644 --- a/sol/stack_guard.hpp +++ b/sol/stack_guard.hpp @@ -34,7 +34,7 @@ inline void stack_fail(int, int) { #else // Lol, what do you want, an error printout? :3c // There's no sane default here. The right way would be C-style abort(), and that's not acceptable, so - // hopefully someone will register their own stack_fail thing here + // hopefully someone will register their own stack_fail thing for the `fx` parameter of stack_guard. #endif // No Exceptions } } // detail @@ -42,16 +42,16 @@ inline void stack_fail(int, int) { struct stack_guard { lua_State* L; int top; - std::function fx; + std::function on_mismatch; stack_guard(lua_State* L) : stack_guard(L, lua_gettop(L)) {} - stack_guard(lua_State* L, int top, std::function fx = detail::stack_fail) : L(L), top(top), fx(std::move(fx)) {} + stack_guard(lua_State* L, int top, std::function fx = detail::stack_fail) : L(L), top(top), on_mismatch(std::move(fx)) {} ~stack_guard() { int bottom = lua_gettop(L); if (top == bottom) { return; } - fx(top, bottom); + on_mismatch(top, bottom); } }; } // sol diff --git a/sol/stack_pop.hpp b/sol/stack_pop.hpp index 9f22d379..11eff7b9 100644 --- a/sol/stack_pop.hpp +++ b/sol/stack_pop.hpp @@ -55,6 +55,11 @@ struct popper> { return r; } }; + +template +struct popper>::value>> { + static_assert(meta::Not>>::value, "You cannot pop something that derives from stack_reference: it will not remain on the stack and thusly will go out of scope!"); +}; } // stack } // sol diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index 7199079f..6a09d648 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -50,6 +50,14 @@ struct pusher { } }; +template <> +struct pusher { + template + static int push(lua_State* L, T&& obj) { + return stack::push(L, detail::ptr(obj)); + } +}; + template struct pusher { static int push(lua_State* L, T* obj) { diff --git a/sol/stack_reference.hpp b/sol/stack_reference.hpp index 3209250d..1debc401 100644 --- a/sol/stack_reference.hpp +++ b/sol/stack_reference.hpp @@ -22,8 +22,6 @@ #ifndef SOL_STACK_REFERENCE_HPP #define SOL_STACK_REFERENCE_HPP -#include "reference.hpp" - namespace sol { class stack_reference { private: @@ -31,6 +29,9 @@ private: int index = 0; protected: + int registry_index () const noexcept { + return LUA_NOREF; + } public: stack_reference() noexcept = default; @@ -45,6 +46,10 @@ public: return 1; } + int stack_index () const noexcept { + return index; + } + type get_type() const noexcept { int result = lua_type(L, index); return static_cast(result); diff --git a/sol/state.hpp b/sol/state.hpp index 681bb0e7..06d2221c 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -25,11 +25,28 @@ #include "state_view.hpp" namespace sol { +inline int default_at_panic(lua_State* L) { +#ifdef SOL_NO_EXCEPTIONS + (void)L; + return -1; +#else + const char* message = lua_tostring(L, -1); + std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic"; + throw error(err); +#endif +} + class state : private std::unique_ptr, public state_view { private: typedef std::unique_ptr unique_base; public: - state(lua_CFunction panic = detail::atpanic) : unique_base(luaL_newstate(), lua_close), + state(lua_CFunction panic = default_at_panic) : unique_base(luaL_newstate(), lua_close), + state_view(unique_base::get()) { + set_panic(panic); + stack::luajit_exception_handler(unique_base::get()); + } + + state(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr) : unique_base(lua_newstate(alfunc, alpointer), lua_close), state_view(unique_base::get()) { set_panic(panic); stack::luajit_exception_handler(unique_base::get()); diff --git a/sol/state_view.hpp b/sol/state_view.hpp index 14302abb..c42f3c1f 100644 --- a/sol/state_view.hpp +++ b/sol/state_view.hpp @@ -27,19 +27,6 @@ #include namespace sol { -namespace detail { -inline int atpanic(lua_State* L) { -#ifdef SOL_NO_EXCEPTIONS - (void)L; - return -1; -#else - const char* message = lua_tostring(L, -1); - std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic"; - throw error(err); -#endif -} -} // detail - enum class lib : char { base, package, @@ -60,6 +47,9 @@ private: table reg; global_table global; public: + typedef typename global_table::iterator iterator; + typedef typename global_table::const_iterator const_iterator; + state_view(lua_State* L): L(L), reg(L, LUA_REGISTRYINDEX), @@ -152,19 +142,19 @@ public: } } - table_iterator begin () const { + iterator begin () const { return global.begin(); } - table_iterator end() const { + iterator end() const { return global.end(); } - table_iterator cbegin() const { + const_iterator cbegin() const { return global.cbegin(); } - table_iterator cend() const { + const_iterator cend() const { return global.cend(); } diff --git a/sol/table_core.hpp b/sol/table_core.hpp index 6ea76f1f..e97ae558 100644 --- a/sol/table_core.hpp +++ b/sol/table_core.hpp @@ -34,8 +34,9 @@ template struct clean { lua_State* L; clean(lua_State* L) : L(L) {} ~clean() { lua_pop(L, static_cast(n)); } }; struct ref_clean { lua_State* L; int& n; ref_clean(lua_State* L, int& n) : L(L), n(n) {} ~ref_clean() { lua_pop(L, static_cast(n)); } }; } -template -class table_core : public reference { + +template +class basic_table_core : public base_t { friend class state; friend class state_view; @@ -45,25 +46,25 @@ class table_core : public reference { template void for_each(std::true_type, Fx&& fx) const { auto pp = stack::push_pop( *this ); - stack::push( lua_state( ), nil ); - while ( lua_next( this->lua_state( ), -2 ) ) { - sol::object key( lua_state( ), -2 ); - sol::object value( lua_state( ), -1 ); + stack::push( base_t::lua_state( ), nil ); + while ( lua_next( base_t::lua_state( ), -2 ) ) { + sol::object key( base_t::lua_state( ), -2 ); + sol::object value( base_t::lua_state( ), -1 ); std::pair keyvalue(key, value); fx( keyvalue ); - lua_pop( lua_state( ), 1 ); + lua_pop( base_t::lua_state( ), 1 ); } } template void for_each(std::false_type, Fx&& fx) const { auto pp = stack::push_pop( *this ); - stack::push( lua_state( ), nil ); - while ( lua_next( this->lua_state( ), -2 ) ) { - sol::object key( lua_state( ), -2 ); - sol::object value( lua_state( ), -1 ); + stack::push( base_t::lua_state( ), nil ); + while ( lua_next( base_t::lua_state( ), -2 ) ) { + sol::object key( base_t::lua_state( ), -2 ); + sol::object value( base_t::lua_state( ), -1 ); fx( key, value ); - lua_pop( lua_state( ), 1 ); + lua_pop( base_t::lua_state( ), 1 ); } } @@ -72,21 +73,21 @@ class table_core : public reference { -> decltype(stack::pop>(nullptr)){ typedef decltype(stack::pop>(nullptr)) Tup; return Tup( - traverse_get_optional(meta::is_specialization_of, sol::optional>(), detail::forward_get<0>(keys)), - traverse_get_optional(meta::is_specialization_of, sol::optional>(), detail::forward_get<1>(keys)), - traverse_get_optional(meta::is_specialization_of, sol::optional>(), detail::forward_get(keys))... + traverse_get_optional(meta::is_specialization_of>(), detail::forward_get<0>(keys)), + traverse_get_optional(meta::is_specialization_of>(), detail::forward_get<1>(keys)), + traverse_get_optional(meta::is_specialization_of>(), detail::forward_get(keys))... ); } template decltype(auto) tuple_get( types, std::index_sequence, Keys&& keys ) const { - return traverse_get_optional( meta::is_specialization_of, sol::optional>(), detail::forward_get(keys) ); + return traverse_get_optional( meta::is_specialization_of>(), detail::forward_get(keys) ); } template void tuple_set( std::index_sequence, Pairs&& pairs ) { auto pp = stack::push_pop(pairs))...>::value)>(*this); - void(detail::swallow{ (stack::set_field(lua_state(), + void(detail::swallow{ (stack::set_field(base_t::lua_state(), detail::forward_get(pairs), detail::forward_get(pairs) ), 0)... }); @@ -94,28 +95,28 @@ class table_core : public reference { template decltype(auto) traverse_get_deep( Key&& key ) const { - stack::get_field( lua_state( ), std::forward( key ) ); - return stack::get( lua_state( ) ); + stack::get_field( base_t::lua_state( ), std::forward( key ) ); + return stack::get( base_t::lua_state( ) ); } template decltype(auto) traverse_get_deep( Key&& key, Keys&&... keys ) const { - stack::get_field( lua_state( ), std::forward( key ) ); + stack::get_field( base_t::lua_state( ), std::forward( key ) ); return traverse_get_deep(std::forward(keys)...); } template decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key ) const { - auto p = stack::probe_get_field(lua_state(), std::forward(key), -1); + auto p = stack::probe_get_field(base_t::lua_state(), std::forward(key), -1); popcount += p.levels; if (!p.success) return T(nullopt); - return stack::get( lua_state( ) ); + return stack::get( base_t::lua_state( ) ); } template decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key, Keys&&... keys ) const { - auto p = I > 0 ? stack::probe_get_field(lua_state(), std::forward(key), - 1) : stack::probe_get_field( lua_state( ), std::forward( key ) ); + auto p = I > 0 ? stack::probe_get_field(base_t::lua_state(), std::forward(key), - 1) : stack::probe_get_field( base_t::lua_state( ), std::forward( key ) ); popcount += p.levels; if (!p.success) return T(nullopt); @@ -124,52 +125,57 @@ class table_core : public reference { template decltype(auto) traverse_get_optional( std::false_type, Keys&&... keys ) const { - detail::clean c(lua_state()); + detail::clean c(base_t::lua_state()); return traverse_get_deep(std::forward(keys)...); } template decltype(auto) traverse_get_optional( std::true_type, Keys&&... keys ) const { int popcount = 0; - detail::ref_clean c(lua_state(), popcount); + detail::ref_clean c(base_t::lua_state(), popcount); return traverse_get_deep_optional(popcount, std::forward(keys)...); } template void traverse_set_deep( Key&& key, Value&& value ) const { - stack::set_field( lua_state( ), std::forward( key ), std::forward(value) ); + stack::set_field( base_t::lua_state( ), std::forward( key ), std::forward(value) ); } template void traverse_set_deep( Key&& key, Keys&&... keys ) const { - stack::get_field( lua_state( ), std::forward( key ) ); + stack::get_field( base_t::lua_state( ), std::forward( key ) ); traverse_set_deep(std::forward(keys)...); } - table_core(lua_State* L, detail::global_tag t) noexcept : reference(L, t) { } + basic_table_core(lua_State* L, detail::global_tag t) noexcept : reference(L, t) { } public: - table_core( ) noexcept : reference( ) { } - table_core( const table_core& global ) noexcept : reference( global ) { } - table_core( lua_State* L, int index = -1 ) : reference( L, index ) { + typedef basic_table_iterator iterator; + typedef iterator const_iterator; + + basic_table_core( ) noexcept : base_t( ) { } + basic_table_core( const table_core& global ) noexcept : base_t( global ) { } + basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {} + basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {} + basic_table_core( lua_State* L, int index = -1 ) : base_t( L, index ) { #ifdef SOL_CHECK_ARGUMENTS type_assert( L, index, type::table ); #endif // Safety } - table_iterator begin () const { - return table_iterator(*this); + iterator begin () const { + return iterator(*this); } - table_iterator end() const { - return table_iterator(); + iterator end() const { + return iterator(); } - table_iterator cbegin() const { + const_iterator cbegin() const { return begin(); } - table_iterator cend() const { + const_iterator cend() const { return end(); } @@ -202,48 +208,48 @@ public: template decltype(auto) traverse_get( Keys&&... keys ) const { auto pp = stack::push_pop::value>(*this); - return traverse_get_optional(meta::is_specialization_of, sol::optional>(), std::forward(keys)...); + return traverse_get_optional(meta::is_specialization_of>(), std::forward(keys)...); } template - table_core& traverse_set( Keys&&... keys ) { + basic_table_core& traverse_set( Keys&&... keys ) { auto pp = stack::push_pop::value>(*this); traverse_set_deep(std::forward(keys)...); - lua_pop(lua_state(), static_cast(sizeof...(Keys)-2)); + lua_pop(base_t::lua_state(), static_cast(sizeof...(Keys)-2)); return *this; } template - table_core& set( Args&&... args ) { + basic_table_core& set( Args&&... args ) { tuple_set(std::make_index_sequence(), std::forward_as_tuple(std::forward(args)...)); return *this; } template - table_core& set_usertype( usertype& user ) { + basic_table_core& set_usertype( usertype& user ) { return set_usertype(usertype_traits::name, user); } template - table_core& set_usertype( Key&& key, usertype& user ) { + basic_table_core& set_usertype( Key&& key, usertype& user ) { return set(std::forward(key), user); } template - table_core& new_usertype(const std::string& name, Args&&... args) { + basic_table_core& new_usertype(const std::string& name, Args&&... args) { usertype utype(std::forward(args)...); set_usertype(name, utype); return *this; } template - table_core& new_usertype(const std::string& name, Args&&... args) { + basic_table_core& new_usertype(const std::string& name, Args&&... args) { constructors> ctor{}; return new_usertype(name, ctor, std::forward(args)...); } template - table_core& new_usertype(const std::string& name, constructors ctor, Args&&... args) { + basic_table_core& new_usertype(const std::string& name, constructors ctor, Args&&... args) { usertype utype(ctor, std::forward(args)...); set_usertype(name, utype); return *this; @@ -257,7 +263,7 @@ public: size_t size( ) const { auto pp = stack::push_pop( *this ); - return lua_rawlen(lua_state(), -1); + return lua_rawlen(base_t::lua_state(), -1); } bool empty() const { @@ -265,28 +271,28 @@ public: } template - proxy operator[]( T&& key ) & { - return proxy( *this, std::forward( key ) ); + proxy operator[]( T&& key ) & { + return proxy( *this, std::forward( key ) ); } template - proxy operator[]( T&& key ) const & { - return proxy( *this, std::forward( key ) ); + proxy operator[]( T&& key ) const & { + return proxy( *this, std::forward( key ) ); } template - proxy operator[]( T&& key ) && { - return proxy( *this, std::forward( key ) ); + proxy operator[]( T&& key ) && { + return proxy( *this, std::forward( key ) ); } template - table_core& set_function( Key&& key, Args&&... args ) { + basic_table_core& set_function( Key&& key, Args&&... args ) { set_fx( types( ), std::forward( key ), std::forward( args )... ); return *this; } template - table_core& set_function( Key&& key, Args&&... args ) { + basic_table_core& set_function( Key&& key, Args&&... args ) { set_fx( types<>( ), std::forward( key ), std::forward( args )... ); return *this; } @@ -297,12 +303,12 @@ private: set_resolved_function( std::forward( key ), std::forward( fx ) ); } - template, overload_set>> = 0> + template>> = 0> void set_fx( types<>, Key&& key, Fx&& fx ) { set(std::forward(key), std::forward(fx)); } - template, overload_set>> = 0> + template>> = 0> void set_fx( types<>, Key&& key, Fx&& fx, Args&&... args ) { set(std::forward(key), function_args(std::forward(fx), std::forward(args)...)); } @@ -336,31 +342,31 @@ public: } table create(int narr = 0, int nrec = 0) { - return create(lua_state(), narr, nrec); + return create(base_t::lua_state(), narr, nrec); } template table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args) { - return create(lua_state(), narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); + return create(base_t::lua_state(), narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); } template table create(Name&& name, int narr = 0, int nrec = 0) { - table x = create(lua_state(), narr, nrec); + table x = create(base_t::lua_state(), narr, nrec); this->set(std::forward(name), x); return x; } template table create(Name&& name, int narr, int nrec, Key&& key, Value&& value, Args&&... args) { - table x = create(lua_state(), narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); + table x = create(base_t::lua_state(), narr, nrec, std::forward(key), std::forward(value), std::forward(args)...); this->set(std::forward(name), x); return x; } template table create_with(Args&&... args) { - return create_with(lua_state(), std::forward(args)...); + return create_with(base_t::lua_state(), std::forward(args)...); } template diff --git a/sol/table_iterator.hpp b/sol/table_iterator.hpp index 41075593..25eef1cf 100644 --- a/sol/table_iterator.hpp +++ b/sol/table_iterator.hpp @@ -27,7 +27,8 @@ namespace sol { -class table_iterator : public std::iterator> { +template +class basic_table_iterator : public std::iterator> { private: typedef std::iterator> base_t; public: @@ -41,19 +42,18 @@ public: typedef const value_type& const_reference; private: - typedef ::sol::reference ref_t; std::pair kvp; - ref_t ref; + reference_type ref; int tableidx = 0; std::ptrdiff_t idx = 0; public: - table_iterator () : idx(-1) { + basic_table_iterator () : idx(-1) { } - table_iterator(ref_t x) : ref(std::move(x)) { + basic_table_iterator(reference_type x) : ref(std::move(x)) { ref.push(); tableidx = lua_gettop(ref.lua_state()); stack::push(ref.lua_state(), nil); @@ -64,7 +64,7 @@ public: --idx; } - table_iterator& operator++() { + basic_table_iterator& operator++() { if (idx == -1) return *this; @@ -80,7 +80,7 @@ public: return *this; } - table_iterator operator++(int) { + basic_table_iterator operator++(int) { auto saved = *this; this->operator++(); return saved; @@ -94,15 +94,15 @@ public: return kvp; } - bool operator== (const table_iterator& right) const { + bool operator== (const basic_table_iterator& right) const { return idx == right.idx; } - bool operator!= (const table_iterator& right) const { + bool operator!= (const basic_table_iterator& right) const { return idx != right.idx; } - ~table_iterator() { + ~basic_table_iterator() { if (ref.valid()) { stack::remove(ref.lua_state(), tableidx, 1); } diff --git a/sol/traits.hpp b/sol/traits.hpp index 4124df3a..436b8d9b 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -70,10 +70,10 @@ struct remove_member_pointer { template using remove_member_pointer_t = remove_member_pointer; -template class Templ> +template class Templ, typename T> struct is_specialization_of : std::false_type { }; template class Templ> -struct is_specialization_of, Templ> : std::true_type { }; +struct is_specialization_of> : std::true_type { }; template struct are_same : std::true_type { }; @@ -380,12 +380,12 @@ using is_c_str = Or< >; namespace meta_detail { -template , std::tuple>> = 0> +template >> = 0> decltype(auto) force_tuple(T&& x) { return std::forward_as_tuple(std::forward(x)); } -template , std::tuple>> = 0> +template >> = 0> decltype(auto) force_tuple(T&& x) { return std::forward(x); } diff --git a/sol/types.hpp b/sol/types.hpp index e218e469..f0d48b14 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -105,6 +105,12 @@ struct up_value_index { operator int() const { return index; } }; +struct absolute_index { + int index; + absolute_index(lua_State* L, int idx) : index(lua_absindex(L, idx)) {} + operator int() const { return index; } +}; + struct light_userdata_value { void* value; light_userdata_value(void* data) : value(data) {} @@ -203,17 +209,38 @@ class reference; class stack_reference; template class usertype; -template -class table_core; +template +class basic_table_core; +template +using table_core = basic_table_core; +template +using stack_table_core = basic_table_core; typedef table_core table; typedef table_core global_table; -class function; -class protected_function; +typedef stack_table_core stack_table; +typedef stack_table_core stack_global_table; +template +class basic_function; +template +class basic_protected_function; +using function = basic_function; +using protected_function = basic_protected_function; +using stack_function = basic_function; +using stack_protected_function = basic_protected_function; +template +class basic_object; +template +class basic_userdata; +template +class basic_lightuserdata; +using object = basic_object; +using stack_object = basic_object; +using userdata = basic_userdata; +using stack_userdata = basic_userdata; +using lightuserdata = basic_lightuserdata; +using stack_lightuserdata = basic_lightuserdata; class coroutine; class thread; -class object; -class userdata; -class lightuserdata; template struct lua_type_of : std::integral_constant {}; @@ -242,14 +269,20 @@ struct lua_type_of : std::integral_constant { }; template <> struct lua_type_of : std::integral_constant { }; +template <> +struct lua_type_of : std::integral_constant { }; + +template <> +struct lua_type_of : std::integral_constant { }; + template <> struct lua_type_of : std::integral_constant {}; template <> struct lua_type_of : std::integral_constant {}; -template <> -struct lua_type_of : std::integral_constant {}; +template +struct lua_type_of> : std::integral_constant {}; template struct lua_type_of> : std::integral_constant {}; @@ -263,17 +296,20 @@ struct lua_type_of : std::integral_constant struct lua_type_of : std::integral_constant {}; -template <> -struct lua_type_of : std::integral_constant {}; +template +struct lua_type_of> : std::integral_constant {}; -template <> -struct lua_type_of : std::integral_constant {}; +template +struct lua_type_of> : std::integral_constant {}; template <> struct lua_type_of : std::integral_constant {}; -template <> -struct lua_type_of : std::integral_constant {}; +template +struct lua_type_of> : std::integral_constant {}; + +template +struct lua_type_of> : std::integral_constant {}; template <> struct lua_type_of : std::integral_constant {}; @@ -281,9 +317,6 @@ struct lua_type_of : std::integral_constant {}; template <> struct lua_type_of : std::integral_constant {}; -template <> -struct lua_type_of : std::integral_constant {}; - template struct lua_type_of> : std::integral_constant{}; @@ -303,10 +336,15 @@ template struct is_lua_primitive : std::integral_constant>::value || std::is_base_of>::value - || meta::is_specialization_of, std::tuple>::value - || meta::is_specialization_of, std::pair>::value + || std::is_base_of>::value + || meta::is_specialization_of>::value + || meta::is_specialization_of>::value > { }; +template +struct is_lua_primitive> : std::true_type { }; +template +struct is_lua_primitive> : std::true_type {}; template struct is_lua_primitive : std::true_type {}; template <> @@ -319,12 +357,6 @@ struct is_lua_primitive> : is_lua_primitive {}; template struct is_proxy_primitive : is_lua_primitive { }; -template -struct is_proxy_primitive> : std::true_type { }; - -template -struct is_proxy_primitive> : std::true_type {}; - template struct is_unique_usertype : std::false_type {}; diff --git a/sol/userdata.hpp b/sol/userdata.hpp index 23003b27..bcd2e5c4 100644 --- a/sol/userdata.hpp +++ b/sol/userdata.hpp @@ -25,28 +25,34 @@ #include "reference.hpp" namespace sol { -class userdata : public reference { +template +class basic_userdata : public base_t { public: - userdata () noexcept = default; - userdata(const userdata&) = default; - userdata(userdata&&) = default; - userdata& operator=(const userdata&) = default; - userdata& operator=(userdata&&) = default; - userdata(lua_State* L, int index = -1) : reference(L, index) { + basic_userdata () noexcept = default; + basic_userdata(const basic_userdata&) = default; + basic_userdata(basic_userdata&&) = default; + basic_userdata& operator=(const basic_userdata&) = default; + basic_userdata& operator=(basic_userdata&&) = default; + basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) {} + basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {} + basic_userdata(lua_State* L, int index = -1) : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS type_assert(L, index, type::userdata); #endif // Safety } }; -class lightuserdata : public reference { +template +class basic_lightuserdata : public base_t { public: - lightuserdata () noexcept = default; - lightuserdata(const lightuserdata&) = default; - lightuserdata(lightuserdata&&) = default; - lightuserdata& operator=(const lightuserdata&) = default; - lightuserdata& operator=(lightuserdata&&) = default; - lightuserdata(lua_State* L, int index = -1) : reference(L, index) { + basic_lightuserdata () noexcept = default; + basic_lightuserdata(const basic_lightuserdata&) = default; + basic_lightuserdata(basic_lightuserdata&&) = default; + basic_lightuserdata& operator=(const basic_lightuserdata&) = default; + basic_lightuserdata& operator=(basic_lightuserdata&&) = default; + basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} + basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} + basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS type_assert(L, index, type::lightuserdata); #endif // Safety diff --git a/tests.cpp b/tests.cpp index dac2b9d2..fec08eec 100644 --- a/tests.cpp +++ b/tests.cpp @@ -801,3 +801,60 @@ TEST_CASE("usertype/overloading", "Check if overloading works properly for usert REQUIRE_THROWS(lua.script("r:func(1,2,'meow')")); } + +TEST_CASE("usertype/reference-and-constness", "Make sure constness compiles properly and errors out at runtime") { + struct bark { + int var = 50; + }; + struct woof { + bark b; + }; + + struct nested { + const int f = 25; + }; + + struct outer { + nested n; + }; + + bool caughterror = false; + std::string msg; + sol::state lua; + lua.new_usertype("woof", + "b", &woof::b); + lua.new_usertype("bark", + "var", &bark::var); + lua.new_usertype("outer", + "n", &outer::n); + lua.set("w", woof()); + lua.set("n", nested()); + lua.set("o", outer()); + lua.set("f", sol::c_call); + try { + lua.script(R"( + x = w.b + x.var = 20 + val = w.b.var == x.var + v = f(n); + f(n, 50) +)"); + } + catch (const sol::error& e) { + msg = e.what(); + caughterror = true; + } + REQUIRE(caughterror); + REQUIRE(!msg.empty()); + woof& w = lua["w"]; + bark& x = lua["x"]; + nested& n = lua["n"]; + int v = lua["v"]; + bool val = lua["val"]; + // enforce reference semantics + REQUIRE(std::addressof(w.b) == std::addressof(x)); + REQUIRE(n.f == 25); + REQUIRE(v == 25); + REQUIRE(val); + REQUIRE_THROWS(lua.script("o.n = 25")); +}