// 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_CALL_HPP #define SOL_CALL_HPP #include #include #include #include #include #include #include namespace sol { namespace u_detail { } // namespace u_detail namespace policy_detail { template inline void handle_policy(static_stack_dependencies, lua_State* L, int&) { if constexpr (sizeof...(In) == 0) { (void)L; return; } else { absolute_index ai(L, I); if (type_of(L, ai) != type::userdata) { return; } lua_createtable(L, static_cast(sizeof...(In)), 0); stack_reference deps(L, -1); auto per_dep = [&L, &deps](int i) { #if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow lua_pushvalue(L, i); luaL_ref(L, deps.stack_index()); }; (void)per_dep; (void)detail::swallow{ int(), (per_dep(In), int())... }; lua_setuservalue(L, ai); } } template inline void handle_policy(returns_self_with, lua_State* L, int& pushed) { pushed = stack::push(L, raw_index(1)); handle_policy(static_stack_dependencies<-1, In...>(), L, pushed); } inline void handle_policy(const stack_dependencies& sdeps, lua_State* L, int&) { absolute_index ai(L, sdeps.target); if (type_of(L, ai) != type::userdata) { return; } lua_createtable(L, static_cast(sdeps.size()), 0); stack_reference deps(L, -1); #if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_) luaL_checkstack(L, static_cast(sdeps.size()), detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow for (std::size_t i = 0; i < sdeps.size(); ++i) { lua_pushvalue(L, sdeps.stack_indices[i]); luaL_ref(L, deps.stack_index()); } lua_setuservalue(L, ai); } template >> = meta::enabler> inline void handle_policy(P&& p, lua_State* L, int& pushed) { pushed = std::forward

(p)(L, pushed); } } // namespace policy_detail namespace function_detail { inline int no_construction_error(lua_State* L) { return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); } } // namespace function_detail namespace call_detail { template inline auto& pick(std::true_type, property_wrapper& f) { return f.read(); } template inline auto& pick(std::false_type, property_wrapper& f) { return f.write(); } template struct void_call : void_call> {}; template struct void_call> { static void call(Args...) { } }; template struct constructor_match { T* obj_; constructor_match(T* o) : obj_(o) { } template int operator()(types, meta::index_value, types r, types a, lua_State* L, int, int start) const { detail::default_construct func{}; return stack::call_into_lua(r, a, L, start, func, obj_); } }; namespace overload_detail { template inline int overload_match_arity(types<>, std::index_sequence<>, std::index_sequence, Match&&, lua_State* L, int, int, Args&&...) { return luaL_error(L, "sol: no matching function call takes this number of arguments and the specified types"); } template inline int overload_match_arity(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { typedef lua_bind_traits> traits; typedef meta::tuple_types return_types; typedef typename traits::free_args_list args_list; // compile-time eliminate any functions that we know ahead of time are of improper arity if constexpr (!traits::runtime_variadics_t::value && meta::find_in_pack_v, meta::index_value...>::value) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } else { if constexpr (!traits::runtime_variadics_t::value) { if (traits::free_arity != fxarity) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } } stack::record tracking{}; if (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } return matchfx(types(), meta::index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); } } template inline int overload_match_arity_single( types<>, std::index_sequence<>, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } template inline int overload_match_arity_single( types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { typedef lua_bind_traits> traits; typedef meta::tuple_types return_types; typedef typename traits::free_args_list args_list; // compile-time eliminate any functions that we know ahead of time are of improper arity if constexpr (!traits::runtime_variadics_t::value && meta::find_in_pack_v, meta::index_value...>::value) { return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } if constexpr (!traits::runtime_variadics_t::value) { if (traits::free_arity != fxarity) { return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } } return matchfx(types(), meta::index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); } template inline int overload_match_arity_single(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { typedef lua_bind_traits> traits; typedef meta::tuple_types return_types; typedef typename traits::free_args_list args_list; // compile-time eliminate any functions that we know ahead of time are of improper arity if constexpr (!traits::runtime_variadics_t::value && meta::find_in_pack_v, meta::index_value...>::value) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } else { if constexpr (!traits::runtime_variadics_t::value) { if (traits::free_arity != fxarity) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } } stack::record tracking{}; if (!stack::stack_detail::check_types(args_list(), L, start, no_panic, tracking)) { return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } return matchfx(types(), meta::index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); } } } // namespace overload_detail template inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { return overload_detail::overload_match_arity_single(types(), std::make_index_sequence(), std::index_sequence<>(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } template inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) { int fxarity = lua_gettop(L) - (start - 1); return overload_match_arity(std::forward(matchfx), L, fxarity, start, std::forward(args)...); } template inline int construct_match(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { // use same overload resolution matching as all other parts of the framework return overload_match_arity::call)...>( std::forward(matchfx), L, fxarity, start, std::forward(args)...); } template inline int construct_trampolined(lua_State* L) { static const auto& meta = usertype_traits::metatable(); int argcount = lua_gettop(L); call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits::user_metatable(), 1) : call_syntax::dot; argcount -= static_cast(syntax); T* obj = detail::usertype_allocate(L); reference userdataref(L, -1); stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on); umf(); // put userdata at the first index lua_insert(L, 1); construct_match(constructor_match(obj), L, argcount, 1 + static_cast(syntax)); userdataref.push(); return 1; } template inline int construct(lua_State* L) { return detail::static_trampoline<&construct_trampolined>(L); } template struct agnostic_lua_call_wrapper { template static int call(lua_State* L, Fx&& f, Args&&... args) { using uFx = meta::unqualified_t; static constexpr bool is_ref = is_lua_reference_v; if constexpr (is_ref) { if constexpr (is_index) { return stack::push(L, std::forward(f), std::forward(args)...); } else { std::forward(f) = stack::unqualified_get(L, boost + (is_variable ? 3 : 1)); return 0; } } else { using wrap = wrapper; using traits_type = typename wrap::traits_type; using fp_t = typename traits_type::function_pointer_type; constexpr bool is_function_pointer_convertible = std::is_class_v && std::is_convertible_v, fp_t>; if constexpr (is_function_pointer_convertible) { fp_t fx = f; return agnostic_lua_call_wrapper{}.call( L, fx, std::forward(args)...); } else { using returns_list = typename wrap::returns_list; using args_list = typename wrap::free_args_list; using caller = typename wrap::caller; return stack::call_into_lua( returns_list(), args_list(), L, boost + 1, caller(), std::forward(f), std::forward(args)...); } } } }; template struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { template static int call(lua_State* L, F&& f) { if constexpr (is_index) { constexpr bool is_stack = is_stack_based_v>; if constexpr (clean_stack && !is_stack) { lua_settop(L, 0); } return stack::push_reference(L, detail::unwrap(f.value())); } else { if constexpr (std::is_const_v>) { (void)f; return luaL_error(L, "sol: cannot write to a readonly (const) variable"); } else { using R = meta::unwrapped_t; if constexpr (std::is_assignable_v>, R>) { detail::unwrap(f.value()) = stack::unqualified_get>(L, boost + (is_variable ? 3 : 1)); if (clean_stack) { lua_settop(L, 0); } return 0; } else { return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available"); } } } } }; template struct agnostic_lua_call_wrapper { static int call(lua_State* L, lua_CFunction_ref f) { return f(L); } }; template struct agnostic_lua_call_wrapper { static int call(lua_State* L, lua_CFunction f) { return f(L); } }; #if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_) template struct agnostic_lua_call_wrapper { static int call(lua_State* L, detail::lua_CFunction_noexcept f) { return f(L); } }; #endif // noexcept function types template struct agnostic_lua_call_wrapper { static int call(lua_State* L, const detail::no_prop&) { return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property"); } }; template struct agnostic_lua_call_wrapper { static int call(lua_State* L, const no_construction&) { return function_detail::no_construction_error(L); } }; template struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { static int call(lua_State*, const bases&) { // Uh. How did you even call this, lul return 0; } }; template struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { static int call(lua_State* L, std::reference_wrapper f) { agnostic_lua_call_wrapper alcw{}; return alcw.call(L, f.get()); } }; template struct lua_call_wrapper { template static int call(lua_State* L, Fx&& fx, Args&&... args) { if constexpr (std::is_member_function_pointer_v) { using wrap = wrapper; using object_type = typename wrap::object_type; if constexpr (sizeof...(Args) < 1) { using Ta = meta::conditional_t, object_type, T>; static_assert(std::is_base_of_v, "It seems like you might have accidentally bound a class type with a member function method that does not correspond to the class. For example, there could be a small type in your new_usertype(...) binding, where you specify one class \"T\" but then bind member methods from a complete unrelated class. Check things over!"); #if SOL_IS_ON(SOL_SAFE_USERTYPE_I_) auto maybeo = stack::check_get(L, 1); if (!maybeo || maybeo.value() == nullptr) { return luaL_error(L, "sol: received nil for 'self' argument (use ':' for accessing member functions, make sure member variables are " "preceeded by the " "actual object with '.' syntax)"); } object_type* o = static_cast(maybeo.value()); return call(L, std::forward(fx), *o); #else object_type& o = static_cast(*stack::unqualified_get>(L, 1)); return call(L, std::forward(fx), o); #endif // Safety } else { using returns_list = typename wrap::returns_list; using args_list = typename wrap::args_list; using caller = typename wrap::caller; return stack::call_into_lua( returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward(fx), std::forward(args)...); } } else if constexpr (std::is_member_object_pointer_v) { using wrap = wrapper; using object_type = typename wrap::object_type; if constexpr (is_index) { if constexpr (sizeof...(Args) < 1) { using Ta = meta::conditional_t, object_type, T>; static_assert(std::is_base_of_v, "It seems like you might have accidentally bound a class type with a member function method that does not correspond to the class. For example, there could be a small type in your new_usertype(...) binding, where you specify one class \"T\" but then bind member methods from a complete unrelated class. Check things over!"); #if SOL_IS_ON(SOL_SAFE_USERTYPE_I_) auto maybeo = stack::check_get(L, 1); if (!maybeo || maybeo.value() == nullptr) { if (is_variable) { return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)"); } return luaL_error(L, "sol: 'self' argument is lua_nil (pass 'self' as first argument)"); } object_type* o = static_cast(maybeo.value()); return call(L, std::forward(fx), *o); #else object_type& o = static_cast(*stack::get>(L, 1)); return call(L, std::forward(fx), o); #endif // Safety } else { using returns_list = typename wrap::returns_list; using caller = typename wrap::caller; return stack::call_into_lua(returns_list(), types<>(), L, boost + (is_variable ? 3 : 2), caller(), std::forward(fx), std::forward(args)...); } } else { using traits_type = lua_bind_traits; using return_type = typename traits_type::return_type; constexpr bool ret_is_const = std::is_const_v>; if constexpr (ret_is_const) { (void)fx; (void)detail::swallow{ 0, (static_cast(args), 0)... }; return luaL_error(L, "sol: cannot write to a readonly (const) variable"); } else { using u_return_type = meta::unqualified_t; constexpr bool is_assignable = std::is_copy_assignable_v || std::is_array_v; if constexpr (!is_assignable) { (void)fx; (void)detail::swallow{ 0, ((void)args, 0)... }; return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available"); } else { using args_list = typename wrap::args_list; using caller = typename wrap::caller; if constexpr (sizeof...(Args) > 0) { return stack::call_into_lua(types(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward(fx), std::forward(args)...); } else { using Ta = meta::conditional_t, object_type, T>; #if SOL_IS_ON(SOL_SAFE_USERTYPE_I_) auto maybeo = stack::check_get(L, 1); if (!maybeo || maybeo.value() == nullptr) { if (is_variable) { return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)"); } return luaL_error(L, "sol: received nil for 'self' argument (pass 'self' as first argument)"); } object_type* po = static_cast(maybeo.value()); object_type& o = *po; #else object_type& o = static_cast(*stack::get>(L, 1)); #endif // Safety return stack::call_into_lua( types(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward(fx), o); } } } } } else { agnostic_lua_call_wrapper alcw{}; return alcw.call(L, std::forward(fx), std::forward(args)...); } } }; template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { using traits_type = lua_bind_traits; using wrap = wrapper; using object_type = typename wrap::object_type; static int call(lua_State* L, readonly_wrapper&& rw) { if constexpr (!is_index) { (void)rw; return luaL_error(L, "sol: cannot write to a sol::readonly variable"); } else { lua_call_wrapper lcw; return lcw.call(L, std::move(rw.value())); } } static int call(lua_State* L, readonly_wrapper&& rw, object_type& o) { if constexpr (!is_index) { (void)o; return call(L, std::move(rw)); } else { lua_call_wrapper lcw; return lcw.call(L, rw.value(), o); } } static int call(lua_State* L, const readonly_wrapper& rw) { if constexpr (!is_index) { (void)rw; return luaL_error(L, "sol: cannot write to a sol::readonly variable"); } else { lua_call_wrapper lcw; return lcw.call(L, rw.value()); } } static int call(lua_State* L, const readonly_wrapper& rw, object_type& o) { if constexpr (!is_index) { (void)o; return call(L, rw); } else { lua_call_wrapper lcw; return lcw.call(L, rw.value(), o); } } }; template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef constructor_list F; static int call(lua_State* L, F&) { const auto& meta = usertype_traits::metatable(); int argcount = lua_gettop(L); call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits::user_metatable(), 1) : call_syntax::dot; argcount -= static_cast(syntax); T* obj = detail::usertype_allocate(L); reference userdataref(L, -1); stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on); umf(); // put userdata at the first index lua_insert(L, 1); construct_match(constructor_match(obj), L, argcount, boost + 1 + 1 + static_cast(syntax)); userdataref.push(); return 1; } }; template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef constructor_wrapper F; struct onmatch { template int operator()(types, meta::index_value, types r, types a, lua_State* L, int, int start, F& f) { const auto& meta = usertype_traits::metatable(); T* obj = detail::usertype_allocate(L); reference userdataref(L, -1); stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on); umf(); auto& func = std::get(f.functions); // put userdata at the first index lua_insert(L, 1); stack::call_into_lua(r, a, L, boost + 1 + start, func, detail::implicit_wrapper(obj)); userdataref.push(); return 1; } }; static int call(lua_State* L, F& f) { call_syntax syntax = stack::get_call_syntax(L, usertype_traits::user_metatable(), 1); int syntaxval = static_cast(syntax); int argcount = lua_gettop(L) - syntaxval; return construct_match>...>(onmatch(), L, argcount, 1 + syntaxval, f); } }; template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { template static int call(lua_State* L, F&& f) { if constexpr (std::is_void_v) { return detail::usertype_alloc_destruct(L); } else { using uFx = meta::unqualified_t; lua_call_wrapper lcw{}; return lcw.call(L, std::forward(f).fx); } } }; template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef overload_set F; struct on_match { template int operator()(types, meta::index_value, types, types, lua_State* L, int, int, F& fx) { auto& f = std::get(fx.functions); return lua_call_wrapper{}.call(L, f); } }; static int call(lua_State* L, F& fx) { return overload_match_arity(on_match(), L, lua_gettop(L), 1, fx); } }; template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef factory_wrapper F; struct on_match { template int operator()(types, meta::index_value, types, types, lua_State* L, int, int, F& fx) { auto& f = std::get(fx.functions); return lua_call_wrapper{}.call(L, f); } }; static int call(lua_State* L, F& fx) { return overload_match_arity(on_match(), L, lua_gettop(L) - boost, 1 + boost, fx); } }; template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef meta::conditional_t P; typedef meta::unqualified_t

U; typedef wrapper wrap; typedef lua_bind_traits traits_type; typedef meta::unqualified_t> object_type; template static int call(lua_State* L, F&& f, Args&&... args) { constexpr bool is_specialized = meta::any, meta::is_specialization_of, meta::is_specialization_of, meta::is_specialization_of, std::is_member_pointer>::value; if constexpr (is_specialized) { if constexpr (is_index) { decltype(auto) p = f.read(); lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack> lcw{}; return lcw.call(L, p, std::forward(args)...); } else { decltype(auto) p = f.write(); lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack> lcw{}; return lcw.call(L, p, std::forward(args)...); } } else { constexpr bool non_class_object_type = meta::any, meta::boolean>::value != type::userdata>>::value; if constexpr (non_class_object_type) { // The type being void means we don't have any arguments, so it might be a free functions? using args_list = typename traits_type::free_args_list; using returns_list = typename wrap::returns_list; using caller = typename wrap::caller; if constexpr (is_index) { decltype(auto) pf = f.read(); return stack::call_into_lua( returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf); } else { decltype(auto) pf = f.write(); return stack::call_into_lua( returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf); } } else { using args_list = meta::pop_front_type_t; using Ta = T; using Oa = std::remove_pointer_t; #if SOL_IS_ON(SOL_SAFE_USERTYPE_I_) auto maybeo = stack::check_get(L, 1); if (!maybeo || maybeo.value() == nullptr) { if (is_variable) { return luaL_error(L, "sol: 'self' argument is lua_nil (bad '.' access?)"); } return luaL_error(L, "sol: 'self' argument is lua_nil (pass 'self' as first argument)"); } Oa* o = static_cast(maybeo.value()); #else Oa* o = static_cast(stack::get>(L, 1)); #endif // Safety using returns_list = typename wrap::returns_list; using caller = typename wrap::caller; if constexpr (is_index) { decltype(auto) pf = f.read(); return stack::call_into_lua( returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf, detail::implicit_wrapper(*o)); } else { decltype(auto) pf = f.write(); return stack::call_into_lua( returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf, detail::implicit_wrapper(*o)); } } } } }; template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef protect_t F; template static int call(lua_State* L, F& fx, Args&&... args) { return lua_call_wrapper{}.call(L, fx.value, std::forward(args)...); } }; template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { typedef policy_wrapper P; template static int call(std::index_sequence, lua_State* L, P& fx) { int pushed = lua_call_wrapper{}.call(L, fx.value); (void)detail::swallow{ int(), (policy_detail::handle_policy(std::get(fx.policies), L, pushed), int())... }; return pushed; } static int call(lua_State* L, P& fx) { typedef typename P::indices indices; return call(indices(), L, fx); } }; template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { template static int call(lua_State* L, F&& f) { return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f.func); } }; template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { static int call(lua_State* L, const function_arguments& f) { lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack> lcw{}; return lcw.call(L, std::get<0>(f.arguments)); } static int call(lua_State* L, function_arguments&& f) { lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack> lcw{}; return lcw.call(L, std::get<0>(std::move(f.arguments))); } }; template inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) { using uFx = meta::unqualified_t; if constexpr (meta::is_specialization_of_v) { using real_fx = meta::unqualified_t(fx).func)>; lua_call_wrapper lcw{}; return lcw.call(L, std::forward(fx).func, std::forward(args)...); } else { lua_call_wrapper lcw{}; return lcw.call(L, std::forward(fx), std::forward(args)...); } } template inline int call_user(lua_State* L) { auto& fx = stack::unqualified_get>(L, upvalue_index(start)); using uFx = meta::unqualified_t; int nr = call_wrapped(L, fx); if constexpr (meta::is_specialization_of_v) { return lua_yield(L, nr); } else { return nr; } } template struct is_var_bind : std::false_type {}; template struct is_var_bind::value>> : std::true_type {}; template struct is_var_bind::value>> : std::true_type {}; template <> struct is_var_bind : std::true_type {}; template struct is_var_bind> : std::true_type {}; template struct is_var_bind> : std::true_type {}; template struct is_var_bind> : is_var_bind> {}; template struct is_var_bind> : is_var_bind> {}; } // namespace call_detail template struct is_variable_binding : call_detail::is_var_bind> {}; template using is_var_wrapper = meta::is_specialization_of; template struct is_function_binding : meta::neg> {}; } // namespace sol #endif // SOL_CALL_HPP