mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 17:56:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			961 lines
		
	
	
	
		
			40 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			961 lines
		
	
	
	
		
			40 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // sol2
 | |
| 
 | |
| // The MIT License (MIT)
 | |
| 
 | |
| // Copyright (c) 2013-2021 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.
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| #ifndef SOL_CALL_HPP
 | |
| #define SOL_CALL_HPP
 | |
| 
 | |
| #include <sol/property.hpp>
 | |
| #include <sol/protect.hpp>
 | |
| #include <sol/wrapper.hpp>
 | |
| #include <sol/trampoline.hpp>
 | |
| #include <sol/policies.hpp>
 | |
| #include <sol/stack.hpp>
 | |
| #include <sol/unique_usertype_traits.hpp>
 | |
| 
 | |
| namespace sol {
 | |
| 	namespace u_detail {
 | |
| 
 | |
| 	} // namespace u_detail
 | |
| 
 | |
| 	namespace policy_detail {
 | |
| 		template <int I, int... In>
 | |
| 		inline void handle_policy(static_stack_dependencies<I, In...>, 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<int>(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 <int... In>
 | |
| 		inline void handle_policy(returns_self_with<In...>, 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<int>(sdeps.size()), 0);
 | |
| 			stack_reference deps(L, -1);
 | |
| #if SOL_IS_ON(SOL_SAFE_STACK_CHECK_I_)
 | |
| 			luaL_checkstack(L, static_cast<int>(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 <typename P, meta::disable<std::is_base_of<detail::policy_base_tag, meta::unqualified_t<P>>> = meta::enabler>
 | |
| 		inline void handle_policy(P&& p, lua_State* L, int& pushed) {
 | |
| 			pushed = std::forward<P>(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 <typename R, typename W>
 | |
| 		inline auto& pick(std::true_type, property_wrapper<R, W>& f) {
 | |
| 			return f.read();
 | |
| 		}
 | |
| 
 | |
| 		template <typename R, typename W>
 | |
| 		inline auto& pick(std::false_type, property_wrapper<R, W>& f) {
 | |
| 			return f.write();
 | |
| 		}
 | |
| 
 | |
| 		template <typename T, typename List>
 | |
| 		struct void_call : void_call<T, meta::function_args_t<List>> { };
 | |
| 
 | |
| 		template <typename T, typename... Args>
 | |
| 		struct void_call<T, types<Args...>> {
 | |
| 			static void call(Args...) {
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, bool checked, bool clean_stack>
 | |
| 		struct constructor_match {
 | |
| 			T* obj_;
 | |
| 			reference* obj_lua_ref_;
 | |
| 			stack::stack_detail::undefined_metatable* p_umf_;
 | |
| 
 | |
| 			constructor_match(T* obj_ptr, reference& obj_lua_ref, stack::stack_detail::undefined_metatable& umf)
 | |
| 			: obj_(obj_ptr), obj_lua_ref_(&obj_lua_ref), p_umf_(&umf) {
 | |
| 			}
 | |
| 
 | |
| 			template <typename Fx, std::size_t I, typename... R, typename... Args>
 | |
| 			int operator()(types<Fx>, meta::index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
 | |
| 				detail::default_construct func {};
 | |
| 				int result = stack::call_into_lua<checked, clean_stack>(r, a, L, start, func, this->obj_);
 | |
| 				// construct userdata table
 | |
| 				// SPECIFICALLY, after we've created it successfully.
 | |
| 				// If the constructor exits for any reason we have to break things down...
 | |
| 				if constexpr (clean_stack) {
 | |
| 					obj_lua_ref_->push();
 | |
| 					(*this->p_umf_)();
 | |
| 					obj_lua_ref_->pop();
 | |
| 				}
 | |
| 				else {
 | |
| 					(*this->p_umf_)();
 | |
| 				}
 | |
| 				return result;
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		namespace overload_detail {
 | |
| 			template <std::size_t... M, typename Match, typename... Args>
 | |
| 			inline int overload_match_arity(types<>, std::index_sequence<>, std::index_sequence<M...>, 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 <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args>
 | |
| 			inline int overload_match_arity(types<Fx, Fxs...>, std::index_sequence<I, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L,
 | |
| 			     int fxarity, int start, Args&&... args) {
 | |
| 				typedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits;
 | |
| 				typedef meta::tuple_types<typename traits::return_type> 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<traits::free_arity>, meta::index_value<M>...>::value) {
 | |
| 					return overload_match_arity(types<Fxs...>(),
 | |
| 					     std::index_sequence<In...>(),
 | |
| 					     std::index_sequence<M...>(),
 | |
| 					     std::forward<Match>(matchfx),
 | |
| 					     L,
 | |
| 					     fxarity,
 | |
| 					     start,
 | |
| 					     std::forward<Args>(args)...);
 | |
| 				}
 | |
| 				else {
 | |
| 					if constexpr (!traits::runtime_variadics_t::value) {
 | |
| 						if (traits::free_arity != fxarity) {
 | |
| 							return overload_match_arity(types<Fxs...>(),
 | |
| 							     std::index_sequence<In...>(),
 | |
| 							     std::index_sequence<traits::free_arity, M...>(),
 | |
| 							     std::forward<Match>(matchfx),
 | |
| 							     L,
 | |
| 							     fxarity,
 | |
| 							     start,
 | |
| 							     std::forward<Args>(args)...);
 | |
| 						}
 | |
| 					}
 | |
| 					stack::record tracking {};
 | |
| 					if (!stack::stack_detail::check_types(args_list(), L, start, &no_panic, tracking)) {
 | |
| 						return overload_match_arity(types<Fxs...>(),
 | |
| 						     std::index_sequence<In...>(),
 | |
| 						     std::index_sequence<M...>(),
 | |
| 						     std::forward<Match>(matchfx),
 | |
| 						     L,
 | |
| 						     fxarity,
 | |
| 						     start,
 | |
| 						     std::forward<Args>(args)...);
 | |
| 					}
 | |
| 					return matchfx(types<Fx>(), meta::index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			template <std::size_t... M, typename Match, typename... Args>
 | |
| 			inline int overload_match_arity_single(
 | |
| 			     types<>, std::index_sequence<>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
 | |
| 				return overload_match_arity(types<>(),
 | |
| 				     std::index_sequence<>(),
 | |
| 				     std::index_sequence<M...>(),
 | |
| 				     std::forward<Match>(matchfx),
 | |
| 				     L,
 | |
| 				     fxarity,
 | |
| 				     start,
 | |
| 				     std::forward<Args>(args)...);
 | |
| 			}
 | |
| 
 | |
| 			template <typename Fx, std::size_t I, std::size_t... M, typename Match, typename... Args>
 | |
| 			inline int overload_match_arity_single(
 | |
| 			     types<Fx>, std::index_sequence<I>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
 | |
| 				typedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits;
 | |
| 				typedef meta::tuple_types<typename traits::return_type> 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<traits::free_arity>, meta::index_value<M>...>::value) {
 | |
| 					return overload_match_arity(types<>(),
 | |
| 					     std::index_sequence<>(),
 | |
| 					     std::index_sequence<M...>(),
 | |
| 					     std::forward<Match>(matchfx),
 | |
| 					     L,
 | |
| 					     fxarity,
 | |
| 					     start,
 | |
| 					     std::forward<Args>(args)...);
 | |
| 				}
 | |
| 				if constexpr (!traits::runtime_variadics_t::value) {
 | |
| 					if (traits::free_arity != fxarity) {
 | |
| 						return overload_match_arity(types<>(),
 | |
| 						     std::index_sequence<>(),
 | |
| 						     std::index_sequence<traits::free_arity, M...>(),
 | |
| 						     std::forward<Match>(matchfx),
 | |
| 						     L,
 | |
| 						     fxarity,
 | |
| 						     start,
 | |
| 						     std::forward<Args>(args)...);
 | |
| 					}
 | |
| 				}
 | |
| 				return matchfx(types<Fx>(), meta::index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
 | |
| 			}
 | |
| 
 | |
| 			template <typename Fx, typename Fx1, typename... Fxs, std::size_t I, std::size_t I1, std::size_t... In, std::size_t... M, typename Match,
 | |
| 			     typename... Args>
 | |
| 			inline int overload_match_arity_single(types<Fx, Fx1, Fxs...>, std::index_sequence<I, I1, In...>, std::index_sequence<M...>, Match&& matchfx,
 | |
| 			     lua_State* L, int fxarity, int start, Args&&... args) {
 | |
| 				typedef lua_bind_traits<meta::unwrap_unqualified_t<Fx>> traits;
 | |
| 				typedef meta::tuple_types<typename traits::return_type> 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<traits::free_arity>, meta::index_value<M>...>::value) {
 | |
| 					return overload_match_arity(types<Fx1, Fxs...>(),
 | |
| 					     std::index_sequence<I1, In...>(),
 | |
| 					     std::index_sequence<M...>(),
 | |
| 					     std::forward<Match>(matchfx),
 | |
| 					     L,
 | |
| 					     fxarity,
 | |
| 					     start,
 | |
| 					     std::forward<Args>(args)...);
 | |
| 				}
 | |
| 				else {
 | |
| 					if constexpr (!traits::runtime_variadics_t::value) {
 | |
| 						if (traits::free_arity != fxarity) {
 | |
| 							return overload_match_arity(types<Fx1, Fxs...>(),
 | |
| 							     std::index_sequence<I1, In...>(),
 | |
| 							     std::index_sequence<traits::free_arity, M...>(),
 | |
| 							     std::forward<Match>(matchfx),
 | |
| 							     L,
 | |
| 							     fxarity,
 | |
| 							     start,
 | |
| 							     std::forward<Args>(args)...);
 | |
| 						}
 | |
| 					}
 | |
| 					stack::record tracking {};
 | |
| 					if (!stack::stack_detail::check_types(args_list(), L, start, &no_panic, tracking)) {
 | |
| 						return overload_match_arity(types<Fx1, Fxs...>(),
 | |
| 						     std::index_sequence<I1, In...>(),
 | |
| 						     std::index_sequence<M...>(),
 | |
| 						     std::forward<Match>(matchfx),
 | |
| 						     L,
 | |
| 						     fxarity,
 | |
| 						     start,
 | |
| 						     std::forward<Args>(args)...);
 | |
| 					}
 | |
| 					return matchfx(types<Fx>(), meta::index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
 | |
| 				}
 | |
| 			}
 | |
| 		} // namespace overload_detail
 | |
| 
 | |
| 		template <typename... Functions, typename Match, typename... Args>
 | |
| 		inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
 | |
| 			return overload_detail::overload_match_arity_single(types<Functions...>(),
 | |
| 			     std::make_index_sequence<sizeof...(Functions)>(),
 | |
| 			     std::index_sequence<>(),
 | |
| 			     std::forward<Match>(matchfx),
 | |
| 			     L,
 | |
| 			     fxarity,
 | |
| 			     start,
 | |
| 			     std::forward<Args>(args)...);
 | |
| 		}
 | |
| 
 | |
| 		template <typename... Functions, typename Match, typename... Args>
 | |
| 		inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) {
 | |
| 			int fxarity = lua_gettop(L) - (start - 1);
 | |
| 			return overload_match_arity<Functions...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
 | |
| 		}
 | |
| 
 | |
| 		template <typename T, typename... TypeLists, typename Match, typename... Args>
 | |
| 		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<decltype(void_call<T, TypeLists>::call)...>(
 | |
| 			     std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
 | |
| 		}
 | |
| 
 | |
| 		template <typename T, bool checked, bool clean_stack, typename... TypeLists>
 | |
| 		inline int construct_trampolined(lua_State* L) {
 | |
| 			static const auto& meta = usertype_traits<T>::metatable();
 | |
| 			int argcount = lua_gettop(L);
 | |
| 			call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot;
 | |
| 			argcount -= static_cast<int>(syntax);
 | |
| 
 | |
| 			T* obj = detail::usertype_allocate<T>(L);
 | |
| 			reference userdataref(L, -1);
 | |
| 			stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on<T>);
 | |
| 
 | |
| 			// put userdata at the first index
 | |
| 			lua_insert(L, 1);
 | |
| 			construct_match<T, TypeLists...>(constructor_match<T, checked, clean_stack>(obj, userdataref, umf), L, argcount, 1 + static_cast<int>(syntax));
 | |
| 
 | |
| 			userdataref.push();
 | |
| 			return 1;
 | |
| 		}
 | |
| 
 | |
| 		template <typename T, bool checked, bool clean_stack, typename... TypeLists>
 | |
| 		inline int construct(lua_State* L) {
 | |
| 			return detail::static_trampoline<&construct_trampolined<T, checked, clean_stack, TypeLists...>>(L);
 | |
| 		}
 | |
| 
 | |
| 		template <typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename = void>
 | |
| 		struct agnostic_lua_call_wrapper {
 | |
| 			template <typename Fx, typename... Args>
 | |
| 			static int call(lua_State* L, Fx&& f, Args&&... args) {
 | |
| 				using uFx = meta::unqualified_t<Fx>;
 | |
| 				static constexpr bool is_ref = is_lua_reference_v<uFx>;
 | |
| 				if constexpr (is_ref) {
 | |
| 					if constexpr (is_index) {
 | |
| 						return stack::push(L, std::forward<Fx>(f), std::forward<Args>(args)...);
 | |
| 					}
 | |
| 					else {
 | |
| 						std::forward<Fx>(f) = stack::unqualified_get<F>(L, boost + (is_variable ? 3 : 1));
 | |
| 						return 0;
 | |
| 					}
 | |
| 				}
 | |
| 				else {
 | |
| 					using wrap = wrapper<uFx>;
 | |
| 					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<uFx> && std::is_convertible_v<std::decay_t<Fx>, fp_t>;
 | |
| 					if constexpr (is_function_pointer_convertible) {
 | |
| 						fp_t fx = f;
 | |
| 						return agnostic_lua_call_wrapper<fp_t, is_index, is_variable, checked, boost, clean_stack> {}.call(
 | |
| 						     L, fx, std::forward<Args>(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<checked, clean_stack>(
 | |
| 						     returns_list(), args_list(), L, boost + 1, caller(), std::forward<Fx>(f), std::forward<Args>(args)...);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct agnostic_lua_call_wrapper<var_wrapper<T>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			template <typename F>
 | |
| 			static int call(lua_State* L, F&& f) {
 | |
| 				if constexpr (is_index) {
 | |
| 					constexpr bool is_stack = is_stack_based_v<meta::unqualified_t<decltype(detail::unwrap(f.value()))>>;
 | |
| 					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<meta::unwrapped_t<T>>) {
 | |
| 						(void)f;
 | |
| 						return luaL_error(L, "sol: cannot write to a readonly (const) variable");
 | |
| 					}
 | |
| 					else {
 | |
| 						using R = meta::unwrapped_t<T>;
 | |
| 						if constexpr (std::is_assignable_v<std::add_lvalue_reference_t<meta::unqualified_t<R>>, R>) {
 | |
| 							detail::unwrap(f.value()) = stack::unqualified_get<meta::unwrapped_t<T>>(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 <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct agnostic_lua_call_wrapper<lua_CFunction_ref, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			static int call(lua_State* L, lua_CFunction_ref f) {
 | |
| 				return f(L);
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct agnostic_lua_call_wrapper<lua_CFunction, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			static int call(lua_State* L, lua_CFunction f) {
 | |
| 				return f(L);
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| #if SOL_IS_ON(SOL_USE_NOEXCEPT_FUNCTION_TYPE_I_)
 | |
| 		template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct agnostic_lua_call_wrapper<detail::lua_CFunction_noexcept, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			static int call(lua_State* L, detail::lua_CFunction_noexcept f) {
 | |
| 				return f(L);
 | |
| 			}
 | |
| 		};
 | |
| #endif // noexcept function types
 | |
| 
 | |
| 		template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct agnostic_lua_call_wrapper<detail::no_prop, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			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 <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct agnostic_lua_call_wrapper<no_construction, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			static int call(lua_State* L, const no_construction&) {
 | |
| 				return function_detail::no_construction_error(L);
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct agnostic_lua_call_wrapper<bases<Args...>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			static int call(lua_State*, const bases<Args...>&) {
 | |
| 				// Uh. How did you even call this, lul
 | |
| 				return 0;
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct agnostic_lua_call_wrapper<std::reference_wrapper<T>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			static int call(lua_State* L, std::reference_wrapper<T> f) {
 | |
| 				agnostic_lua_call_wrapper<T, is_index, is_variable, checked, boost, clean_stack> alcw {};
 | |
| 				return alcw.call(L, f.get());
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, typename F, bool is_index, bool is_variable, bool checked = detail::default_safe_function_calls, int boost = 0,
 | |
| 		     bool clean_stack = true, typename = void>
 | |
| 		struct lua_call_wrapper {
 | |
| 			template <typename Fx, typename... Args>
 | |
| 			static int call(lua_State* L, Fx&& fx, Args&&... args) {
 | |
| 				if constexpr (std::is_member_function_pointer_v<F>) {
 | |
| 					using wrap = wrapper<F>;
 | |
| 					using object_type = typename wrap::object_type;
 | |
| 					if constexpr (sizeof...(Args) < 1) {
 | |
| 						using Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>;
 | |
| 						static_assert(std::is_base_of_v<object_type, Ta>,
 | |
| 						     "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<T>(...) 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<Ta*>(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<object_type*>(maybeo.value());
 | |
| 						return call(L, std::forward<Fx>(fx), *o);
 | |
| #else
 | |
| 						object_type& o = static_cast<object_type&>(*stack::unqualified_get<non_null<Ta*>>(L, 1));
 | |
| 						return call(L, std::forward<Fx>(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<checked, clean_stack>(
 | |
| 						     returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(fx), std::forward<Args>(args)...);
 | |
| 					}
 | |
| 				}
 | |
| 				else if constexpr (std::is_member_object_pointer_v<F>) {
 | |
| 					using wrap = wrapper<F>;
 | |
| 					using object_type = typename wrap::object_type;
 | |
| 					if constexpr (is_index) {
 | |
| 						if constexpr (sizeof...(Args) < 1) {
 | |
| 							using Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>;
 | |
| 							static_assert(std::is_base_of_v<object_type, Ta>,
 | |
| 							     "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<T>(...) 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<Ta*>(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<object_type*>(maybeo.value());
 | |
| 							return call(L, std::forward<Fx>(fx), *o);
 | |
| #else
 | |
| 							object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1));
 | |
| 							return call(L, std::forward<Fx>(fx), o);
 | |
| #endif // Safety
 | |
| 						}
 | |
| 						else {
 | |
| 							using returns_list = typename wrap::returns_list;
 | |
| 							using caller = typename wrap::caller;
 | |
| 							return stack::call_into_lua<checked, clean_stack>(returns_list(),
 | |
| 							     types<>(),
 | |
| 							     L,
 | |
| 							     boost + (is_variable ? 3 : 2),
 | |
| 							     caller(),
 | |
| 							     std::forward<Fx>(fx),
 | |
| 							     std::forward<Args>(args)...);
 | |
| 						}
 | |
| 					}
 | |
| 					else {
 | |
| 						using traits_type = lua_bind_traits<F>;
 | |
| 						using return_type = typename traits_type::return_type;
 | |
| 						constexpr bool ret_is_const = std::is_const_v<std::remove_reference_t<return_type>>;
 | |
| 						if constexpr (ret_is_const) {
 | |
| 							(void)fx;
 | |
| 							(void)detail::swallow { 0, (static_cast<void>(args), 0)... };
 | |
| 							return luaL_error(L, "sol: cannot write to a readonly (const) variable");
 | |
| 						}
 | |
| 						else {
 | |
| 							using u_return_type = meta::unqualified_t<return_type>;
 | |
| 							constexpr bool is_assignable = std::is_copy_assignable_v<u_return_type> || std::is_array_v<u_return_type>;
 | |
| 							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<checked, clean_stack>(types<void>(),
 | |
| 									     args_list(),
 | |
| 									     L,
 | |
| 									     boost + (is_variable ? 3 : 2),
 | |
| 									     caller(),
 | |
| 									     std::forward<Fx>(fx),
 | |
| 									     std::forward<Args>(args)...);
 | |
| 								}
 | |
| 								else {
 | |
| 									using Ta = meta::conditional_t<std::is_void_v<T>, object_type, T>;
 | |
| #if SOL_IS_ON(SOL_SAFE_USERTYPE_I_)
 | |
| 									auto maybeo = stack::check_get<Ta*>(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<object_type*>(maybeo.value());
 | |
| 									object_type& o = *po;
 | |
| #else
 | |
| 									object_type& o = static_cast<object_type&>(*stack::get<non_null<Ta*>>(L, 1));
 | |
| #endif // Safety
 | |
| 
 | |
| 									return stack::call_into_lua<checked, clean_stack>(
 | |
| 									     types<void>(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), std::forward<Fx>(fx), o);
 | |
| 								}
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				else {
 | |
| 					agnostic_lua_call_wrapper<F, is_index, is_variable, checked, boost, clean_stack> alcw {};
 | |
| 					return alcw.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
 | |
| 				}
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, typename F, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct lua_call_wrapper<T, readonly_wrapper<F>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			using traits_type = lua_bind_traits<F>;
 | |
| 			using wrap = wrapper<F>;
 | |
| 			using object_type = typename wrap::object_type;
 | |
| 
 | |
| 			static int call(lua_State* L, readonly_wrapper<F>&& rw) {
 | |
| 				if constexpr (!is_index) {
 | |
| 					(void)rw;
 | |
| 					return luaL_error(L, "sol: cannot write to a sol::readonly variable");
 | |
| 				}
 | |
| 				else {
 | |
| 					lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw;
 | |
| 					return lcw.call(L, std::move(rw.value()));
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			static int call(lua_State* L, readonly_wrapper<F>&& rw, object_type& o) {
 | |
| 				if constexpr (!is_index) {
 | |
| 					(void)o;
 | |
| 					return call(L, std::move(rw));
 | |
| 				}
 | |
| 				else {
 | |
| 					lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw;
 | |
| 					return lcw.call(L, rw.value(), o);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			static int call(lua_State* L, const readonly_wrapper<F>& rw) {
 | |
| 				if constexpr (!is_index) {
 | |
| 					(void)rw;
 | |
| 					return luaL_error(L, "sol: cannot write to a sol::readonly variable");
 | |
| 				}
 | |
| 				else {
 | |
| 					lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw;
 | |
| 					return lcw.call(L, rw.value());
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			static int call(lua_State* L, const readonly_wrapper<F>& rw, object_type& o) {
 | |
| 				if constexpr (!is_index) {
 | |
| 					(void)o;
 | |
| 					return call(L, rw);
 | |
| 				}
 | |
| 				else {
 | |
| 					lua_call_wrapper<T, F, true, is_variable, checked, boost, clean_stack, C> lcw;
 | |
| 					return lcw.call(L, rw.value(), o);
 | |
| 				}
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, typename... Args, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct lua_call_wrapper<T, constructor_list<Args...>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			typedef constructor_list<Args...> F;
 | |
| 
 | |
| 			static int call(lua_State* L, F&) {
 | |
| 				const auto& meta = usertype_traits<T>::metatable();
 | |
| 				int argcount = lua_gettop(L);
 | |
| 				call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1) : call_syntax::dot;
 | |
| 				argcount -= static_cast<int>(syntax);
 | |
| 
 | |
| 				T* obj = detail::usertype_allocate<T>(L);
 | |
| 				reference userdataref(L, -1);
 | |
| 				stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on<T>);
 | |
| 
 | |
| 				// put userdata at the first index
 | |
| 				lua_insert(L, 1);
 | |
| 				// Because of the way constructors work,
 | |
| 				// we have to kill the data, but only if the cosntructor is successfulyl invoked...
 | |
| 				// if it's not successfully invoked and we panic,
 | |
| 				// we cannot actually deallcoate/delete the data.
 | |
| 				construct_match<T, Args...>(
 | |
| 				     constructor_match<T, checked, clean_stack>(obj, userdataref, umf), L, argcount, boost + 1 + 1 + static_cast<int>(syntax));
 | |
| 
 | |
| 				userdataref.push();
 | |
| 				return 1;
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, typename... Cxs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct lua_call_wrapper<T, constructor_wrapper<Cxs...>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			typedef constructor_wrapper<Cxs...> F;
 | |
| 
 | |
| 			struct onmatch {
 | |
| 				template <typename Fx, std::size_t I, typename... R, typename... Args>
 | |
| 				int operator()(types<Fx>, meta::index_value<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start, F& f) {
 | |
| 					const auto& meta = usertype_traits<T>::metatable();
 | |
| 					T* obj = detail::usertype_allocate<T>(L);
 | |
| 					reference userdataref(L, -1);
 | |
| 					stack::stack_detail::undefined_metatable umf(L, &meta[0], &stack::stack_detail::set_undefined_methods_on<T>);
 | |
| 					umf();
 | |
| 
 | |
| 					auto& func = std::get<I>(f.functions);
 | |
| 					// put userdata at the first index
 | |
| 					lua_insert(L, 1);
 | |
| 					stack::call_into_lua<checked, clean_stack>(r, a, L, boost + 1 + start, func, detail::implicit_wrapper<T>(obj));
 | |
| 
 | |
| 					userdataref.push();
 | |
| 					return 1;
 | |
| 				}
 | |
| 			};
 | |
| 
 | |
| 			static int call(lua_State* L, F& f) {
 | |
| 				call_syntax syntax = stack::get_call_syntax(L, usertype_traits<T>::user_metatable(), 1);
 | |
| 				int syntaxval = static_cast<int>(syntax);
 | |
| 				int argcount = lua_gettop(L) - syntaxval;
 | |
| 				return construct_match<T, meta::pop_front_type_t<meta::function_args_t<Cxs>>...>(onmatch(), L, argcount, 1 + syntaxval, f);
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, typename Fx, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct lua_call_wrapper<T, destructor_wrapper<Fx>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 
 | |
| 			template <typename F>
 | |
| 			static int call(lua_State* L, F&& f) {
 | |
| 				if constexpr (std::is_void_v<Fx>) {
 | |
| 					return detail::usertype_alloc_destroy<T>(L);
 | |
| 				}
 | |
| 				else {
 | |
| 					using uFx = meta::unqualified_t<Fx>;
 | |
| 					lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw {};
 | |
| 					return lcw.call(L, std::forward<F>(f).fx);
 | |
| 				}
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct lua_call_wrapper<T, overload_set<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			typedef overload_set<Fs...> F;
 | |
| 
 | |
| 			struct on_match {
 | |
| 				template <typename Fx, std::size_t I, typename... R, typename... Args>
 | |
| 				int operator()(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) {
 | |
| 					auto& f = std::get<I>(fx.functions);
 | |
| 					return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost> {}.call(L, f);
 | |
| 				}
 | |
| 			};
 | |
| 
 | |
| 			static int call(lua_State* L, F& fx) {
 | |
| 				return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L), 1, fx);
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, typename... Fs, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct lua_call_wrapper<T, factory_wrapper<Fs...>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			typedef factory_wrapper<Fs...> F;
 | |
| 
 | |
| 			struct on_match {
 | |
| 				template <typename Fx, std::size_t I, typename... R, typename... Args>
 | |
| 				int operator()(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, F& fx) {
 | |
| 					auto& f = std::get<I>(fx.functions);
 | |
| 					return lua_call_wrapper<T, Fx, is_index, is_variable, checked, boost, clean_stack> {}.call(L, f);
 | |
| 				}
 | |
| 			};
 | |
| 
 | |
| 			static int call(lua_State* L, F& fx) {
 | |
| 				return overload_match_arity<Fs...>(on_match(), L, lua_gettop(L) - boost, 1 + boost, fx);
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, typename R, typename W, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct lua_call_wrapper<T, property_wrapper<R, W>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			typedef meta::conditional_t<is_index, R, W> P;
 | |
| 			typedef meta::unqualified_t<P> U;
 | |
| 			typedef wrapper<U> wrap;
 | |
| 			typedef lua_bind_traits<U> traits_type;
 | |
| 			typedef meta::unqualified_t<typename traits_type::template arg_at<0>> object_type;
 | |
| 
 | |
| 			template <typename F, typename... Args>
 | |
| 			static int call(lua_State* L, F&& f, Args&&... args) {
 | |
| 				constexpr bool is_specialized = meta::any<std::is_same<U, detail::no_prop>,
 | |
| 				     meta::is_specialization_of<U, var_wrapper>,
 | |
| 				     meta::is_specialization_of<U, constructor_wrapper>,
 | |
| 				     meta::is_specialization_of<U, constructor_list>,
 | |
| 				     std::is_member_pointer<U>>::value;
 | |
| 				if constexpr (is_specialized) {
 | |
| 					if constexpr (is_index) {
 | |
| 						decltype(auto) p = f.read();
 | |
| 						lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack> lcw {};
 | |
| 						return lcw.call(L, p, std::forward<Args>(args)...);
 | |
| 					}
 | |
| 					else {
 | |
| 						decltype(auto) p = f.write();
 | |
| 						lua_call_wrapper<T, meta::unqualified_t<decltype(p)>, is_index, is_variable, checked, boost, clean_stack> lcw {};
 | |
| 						return lcw.call(L, p, std::forward<Args>(args)...);
 | |
| 					}
 | |
| 				}
 | |
| 				else {
 | |
| 					constexpr bool non_class_object_type = meta::any<std::is_void<object_type>,
 | |
| 					     meta::boolean<lua_type_of<meta::unwrap_unqualified_t<object_type>>::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<checked, clean_stack>(
 | |
| 							     returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf);
 | |
| 						}
 | |
| 						else {
 | |
| 							decltype(auto) pf = f.write();
 | |
| 							return stack::call_into_lua<checked, clean_stack>(
 | |
| 							     returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf);
 | |
| 						}
 | |
| 					}
 | |
| 					else {
 | |
| 						using args_list = meta::pop_front_type_t<typename traits_type::free_args_list>;
 | |
| 						using Ta = T;
 | |
| 						using Oa = std::remove_pointer_t<object_type>;
 | |
| #if SOL_IS_ON(SOL_SAFE_USERTYPE_I_)
 | |
| 						auto maybeo = stack::check_get<Ta*>(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<Oa*>(maybeo.value());
 | |
| #else
 | |
| 						Oa* o = static_cast<Oa*>(stack::get<non_null<Ta*>>(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<checked, clean_stack>(
 | |
| 							     returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf, detail::implicit_wrapper<Oa>(*o));
 | |
| 						}
 | |
| 						else {
 | |
| 							decltype(auto) pf = f.write();
 | |
| 							return stack::call_into_lua<checked, clean_stack>(
 | |
| 							     returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), pf, detail::implicit_wrapper<Oa>(*o));
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, typename V, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct lua_call_wrapper<T, protect_t<V>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			typedef protect_t<V> F;
 | |
| 
 | |
| 			template <typename... Args>
 | |
| 			static int call(lua_State* L, F& fx, Args&&... args) {
 | |
| 				return lua_call_wrapper<T, V, is_index, is_variable, true, boost, clean_stack> {}.call(L, fx.value, std::forward<Args>(args)...);
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, typename F, typename... Policies, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct lua_call_wrapper<T, policy_wrapper<F, Policies...>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			typedef policy_wrapper<F, Policies...> P;
 | |
| 
 | |
| 			template <std::size_t... In>
 | |
| 			static int call(std::index_sequence<In...>, lua_State* L, P& fx) {
 | |
| 				int pushed = lua_call_wrapper<T, F, is_index, is_variable, checked, boost, false, C> {}.call(L, fx.value);
 | |
| 				(void)detail::swallow { int(), (policy_detail::handle_policy(std::get<In>(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 <typename T, typename Y, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct lua_call_wrapper<T, yielding_t<Y>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			template <typename F>
 | |
| 			static int call(lua_State* L, F&& f) {
 | |
| 				return lua_call_wrapper<T, meta::unqualified_t<Y>, is_index, is_variable, checked, boost, clean_stack> {}.call(L, f.func);
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
 | |
| 		struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, clean_stack, C> {
 | |
| 			static int call(lua_State* L, const function_arguments<Sig, P>& f) {
 | |
| 				lua_call_wrapper<T, meta::unqualified_t<P>, 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<Sig, P>& f) {
 | |
| 				lua_call_wrapper<T, meta::unqualified_t<P>, 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<Sig, P>&& f) {
 | |
| 				lua_call_wrapper<T, meta::unqualified_t<P>, is_index, is_variable, checked, boost, clean_stack> lcw {};
 | |
| 				return lcw.call(L, std::get<0>(std::move(f.arguments)));
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		template <typename T, bool is_index, bool is_variable, int boost = 0, bool checked = detail::default_safe_function_calls, bool clean_stack = true,
 | |
| 		     typename Fx, typename... Args>
 | |
| 		inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) {
 | |
| 			using uFx = meta::unqualified_t<Fx>;
 | |
| 			if constexpr (meta::is_specialization_of_v<uFx, yielding_t>) {
 | |
| 				using real_fx = meta::unqualified_t<decltype(std::forward<Fx>(fx).func)>;
 | |
| 				lua_call_wrapper<T, real_fx, is_index, is_variable, checked, boost, clean_stack> lcw {};
 | |
| 				return lcw.call(L, std::forward<Fx>(fx).func, std::forward<Args>(args)...);
 | |
| 			}
 | |
| 			else {
 | |
| 				lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack> lcw {};
 | |
| 				return lcw.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls,
 | |
| 		     bool clean_stack = true>
 | |
| 		inline int call_user(lua_State* L) {
 | |
| 			auto& fx = stack::unqualified_get<user<F>>(L, upvalue_index(start));
 | |
| 			using uFx = meta::unqualified_t<F>;
 | |
| 			int nr = call_wrapped<T, is_index, is_variable, 0, checked, clean_stack>(L, fx);
 | |
| 			if constexpr (meta::is_specialization_of_v<uFx, yielding_t>) {
 | |
| 				return lua_yield(L, nr);
 | |
| 			}
 | |
| 			else {
 | |
| 				return nr;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		template <typename T, typename = void>
 | |
| 		struct is_var_bind : std::false_type { };
 | |
| 
 | |
| 		template <typename T>
 | |
| 		struct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type { };
 | |
| 
 | |
| 		template <typename T>
 | |
| 		struct is_var_bind<T, std::enable_if_t<is_lua_reference_or_proxy<T>::value>> : std::true_type { };
 | |
| 
 | |
| 		template <>
 | |
| 		struct is_var_bind<detail::no_prop> : std::true_type { };
 | |
| 
 | |
| 		template <typename R, typename W>
 | |
| 		struct is_var_bind<property_wrapper<R, W>> : std::true_type { };
 | |
| 
 | |
| 		template <typename T>
 | |
| 		struct is_var_bind<var_wrapper<T>> : std::true_type { };
 | |
| 
 | |
| 		template <typename T>
 | |
| 		struct is_var_bind<readonly_wrapper<T>> : is_var_bind<meta::unqualified_t<T>> { };
 | |
| 
 | |
| 		template <typename F, typename... Policies>
 | |
| 		struct is_var_bind<policy_wrapper<F, Policies...>> : is_var_bind<meta::unqualified_t<F>> { };
 | |
| 	} // namespace call_detail
 | |
| 
 | |
| 	template <typename T>
 | |
| 	struct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> { };
 | |
| 
 | |
| 	template <typename T>
 | |
| 	using is_var_wrapper = meta::is_specialization_of<T, var_wrapper>;
 | |
| 
 | |
| 	template <typename T>
 | |
| 	struct is_function_binding : meta::neg<is_variable_binding<T>> { };
 | |
| 
 | |
| } // namespace sol
 | |
| 
 | |
| #endif // SOL_CALL_HPP
 |