1 #ifndef LUAGLUE_METHOD_H_GUARD
2 #define LUAGLUE_METHOD_H_GUARD
3 
4 #include <lua.hpp>
5 #include <string>
6 #include <tuple>
7 #include <utility>
8 
9 #include "LuaGlue/LuaGlueMethodBase.h"
10 #include "LuaGlue/LuaGlueObject.h"
11 #include "LuaGlue/LuaGlueApplyTuple.h"
12 #include "LuaGlue/LuaGlueDebug.h"
13 
14 #include "LuaGlue/LuaGlueBase.h"
15 
16 template<typename _Class>
17 class LuaGlueClass;
18 
19 template<typename _Ret, typename _Class, typename... _Args>
20 class LuaGlueMethod : public LuaGlueMethodBase
21 {
22 	private:
23         template < typename... T >
24         struct tuple
25         {
26             typedef std::tuple<typename std::remove_const<typename std::remove_reference<T>::type>::type...> type;
27         };
28 
29 	public:
30 		typedef _Class ClassType;
31 		typedef _Ret ReturnType;
32 		typedef _Ret (_Class::*MethodType)( _Args... );
33 
LuaGlueMethod(LuaGlueClass<_Class> * luaClass,const std::string & name,MethodType && fn)34 		LuaGlueMethod(LuaGlueClass<_Class> *luaClass, const std::string &name, MethodType &&fn) : glueClass(luaClass), name_(name), fn(std::forward<decltype(fn)>(fn))
35 		{ /*printf("new class %s method %s\n", typeid(_Class).name(), typeid(MethodType).name());*/ }
36 
~LuaGlueMethod()37 		~LuaGlueMethod() {}
38 
name()39 		std::string name() { return name_; }
40 
glue(LuaGlueBase * luaGlue)41 		bool glue(LuaGlueBase *luaGlue)
42 		{
43 			lua_pushlightuserdata(luaGlue->state(), this);
44 			lua_pushcclosure(luaGlue->state(), &lua_call_func, 1);
45 			lua_setfield(luaGlue->state(), -2, name_.c_str());
46 			return true;
47 		}
48 
49 	private:
50 		LuaGlueClass<_Class> *glueClass;
51 		std::string name_;
52 		MethodType fn;
53 		std::tuple<_Args...> args;
54 		static const unsigned int Arg_Count_ = sizeof...(_Args);
55 
56 	public:
invoke(lua_State * state)57 		int invoke(lua_State *state)
58 		{
59 			ReturnType ret;
60 
61 			auto base = GetLuaUdata(state, 1, glueClass->name().c_str());
62 			if(base->isSharedPtr())
63 			{
64 				auto obj = *CastLuaGlueObjectShared(ClassType, base);
65 				ret = applyTuple(glueClass->luaGlue(), state, obj, fn, args);
66 			}
67 			else
68 			{
69 				auto obj = *CastLuaGlueObject(ClassType, base);
70 				ret = applyTuple(glueClass->luaGlue(), state, obj, fn, args);
71 			}
72 
73 			if(Arg_Count_) lua_pop(state, (int)Arg_Count_);
74 
75 			stack<ReturnType>::put(glueClass->luaGlue(), state, ret);
76 			return 1;
77 		}
78 
79 	private:
lua_call_func(lua_State * state)80 		static int lua_call_func(lua_State *state)
81 		{
82 			auto mimp = (LuaGlueMethod<_Ret, _Class, _Args...> *)lua_touserdata(state, lua_upvalueindex(1));
83 			return mimp->invoke(state);
84 		}
85 };
86 
87 template<typename _Class, typename... _Args>
88 class LuaGlueMethod<void, _Class, _Args...> : public LuaGlueMethodBase
89 {
90 	private:
91 		template <typename... T>
92         struct tuple
93         {
94             typedef std::tuple<typename std::remove_const<typename std::remove_reference<T>::type>::type...> type;
95         };
96 
97 	public:
98 		typedef _Class ClassType;
99 		typedef void (_Class::*MethodType)(_Args...);
100 
LuaGlueMethod(LuaGlueClass<_Class> * luaClass,const std::string & name,MethodType && fn)101 		LuaGlueMethod(LuaGlueClass<_Class> *luaClass, const std::string &name, MethodType &&fn) : glueClass(luaClass), name_(name), fn(std::forward<decltype(fn)>(fn))
102 		{ /*printf("new class %s method %s\n", typeid(_Class).name(), typeid(MethodType).name());*/ }
103 
~LuaGlueMethod()104 		~LuaGlueMethod() {}
105 
name()106 		std::string name() { return name_; }
107 
glue(LuaGlueBase * luaGlue)108 		bool glue(LuaGlueBase *luaGlue)
109 		{
110 			lua_pushlightuserdata(luaGlue->state(), this);
111 			lua_pushcclosure(luaGlue->state(), &lua_call_func, 1);
112 			lua_setfield(luaGlue->state(), -2, name_.c_str());
113 			return true;
114 		}
115 
116 	private:
117 		LuaGlueClass<_Class> *glueClass;
118 		std::string name_;
119 		MethodType fn;
120 		std::tuple<_Args...> args;
121 		static const unsigned int Arg_Count_ = sizeof...(_Args);
122 
123 	public:
invoke(lua_State * state)124 		int invoke(lua_State *state)
125 		{
126 			//printf("invokev: %s::%s\n", typeid(*glueClass).name(), name_.c_str());
127 
128 			auto base = GetLuaUdata(state, 1, glueClass->name().c_str());
129 			if(base->isSharedPtr())
130 			{
131 				auto obj = *CastLuaGlueObjectShared(ClassType, base);
132 				applyTuple(glueClass->luaGlue(), state, obj, fn, args);
133 			}
134 			else
135 			{
136 				auto obj = *CastLuaGlueObject(ClassType, base);
137 				applyTuple(glueClass->luaGlue(), state, obj, fn, args);
138 			}
139 
140 			if(Arg_Count_) lua_pop(state, (int)Arg_Count_);
141 			return 0;
142 		}
143 
144 	private:
lua_call_func(lua_State * state)145 		static int lua_call_func(lua_State *state)
146 		{
147 			auto mimp = (LuaGlueMethod<void, _Class, _Args...> *)lua_touserdata(state, lua_upvalueindex(1));
148 			return mimp->invoke(state);
149 		}
150 };
151 
152 template<typename _Ret, typename _Class, typename... _Args>
153 class LuaGlueConstMethod : public LuaGlueMethodBase
154 {
155 	private:
156 		template <typename... T>
157         struct tuple
158         {
159             typedef std::tuple<typename std::remove_const<typename std::remove_reference<T>::type>::type...> type;
160         };
161 
162 	public:
163 		typedef _Class ClassType;
164 		typedef _Ret ReturnType;
165 		typedef _Ret (_Class::*MethodType)( _Args... ) const;
166 
LuaGlueConstMethod(LuaGlueClass<_Class> * luaClass,const std::string & name,MethodType && fn)167 		LuaGlueConstMethod(LuaGlueClass<_Class> *luaClass, const std::string &name, MethodType &&fn) : glueClass(luaClass), name_(name), fn(std::forward<decltype(fn)>(fn))
168 		{ /*printf("new class %s method %s\n", typeid(_Class).name(), typeid(MethodType).name());*/ }
169 
~LuaGlueConstMethod()170 		~LuaGlueConstMethod() {}
171 
name()172 		std::string name() { return name_; }
173 
glue(LuaGlueBase * luaGlue)174 		bool glue(LuaGlueBase *luaGlue)
175 		{
176 			lua_pushlightuserdata(luaGlue->state(), this);
177 			lua_pushcclosure(luaGlue->state(), &lua_call_func, 1);
178 			lua_setfield(luaGlue->state(), -2, name_.c_str());
179 			return true;
180 		}
181 
182 	private:
183 		LuaGlueClass<_Class> *glueClass;
184 		std::string name_;
185 		MethodType fn;
186 		tuple<_Args...> args;
187 		static const unsigned int Arg_Count_ = sizeof...(_Args);
188 
189 	public:
invoke(lua_State * state)190 		int invoke(lua_State *state)
191 		{
192 			//printf("invoker: %s::%s\n", typeid(*glueClass).name(), name_.c_str());
193 
194 			ReturnType ret;
195 			auto base = GetLuaUdata(state, 1, glueClass->name().c_str());
196 			if(base->isSharedPtr())
197 			{
198 				LuaGlueObject<std::shared_ptr<ClassType>> obj = *CastLuaGlueObjectShared(ClassType, base);
199 				ret = applyTuple(glueClass->luaGlue(), state, obj, fn, args);
200 			}
201 			else
202 			{
203 				auto obj = *CastLuaGlueObject(ClassType, base);
204 				ret = applyTuple(glueClass->luaGlue(), state, obj, fn, args);
205 			}
206 
207 			if(Arg_Count_) lua_pop(state, (int)Arg_Count_);
208 
209 			stack<ReturnType>::put(glueClass->luaGlue(), state, ret);
210 			return 1;
211 		}
212 
213 	private:
lua_call_func(lua_State * state)214 		static int lua_call_func(lua_State *state)
215 		{
216 			auto mimp = (LuaGlueConstMethod<_Ret, _Class, _Args...> *)lua_touserdata(state, lua_upvalueindex(1));
217 			return mimp->invoke(state);
218 		}
219 };
220 
221 template<typename _Class, typename... _Args>
222 class LuaGlueConstMethod<void, _Class, _Args...> : public LuaGlueMethodBase
223 {
224 	private:
225 		template <typename... T>
226         struct tuple
227         {
228             typedef std::tuple<typename std::remove_const<typename std::remove_reference<T>::type>::type...> type;
229         };
230 
231 	public:
232 		typedef _Class ClassType;
233 		typedef void (_Class::*MethodType)(_Args...) const;
234 
LuaGlueConstMethod(LuaGlueClass<_Class> * luaClass,const std::string & name,MethodType && fn)235 		LuaGlueConstMethod(LuaGlueClass<_Class> *luaClass, const std::string &name, MethodType &&fn) : glueClass(luaClass), name_(name), fn(std::forward<decltype(fn)>(fn))
236 		{ /*printf("new class %s method %s\n", typeid(_Class).name(), typeid(MethodType).name());*/ }
237 
~LuaGlueConstMethod()238 		~LuaGlueConstMethod() {}
239 
name()240 		std::string name() { return name_; }
241 
glue(LuaGlueBase * luaGlue)242 		bool glue(LuaGlueBase *luaGlue)
243 		{
244 			lua_pushlightuserdata(luaGlue->state(), this);
245 			lua_pushcclosure(luaGlue->state(), &lua_call_func, 1);
246 			lua_setfield(luaGlue->state(), -2, name_.c_str());
247 			return true;
248 		}
249 
250 	private:
251 		LuaGlueClass<_Class> *glueClass;
252 		std::string name_;
253 		MethodType fn;
254 		std::tuple<_Args...> args;
255 		static const unsigned int Arg_Count_ = sizeof...(_Args);
256 
257 	public:
invoke(lua_State * state)258 		int invoke(lua_State *state)
259 		{
260 			//printf("invokev: %s::%s\n", typeid(*glueClass).name(), name_.c_str());
261 
262 			auto base = GetLuaUdata(state, 1, glueClass->name().c_str());
263 			if(base->isSharedPtr())
264 			{
265 				auto obj = *CastLuaGlueObjectShared(ClassType, base);
266 				applyTuple(glueClass->luaGlue(), state, obj, fn, args);
267 			}
268 			else
269 			{
270 				auto obj = *CastLuaGlueObject(ClassType, base);
271 				applyTuple(glueClass->luaGlue(), state, obj, fn, args);
272 			}
273 
274 			if(Arg_Count_) lua_pop(state, (int)Arg_Count_);
275 			return 0;
276 		}
277 
278 	private:
lua_call_func(lua_State * state)279 		static int lua_call_func(lua_State *state)
280 		{
281 			auto mimp = (LuaGlueConstMethod<void, _Class, _Args...> *)lua_touserdata(state, lua_upvalueindex(1));
282 			return mimp->invoke(state);
283 		}
284 };
285 
286 // shared_ptr specializations
287 
288 template<typename _Ret, typename _Class, typename... _Args>
289 class LuaGlueMethod<_Ret, std::shared_ptr<_Class>, _Args...> : public LuaGlueMethodBase
290 {
291 	private:
292 		template <typename... T>
293         struct tuple
294         {
295             typedef std::tuple<typename std::remove_const<typename std::remove_reference<T>::type>::type...> type;
296         };
297 
298 	public:
299 		typedef _Class ClassType;
300 		typedef std::shared_ptr<_Class> SharedType;
301 		typedef _Ret ReturnType;
302 		typedef _Ret (_Class::*MethodType)( _Args... );
303 
LuaGlueMethod(LuaGlueClass<ClassType> * luaClass,const std::string & name,MethodType && fn)304 		LuaGlueMethod(LuaGlueClass<ClassType> *luaClass, const std::string &name, MethodType &&fn) : glueClass(luaClass), name_(name), fn(std::forward<decltype(fn)>(fn))
305 		{}
306 
~LuaGlueMethod()307 		~LuaGlueMethod() {}
308 
name()309 		std::string name() { return name_; }
310 
glue(LuaGlueBase * luaGlue)311 		bool glue(LuaGlueBase *luaGlue)
312 		{
313 			lua_pushlightuserdata(luaGlue->state(), this);
314 			lua_pushcclosure(luaGlue->state(), &lua_call_func, 1);
315 			lua_setfield(luaGlue->state(), -2, name_.c_str());
316 			return true;
317 		}
318 
319 	private:
320 		LuaGlueClass<_Class> *glueClass;
321 		std::string name_;
322 		MethodType fn;
323 		tuple<_Args...> args;
324 		static const unsigned int Arg_Count_ = sizeof...(_Args);
325 
326 	public:
invoke(lua_State * state)327 		int invoke(lua_State *state)
328 		{
329 			//printf("invoker: %s::%s\n", typeid(*glueClass).name(), name_.c_str());
330 
331 			ReturnType ret;
332 			auto base = GetLuaUdata(state, 1, glueClass->name().c_str());
333 			if(base->isSharedPtr())
334 			{
335 				auto obj = *CastLuaGlueObjectShared(ClassType, base);
336 				ret = applyTuple(glueClass->luaGlue(), state, obj, fn, args);
337 			}
338 			else
339 			{
340 				auto obj = *CastLuaGlueObject(ClassType, base);
341 				ret = applyTuple(glueClass->luaGlue(), state, obj, fn, args);
342 			}
343 
344 			if(Arg_Count_) lua_pop(state, (int)Arg_Count_);
345 
346 			stack<ReturnType>::put(glueClass->luaGlue(), state, ret);
347 			return 1;
348 		}
349 
350 	private:
lua_call_func(lua_State * state)351 		static int lua_call_func(lua_State *state)
352 		{
353 			auto mimp = (LuaGlueMethod<_Ret, _Class, _Args...> *)lua_touserdata(state, lua_upvalueindex(1));
354 			return mimp->invoke(state);
355 		}
356 };
357 
358 template<typename _Class, typename... _Args>
359 class LuaGlueMethod<void, std::shared_ptr<_Class>, _Args...> : public LuaGlueMethodBase
360 {
361 	private:
362 		template <typename... T>
363         struct tuple
364         {
365             typedef std::tuple<typename std::remove_const<typename std::remove_reference<T>::type>::type...> type;
366         };
367 
368 	public:
369 		typedef _Class ClassType;
370 		typedef std::shared_ptr<_Class> SharedType;
371 		typedef void (_Class::*MethodType)(_Args...);
372 
LuaGlueMethod(LuaGlueClass<_Class> * luaClass,const std::string & name,MethodType && fn)373 		LuaGlueMethod(LuaGlueClass<_Class> *luaClass, const std::string &name, MethodType &&fn) : glueClass(luaClass), name_(name), fn(std::forward<decltype(fn)>(fn))
374 		{}
375 
~LuaGlueMethod()376 		~LuaGlueMethod() {}
377 
name()378 		std::string name() { return name_; }
379 
glue(LuaGlueBase * luaGlue)380 		bool glue(LuaGlueBase *luaGlue)
381 		{
382 			lua_pushlightuserdata(luaGlue->state(), this);
383 			lua_pushcclosure(luaGlue->state(), &lua_call_func, 1);
384 			lua_setfield(luaGlue->state(), -2, name_.c_str());
385 			return true;
386 		}
387 
388 	private:
389 		LuaGlueClass<_Class> *glueClass;
390 		std::string name_;
391 		MethodType fn;
392 		std::tuple<_Args...> args;
393 		static const unsigned int Arg_Count_ = sizeof...(_Args);
394 
395 	public:
invoke(lua_State * state)396 		int invoke(lua_State *state)
397 		{
398 			//printf("invokev: %s::%s\n", typeid(*glueClass).name(), name_.c_str());
399 
400 			auto base = GetLuaUdata(state, 1, glueClass->name().c_str());
401 			if(base->isSharedPtr())
402 			{
403 				auto obj = *CastLuaGlueObjectShared(ClassType, base);
404 				applyTuple(glueClass->luaGlue(), state, obj, fn, args);
405 			}
406 			else
407 			{
408 				auto obj = *CastLuaGlueObject(ClassType, base);
409 				applyTuple(glueClass->luaGlue(), state, obj, fn, args);
410 			}
411 
412 			if(Arg_Count_) lua_pop(state, (int)Arg_Count_);
413 			return 0;
414 		}
415 
416 	private:
lua_call_func(lua_State * state)417 		static int lua_call_func(lua_State *state)
418 		{
419 			auto mimp = (LuaGlueMethod<void, _Class, _Args...> *)lua_touserdata(state, lua_upvalueindex(1));
420 			return mimp->invoke(state);
421 		}
422 };
423 
424 
425 #endif /* LUAGLUE_METHOD_H_GUARD */
426