2 Copyright (c) 2006 Paolo Capriotti <p.capriotti@gmail.com>
3 (c) 2006 Maurizio Monge <maurizio.monge@kdemail.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
11 #ifndef LUAAPI__GENERICWRAPPER_H
12 #define LUAAPI__GENERICWRAPPER_H
24 namespace Loader
{ class Context
; }
28 #define WRAP_0(func, selftype, restype) \
29 static int func(lua_State* l) { \
30 selftype* self = retrieve(l, 1); \
31 CAT0(lua_push, restype)(l, self->func()); \
35 #define PROPERTY_RW(PROP, GET, SET, restype) \
36 static int get_##PROP(lua_State* l) { \
37 lua_push##restype(l, retrieve(l, 1, DontCheck)->GET()); \
41 static int set_##PROP(lua_State* l) { \
42 retrieve(l, 1, DontCheck)->SET( lua_to##restype(l, 2) ); \
46 #define PROPERTY_RO(PROP, GET, restype) \
47 static int get_##PROP(lua_State* l) { \
48 lua_push##restype(l, retrieve(l, 1, DontCheck)->GET()); \
52 #define PROPERTY_RW_TYPE(PROP, GET, SET, restype, TYPE) \
53 static int get_##PROP(lua_State* l) { \
54 lua_push##restype(l, retrieve(l, 1, DontCheck)->GET()); \
58 static int set_##PROP(lua_State* l) { \
59 retrieve(l, 1, DontCheck)->SET( TYPE(lua_to##restype(l, 2)) ); \
63 #define PROPERTY_RO_TYPE(PROP, GET, restype, TYPE) \
64 static int get_##PROP(lua_State* l) { \
65 lua_push##restype(l, retrieve(l, 1, DontCheck)->GET()); \
69 #define PROPERTY_RW_CLASS(PROP, GET, SET, CLASS) \
70 static int get_##PROP(lua_State* l) { \
71 Wrapper<CLASS>::create(l, retrieve(l, 1, DontCheck)->GET()); \
75 static int set_##PROP(lua_State* l) { \
76 retrieve(l, 1, DontCheck)->SET( *Wrapper<CLASS>::retrieve(l, 2, AssertOk) ); \
80 #define PROPERTY_RO_CLASS(PROP, GET, CLASS) \
81 static int get_##PROP(lua_State* l) { \
82 Wrapper<CLASS>::create(l, retrieve(l, 1, DontCheck)->GET()); \
86 #define PROPERTY_RO_QSTRING(PROP, GET) \
87 static int get_##PROP(lua_State* l) { \
88 QString s = retrieve(l, 1, DontCheck)->GET(); \
89 lua_pushstring(l, s.toAscii().constData()); \
93 #define PROPERTY_RW_QSTRING(PROP, GET, SET) \
94 static int get_##PROP(lua_State* l) { \
95 QString s = retrieve(l, 1, DontCheck)->GET(); \
96 lua_pushstring(l, s.toAscii().constData()); \
100 static int set_##PROP(lua_State* l) { \
101 retrieve(l, 1, DontCheck)->SET( QString(lua_tostring(l, 2)) ); \
105 #define SET_PROPERTY_RW(LUA, PROP) \
106 set_property(LUA, #PROP, get_##PROP, set_##PROP);
108 #define SET_PROPERTY_RO(LUA, PROP) \
109 set_property(LUA, #PROP, get_##PROP, NULL);
112 #define LOADING_CONTEXT "tagua_loading_context"
113 #define CURRENT_DIRECTORY "tagua_script_curr_dir"
114 #define API_LOADER "tagua_api_loader"
119 * A simple class that read lua stack level at creation and checks it
120 * when destroyed, printing and error message if different from expected.
126 StackCheck(lua_State
* l
, int expect
= 0) : l(l
) {
127 top
= lua_gettop(l
) + expect
;
131 if (lua_gettop(l
) != top
) {
132 kDebug() << "Wrong lua stack size!\n"
133 " expected = " << top
<< "\n"
134 " actual = " << lua_gettop(l
);
141 * An enumarated value to test how strongly casts will be checked
150 template <typename T
>
154 //BEGIN GenericWrappeBase------------------------------------------------------
156 class GenericWrapperBase
{
158 static QString
file_path(lua_State
* l
, const QString
& f
);
160 static Loader::Context
* retrieve_context(lua_State
* l
);
163 * Add property \a f to the table at @a index.
165 static void set_property(lua_State
* l
, const char* name
, lua_CFunction get
,
166 lua_CFunction set
= NULL
, int index
= -1);
169 * Add method \a f to the table at @a index.
171 static void set_method(lua_State
* l
, lua_CFunction f
, const char* name
, int index
= -1);
174 * Add meta method \a f to the table at @a index.
176 static void set_meta_method(lua_State
* l
, lua_CFunction f
, const char* name
, int index
= -1);
179 * Object index read event
181 static int object_meta_index_event(lua_State
* l
);
184 * Object index write event
186 static int object_meta_newindex_event(lua_State
* l
);
189 //END GenericWrapperBase-------------------------------------------------------
192 //BEGIN GenericWrapprCommon----------------------------------------------------
194 template <typename T
>
195 class GenericWrapperCommon
: public GenericWrapperBase
{
199 * Checks the type, will return true if ok, or false or raise a lua
200 * error if not (in case of Check/AssertOk parameters).
202 static bool check_type(lua_State
* l
, int index
, CheckStrenght check
) {
205 if(check
!= DontCheck
) {
206 if(!lua_getmetatable(l
,index
)) {
207 if(check
== AssertOk
)
208 luaL_error(l
, "Mismatch, got object of unknown type expecting %s",
209 Wrapper
<T
>::class_name());
212 Wrapper
<T
>::push_meta_table(l
);
214 if(!lua_rawequal(l
, -2, -1)) {
215 if(check
== AssertOk
) {
216 if(lua_istable(l
, -2)) {
217 lua_getfield(l
, -2, ".type");
218 if(lua_isstring(l
, -1))
219 luaL_error(l
, "Mismatch, got object of type %s expecting %s",
220 lua_tostring(l
,-1), Wrapper
<T
>::class_name());
223 luaL_error(l
, "Mismatch, got object of unknown type expecting %s",
224 Wrapper
<T
>::class_name());
236 * Create the factory class and static metatable.
238 static void register_class(lua_State
* l
) {
241 lua_newtable(l
); // factory class
243 lua_newtable(l
); // metatable
244 lua_pushcfunction(l
, &Wrapper
<T
>::constructor_wrapper
);
245 lua_setfield(l
, -2, "__call");
246 lua_setmetatable(l
, -2);
248 lua_newtable(l
); // object metatable
251 lua_pushcfunction(l
, &Wrapper
<T
>::deallocate
);
252 lua_setfield(l
, -2, "__gc");
254 // add index metamethod
255 lua_pushcfunction(l
, &Wrapper
<T
>::object_meta_index_event
);
256 lua_setfield(l
, -2, "__index");
258 // add newindex metamethod
259 lua_pushcfunction(l
, &Wrapper
<T
>::object_meta_newindex_event
);
260 lua_setfield(l
, -2, "__newindex");
263 lua_setfield(l
, -2, ".methods");
266 lua_setfield(l
, -2, ".get");
269 lua_setfield(l
, -2, ".set");
271 lua_pushstring(l
, Wrapper
<T
>::class_name() );
272 lua_setfield(l
, -2, ".type");
274 Wrapper
<T
>::create_index_table(l
);
276 lua_setfield(l
, -2, "object_meta_table");
277 lua_setglobal(l
, Wrapper
<T
>::class_name() );
281 * Calls the Wrapper<T> constructor
283 static int constructor_wrapper(lua_State
* l
) {
285 return Wrapper
<T
>::constructor(l
);
289 * Pushes this object's meta table.
291 static void push_meta_table(lua_State
* l
) {
294 lua_getglobal(l
, Wrapper
<T
>::class_name());
295 lua_pushstring(l
, "object_meta_table");
301 //END GenericWrapperCommon-----------------------------------------------------
304 //BEGIN GenericWrapper---------------------------------------------------------
306 template <typename T
>
307 class GenericWrapper
: public GenericWrapperCommon
<T
> {
311 * Retrieve a wrapped object on the stack.
313 static T
* retrieve(lua_State
* l
, int index
= -1, CheckStrenght check
= Check
);
316 * Destroy a wrapped object of type T.
318 static int deallocate(lua_State
* l
);
321 * Wrap an object of type T in a Lua userdatum.
322 * Lua takes ownership of the object, so that it is
323 * automatically disposed by the Lua garbage collector.
325 static void allocate(lua_State
* l
, T
* x
);
329 T
* GenericWrapper
<T
>::retrieve(lua_State
* l
, int index
, CheckStrenght check
) {
330 if(!GenericWrapperCommon
<T
>::check_type(l
, index
, check
))
333 T
** data
= reinterpret_cast<T
**>( lua_touserdata(l
, index
) );
334 return data
? *data
: NULL
;
338 int GenericWrapper
<T
>::deallocate(lua_State
* l
) {
341 T
* data
= retrieve(l
);
348 void GenericWrapper
<T
>::allocate(lua_State
* l
, T
* x
) {
352 T
** data
= reinterpret_cast<T
**>( lua_newuserdata(l
, sizeof(T
*)) );
356 GenericWrapperCommon
<T
>::push_meta_table(l
);
357 lua_setmetatable(l
, -2);
360 //END GenericWrapper-----------------------------------------------------------
362 //BEGIN GenericWrapperByValue---------------------------------------------------------
364 template <typename T
>
365 class GenericWrapperByValue
: public GenericWrapperCommon
<T
> {
369 * Retrieve a wrapped object on the stack.
371 static T
* retrieve(lua_State
* l
, int index
= -1, CheckStrenght check
= Check
);
374 * Destroy a wrapped object of type T.
376 static int deallocate(lua_State
* l
);
379 * Create an object of type T in a Lua userdatum.
380 * Lua takes ownership of the object, so that it is
381 * automatically disposed by the Lua garbage collector.
383 static void create(lua_State
* l
);
384 template<typename A1
>
385 static void create(lua_State
* l
, const A1
&);
386 template<typename A1
, typename A2
>
387 static void create(lua_State
* l
, const A1
&, const A2
&);
388 template<typename A1
, typename A2
, typename A3
>
389 static void create(lua_State
* l
, const A1
&, const A2
&, const A3
&);
390 template<typename A1
, typename A2
, typename A3
, typename A4
>
391 static void create(lua_State
* l
, const A1
&, const A2
&, const A3
&, const A4
&);
392 template<typename A1
, typename A2
, typename A3
, typename A4
, typename A5
>
393 static void create(lua_State
* l
, const A1
&, const A2
&, const A3
&, const A4
&, const A5
&);
397 T
* GenericWrapperByValue
<T
>::retrieve(lua_State
* l
, int index
, CheckStrenght check
) {
398 if(!GenericWrapperCommon
<T
>::check_type(l
, index
, check
))
401 T
* data
= reinterpret_cast<T
*>( lua_touserdata(l
, index
) );
406 int GenericWrapperByValue
<T
>::deallocate(lua_State
* l
) {
409 T
* data
= retrieve(l
);
411 data
->~T(); //placement delete
416 void GenericWrapperByValue
<T
>::create(lua_State
* l
) {
419 T
* data
= reinterpret_cast<T
*>(lua_newuserdata(l
, sizeof(T
)));
420 new(data
) T(); //placement new
421 GenericWrapperCommon
<T
>::push_meta_table(l
);
422 lua_setmetatable(l
, -2);
426 template<typename A1
>
427 void GenericWrapperByValue
<T
>::create(lua_State
* l
, const A1
& a1
) {
430 T
* data
= reinterpret_cast<T
*>(lua_newuserdata(l
, sizeof(T
)));
431 new(data
) T(a1
); //placement new
432 GenericWrapperCommon
<T
>::push_meta_table(l
);
433 lua_setmetatable(l
, -2);
437 template<typename A1
, typename A2
>
438 void GenericWrapperByValue
<T
>::create(lua_State
* l
, const A1
& a1
, const A2
& a2
) {
441 T
* data
= reinterpret_cast<T
*>(lua_newuserdata(l
, sizeof(T
)));
442 new(data
) T(a1
, a2
); //placement new
443 GenericWrapperCommon
<T
>::push_meta_table(l
);
444 lua_setmetatable(l
, -2);
448 template<typename A1
, typename A2
, typename A3
>
449 void GenericWrapperByValue
<T
>::create(lua_State
* l
, const A1
& a1
, const A2
& a2
, const A3
& a3
) {
452 T
* data
= reinterpret_cast<T
*>(lua_newuserdata(l
, sizeof(T
)));
453 new(data
) T(a1
, a2
, a3
); //placement new
454 GenericWrapperCommon
<T
>::push_meta_table(l
);
455 lua_setmetatable(l
, -2);
459 template<typename A1
, typename A2
, typename A3
, typename A4
>
460 void GenericWrapperByValue
<T
>::create(lua_State
* l
, const A1
& a1
, const A2
& a2
,
461 const A3
& a3
, const A4
& a4
) {
464 T
* data
= reinterpret_cast<T
*>(lua_newuserdata(l
, sizeof(T
)));
465 new(data
) T(a1
, a2
, a3
, a4
); //placement new
466 GenericWrapperCommon
<T
>::push_meta_table(l
);
467 lua_setmetatable(l
, -2);
471 template<typename A1
, typename A2
, typename A3
, typename A4
, typename A5
>
472 void GenericWrapperByValue
<T
>::create(lua_State
* l
, const A1
& a1
, const A2
& a2
, const A3
& a3
,
473 const A4
& a4
, const A5
& a5
) {
476 T
* data
= reinterpret_cast<T
*>(lua_newuserdata(l
, sizeof(T
)));
477 new(data
) T(a1
, a2
, a3
, a4
, a5
); //placement new
478 GenericWrapperCommon
<T
>::push_meta_table(l
);
479 lua_setmetatable(l
, -2);
482 //END GenericWrapperByValue-----------------------------------------------------------
488 static void register_in_index_table(lua_State
* l
);
489 static int eq_event(lua_State
* l
);
493 void Comparable
<T
>::register_in_index_table(lua_State
* l
) {
494 Wrapper
<T
>::set_meta_method(l
, &eq_event
, "__eq");
498 int Comparable
<T
>::eq_event(lua_State
* l
) {
499 int n
= lua_gettop(l
);
501 luaL_error(l
, "Wrong argument count %d for __eq", n
);
502 T
*p1
= Wrapper
<T
>::retrieve(l
, 1, AssertOk
);
503 T
*p2
= Wrapper
<T
>::retrieve(l
, 2, AssertOk
);
505 lua_pushboolean(l
, *p1
== *p2
);
512 static void register_in_index_table(lua_State
* l
);
513 static int add_event(lua_State
* l
);
514 static int sub_event(lua_State
* l
);
515 static int unm_event(lua_State
* l
);
519 void Summable
<T
>::register_in_index_table(lua_State
* l
) {
520 Wrapper
<T
>::set_meta_method(l
, &add_event
, "__add");
521 Wrapper
<T
>::set_meta_method(l
, &sub_event
, "__sub");
522 Wrapper
<T
>::set_meta_method(l
, &unm_event
, "__unm");
526 int Summable
<T
>::add_event(lua_State
* l
) {
527 int n
= lua_gettop(l
);
529 luaL_error(l
, "Wrong argument count %d for __add", n
);
530 T
*p1
= Wrapper
<T
>::retrieve(l
, 1, AssertOk
);
531 T
*p2
= Wrapper
<T
>::retrieve(l
, 2, AssertOk
);
534 Wrapper
<T
>::create(l
, *p1
+ *p2
);
540 int Summable
<T
>::sub_event(lua_State
* l
) {
541 int n
= lua_gettop(l
);
543 luaL_error(l
, "Wrong argument count %d for __sub", n
);
544 T
*p1
= Wrapper
<T
>::retrieve(l
, 1, AssertOk
);
545 T
*p2
= Wrapper
<T
>::retrieve(l
, 2, AssertOk
);
548 Wrapper
<T
>::create(l
, *p1
- *p2
);
554 int Summable
<T
>::unm_event(lua_State
* l
) {
555 int n
= lua_gettop(l
);
557 /* for some strange reason unm gets 2 copies of the same argument */
559 luaL_error(l
, "Wrong argument count %d for __unm", n
);
560 T
*p1
= Wrapper
<T
>::retrieve(l
, 1, AssertOk
);
563 Wrapper
<T
>::create(l
, -*p1
);
568 } //end namespace LuaApi
571 #endif //LUAAPI__GENERICWRAPPER_H