1 // The MIT License (MIT)
2 
3 // Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal in
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 // the Software, and to permit persons to whom the Software is furnished to do so,
10 // subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #ifndef SOL_FUNCTION_TYPES_HPP
23 #define SOL_FUNCTION_TYPES_HPP
24 
25 #include "function_types_core.hpp"
26 #include "function_types_templated.hpp"
27 #include "function_types_stateless.hpp"
28 #include "function_types_stateful.hpp"
29 #include "function_types_overloaded.hpp"
30 #include "resolve.hpp"
31 #include "call.hpp"
32 
33 namespace sol {
34 	namespace stack {
35 		template<typename... Sigs>
36 		struct pusher<function_sig<Sigs...>> {
37 			template <typename... Sig, typename Fx, typename... Args>
select_convertiblesol::stack::pusher38 			static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) {
39 				typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
40 				typedef function_detail::functor_function<clean_fx> F;
41 				set_fx<F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
42 			}
43 
44 			template <typename R, typename... A, typename Fx, typename... Args>
select_convertiblesol::stack::pusher45 			static void select_convertible(std::true_type, types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
46 				using fx_ptr_t = R(*)(A...);
47 				fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
48 				select_function(std::true_type(), L, fxptr, std::forward<Args>(args)...);
49 			}
50 
51 			template <typename R, typename... A, typename Fx, typename... Args>
select_convertiblesol::stack::pusher52 			static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) {
53 				typedef std::decay_t<meta::unwrap_unqualified_t<Fx>> raw_fx_t;
54 				typedef R(*fx_ptr_t)(A...);
55 				typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible;
56 				select_convertible(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...);
57 			}
58 
59 			template <typename Fx, typename... Args>
select_convertiblesol::stack::pusher60 			static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
61 				typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig;
62 				select_convertible(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
63 			}
64 
65 			template <typename Fx, typename T, typename... Args>
select_reference_member_variablesol::stack::pusher66 			static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
67 				typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
68 				typedef function_detail::member_variable<meta::unwrap_unqualified_t<T>, clean_fx> F;
69 				set_fx<F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
70 			}
71 
72 			template <typename Fx, typename T, typename... Args>
select_reference_member_variablesol::stack::pusher73 			static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
74 				typedef std::decay_t<Fx> dFx;
75 				dFx memfxptr(std::forward<Fx>(fx));
76 				auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
77 				lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
78 
79 				int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
80 				upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
81 				stack::push(L, c_closure(freefunc, upvalues));
82 			}
83 
84 			template <typename Fx, typename... Args>
select_member_variablesol::stack::pusher85 			static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
86 				select_convertible(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
87 			}
88 
89 			template <typename Fx, typename T, typename... Args>
select_member_variablesol::stack::pusher90 			static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
91 				typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
92 				select_reference_member_variable(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
93 			}
94 
95 			template <typename Fx>
select_member_variablesol::stack::pusher96 			static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) {
97 				typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
98 				lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call;
99 				int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
100 				stack::push(L, c_closure(freefunc, upvalues));
101 			}
102 
103 			template <typename Fx, typename T, typename... Args>
select_reference_member_functionsol::stack::pusher104 			static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
105 				typedef std::decay_t<Fx> clean_fx;
106 				typedef function_detail::member_function<meta::unwrap_unqualified_t<T>, clean_fx> F;
107 				set_fx<F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
108 			}
109 
110 			template <typename Fx, typename T, typename... Args>
select_reference_member_functionsol::stack::pusher111 			static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
112 				typedef std::decay_t<Fx> dFx;
113 				dFx memfxptr(std::forward<Fx>(fx));
114 				auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
115 				lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
116 
117 				int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
118 				upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
119 				stack::push(L, c_closure(freefunc, upvalues));
120 			}
121 
122 			template <typename Fx, typename... Args>
select_member_functionsol::stack::pusher123 			static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
124 				select_member_variable(std::is_member_object_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
125 			}
126 
127 			template <typename Fx, typename T, typename... Args>
select_member_functionsol::stack::pusher128 			static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
129 				typedef meta::boolean<meta::is_specialization_of<std::reference_wrapper, meta::unqualified_t<T>>::value || std::is_pointer<T>::value> is_reference;
130 				select_reference_member_function(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
131 			}
132 
133 			template <typename Fx>
select_member_functionsol::stack::pusher134 			static void select_member_function(std::true_type, lua_State* L, Fx&& fx) {
135 				typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
136 				lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call;
137 				int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
138 				stack::push(L, c_closure(freefunc, upvalues));
139 			}
140 
141 			template <typename Fx, typename... Args>
select_functionsol::stack::pusher142 			static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
143 				select_member_function(std::is_member_function_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
144 			}
145 
146 			template <typename Fx, typename... Args>
select_functionsol::stack::pusher147 			static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) {
148 				std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
149 				lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::call;
150 
151 				int upvalues = stack::stack_detail::push_as_upvalues(L, target);
152 				stack::push(L, c_closure(freefunc, upvalues));
153 			}
154 
select_functionsol::stack::pusher155 			static void select_function(std::true_type, lua_State* L, lua_CFunction f) {
156 				stack::push(L, f);
157 			}
158 
159 			template <typename Fx, typename... Args>
selectsol::stack::pusher160 			static void select(lua_State* L, Fx&& fx, Args&&... args) {
161 				select_function(std::is_function<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
162 			}
163 
164 			template <typename Fx, typename... Args>
set_fxsol::stack::pusher165 			static void set_fx(lua_State* L, Args&&... args) {
166 				lua_CFunction freefunc = function_detail::call<meta::unqualified_t<Fx>>;
167 
168 				stack::push_specific<user<Fx>>(L, std::forward<Args>(args)...);
169 				stack::push(L, c_closure(freefunc, 1));
170 			}
171 
172 			template<typename... Args>
pushsol::stack::pusher173 			static int push(lua_State* L, Args&&... args) {
174 				// Set will always place one thing (function) on the stack
175 				select(L, std::forward<Args>(args)...);
176 				return 1;
177 			}
178 		};
179 
180 		template<typename T, typename... Args>
181 		struct pusher<function_arguments<T, Args...>> {
182 			template <std::size_t... I, typename FP>
push_funcsol::stack::pusher183 			static int push_func(std::index_sequence<I...>, lua_State* L, FP&& fp) {
184 				return stack::push_specific<T>(L, detail::forward_get<I>(fp.arguments)...);
185 			}
186 
pushsol::stack::pusher187 			static int push(lua_State* L, const function_arguments<T, Args...>& fp) {
188 				return push_func(std::make_index_sequence<sizeof...(Args)>(), L, fp);
189 			}
190 
pushsol::stack::pusher191 			static int push(lua_State* L, function_arguments<T, Args...>&& fp) {
192 				return push_func(std::make_index_sequence<sizeof...(Args)>(), L, std::move(fp));
193 			}
194 		};
195 
196 		template<typename Signature>
197 		struct pusher<std::function<Signature>> {
pushsol::stack::pusher198 			static int push(lua_State* L, std::function<Signature> fx) {
199 				return pusher<function_sig<Signature>>{}.push(L, std::move(fx));
200 			}
201 		};
202 
203 		template<typename Signature>
204 		struct pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> {
205 			template <typename F>
pushsol::stack::pusher206 			static int push(lua_State* L, F&& f) {
207 				return pusher<function_sig<>>{}.push(L, std::forward<F>(f));
208 			}
209 		};
210 
211 		template<typename Signature>
212 		struct pusher<Signature, std::enable_if_t<meta::all<std::is_function<Signature>, meta::neg<std::is_same<Signature, lua_CFunction>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>>>::value>> {
213 			template <typename F>
pushsol::stack::pusher214 			static int push(lua_State* L, F&& f) {
215 				return pusher<function_sig<>>{}.push(L, std::forward<F>(f));
216 			}
217 		};
218 
219 		template<typename... Functions>
220 		struct pusher<overload_set<Functions...>> {
pushsol::stack::pusher221 			static int push(lua_State* L, overload_set<Functions...>&& set) {
222 				typedef function_detail::overloaded_function<Functions...> F;
223 				pusher<function_sig<>>{}.set_fx<F>(L, std::move(set.functions));
224 				return 1;
225 			}
226 
pushsol::stack::pusher227 			static int push(lua_State* L, const overload_set<Functions...>& set) {
228 				typedef function_detail::overloaded_function<Functions...> F;
229 				pusher<function_sig<>>{}.set_fx<F>(L, set.functions);
230 				return 1;
231 			}
232 		};
233 
234 		template <typename T>
235 		struct pusher<protect_t<T>> {
pushsol::stack::pusher236 			static int push(lua_State* L, protect_t<T>&& pw) {
237 				lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>>;
238 				int closures = stack::push_specific<user<protect_t<T>>>(L, std::move(pw.value));
239 				return stack::push(L, c_closure(cf, closures));
240 			}
241 
pushsol::stack::pusher242 			static int push(lua_State* L, const protect_t<T>& pw) {
243 				lua_CFunction cf = call_detail::call_user<void, false, false, protect_t<T>>;
244 				int closures = stack::push_specific<user<protect_t<T>>>(L, pw.value);
245 				return stack::push(L, c_closure(cf, closures));
246 			}
247 		};
248 
249 		template <typename F, typename G>
250 		struct pusher<property_wrapper<F, G>, std::enable_if_t<!std::is_void<F>::value && !std::is_void<G>::value>> {
pushsol::stack::pusher251 			static int push(lua_State* L, property_wrapper<F, G>&& pw) {
252 				return stack::push(L, sol::overload(std::move(pw.read), std::move(pw.write)));
253 			}
pushsol::stack::pusher254 			static int push(lua_State* L, const property_wrapper<F, G>& pw) {
255 				return stack::push(L, sol::overload(pw.read, pw.write));
256 			}
257 		};
258 
259 		template <typename F>
260 		struct pusher<property_wrapper<F, void>> {
pushsol::stack::pusher261 			static int push(lua_State* L, property_wrapper<F, void>&& pw) {
262 				return stack::push(L, std::move(pw.read));
263 			}
pushsol::stack::pusher264 			static int push(lua_State* L, const property_wrapper<F, void>& pw) {
265 				return stack::push(L, pw.read);
266 			}
267 		};
268 
269 		template <typename F>
270 		struct pusher<property_wrapper<void, F>> {
pushsol::stack::pusher271 			static int push(lua_State* L, property_wrapper<void, F>&& pw) {
272 				return stack::push(L, std::move(pw.write));
273 			}
pushsol::stack::pusher274 			static int push(lua_State* L, const property_wrapper<void, F>& pw) {
275 				return stack::push(L, pw.write);
276 			}
277 		};
278 
279 		template <typename T>
280 		struct pusher<var_wrapper<T>> {
pushsol::stack::pusher281 			static int push(lua_State* L, var_wrapper<T>&& vw) {
282 				return stack::push(L, std::move(vw.value));
283 			}
pushsol::stack::pusher284 			static int push(lua_State* L, const var_wrapper<T>& vw) {
285 				return stack::push(L, vw.value);
286 			}
287 		};
288 
289 		template <typename... Functions>
290 		struct pusher<factory_wrapper<Functions...>> {
pushsol::stack::pusher291 			static int push(lua_State* L, const factory_wrapper<Functions...>& fw) {
292 				typedef function_detail::overloaded_function<Functions...> F;
293 				pusher<function_sig<>>{}.set_fx<F>(L, fw.functions);
294 				return 1;
295 			}
296 
pushsol::stack::pusher297 			static int push(lua_State* L, factory_wrapper<Functions...>&& fw) {
298 				typedef function_detail::overloaded_function<Functions...> F;
299 				pusher<function_sig<>>{}.set_fx<F>(L, std::move(fw.functions));
300 				return 1;
301 			}
302 		};
303 
304 		template <typename T, typename... Lists>
305 		struct pusher<detail::tagged<T, constructor_list<Lists...>>> {
pushsol::stack::pusher306 			static int push(lua_State* L, detail::tagged<T, constructor_list<Lists...>>) {
307 				lua_CFunction cf = call_detail::construct<T, Lists...>;
308 				return stack::push(L, cf);
309 			}
310 		};
311 
312 		template <typename T, typename... Fxs>
313 		struct pusher<detail::tagged<T, constructor_wrapper<Fxs...>>> {
314 			template <typename C>
pushsol::stack::pusher315 			static int push(lua_State* L, C&& c) {
316 				lua_CFunction cf = call_detail::call_user<T, false, false, constructor_wrapper<Fxs...>>;
317 				int closures = stack::push_specific<user<constructor_wrapper<Fxs...>>>(L, std::forward<C>(c));
318 				return stack::push(L, c_closure(cf, closures));
319 			}
320 		};
321 
322 		template <typename T>
323 		struct pusher<detail::tagged<T, destructor_wrapper<void>>> {
pushsol::stack::pusher324 			static int push(lua_State* L, destructor_wrapper<void>) {
325 				lua_CFunction cf = detail::usertype_alloc_destroy<T>;
326 				return stack::push(L, cf);
327 			}
328 		};
329 
330 		template <typename T, typename Fx>
331 		struct pusher<detail::tagged<T, destructor_wrapper<Fx>>> {
pushsol::stack::pusher332 			static int push(lua_State* L, destructor_wrapper<Fx> c) {
333 				lua_CFunction cf = call_detail::call_user<T, false, false, destructor_wrapper<Fx>>;
334 				int closures = stack::push_specific<user<T>>(L, std::move(c));
335 				return stack::push(L, c_closure(cf, closures));
336 			}
337 		};
338 
339 	} // stack
340 } // sol
341 
342 #endif // SOL_FUNCTION_TYPES_HPP
343