Tentative Randomless-Entropy variant.
[tagua/yd.git] / src / luaapi / genericwrapper.h
blob5763b8bb87dc7a80e358a93276f4dd812d4e0993
1 /*
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.
9 */
11 #ifndef LUAAPI__GENERICWRAPPER_H
12 #define LUAAPI__GENERICWRAPPER_H
14 extern "C" {
15 #include <lua.h>
16 #include <lualib.h>
17 #include <lauxlib.h>
18 #include "lfunclib.h"
20 #include <QString>
21 #include <KDebug>
22 #include "common.h"
24 namespace Loader { class Context; }
26 namespace LuaApi {
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()); \
32 return 1; \
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()); \
38 return 1; \
39 } \
41 static int set_##PROP(lua_State* l) { \
42 retrieve(l, 1, DontCheck)->SET( lua_to##restype(l, 2) ); \
43 return 0; \
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()); \
49 return 1; \
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()); \
55 return 1; \
56 } \
58 static int set_##PROP(lua_State* l) { \
59 retrieve(l, 1, DontCheck)->SET( TYPE(lua_to##restype(l, 2)) ); \
60 return 0; \
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()); \
66 return 1; \
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()); \
72 return 1; \
73 } \
75 static int set_##PROP(lua_State* l) { \
76 retrieve(l, 1, DontCheck)->SET( *Wrapper<CLASS>::retrieve(l, 2, AssertOk) ); \
77 return 0; \
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()); \
83 return 1; \
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()); \
90 return 1; \
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()); \
97 return 1; \
98 } \
100 static int set_##PROP(lua_State* l) { \
101 retrieve(l, 1, DontCheck)->SET( QString(lua_tostring(l, 2)) ); \
102 return 0; \
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.
122 class StackCheck {
123 lua_State* l;
124 int top;
125 public:
126 StackCheck(lua_State* l, int expect = 0) : l(l) {
127 top = lua_gettop(l) + expect;
130 ~StackCheck() {
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
143 enum CheckStrenght {
144 DontCheck,
145 Check,
146 AssertOk
150 template <typename T>
151 class Wrapper;
154 //BEGIN GenericWrappeBase------------------------------------------------------
156 class GenericWrapperBase {
157 public:
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 {
196 public:
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) {
203 StackCheck s(l);
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());
210 return false;
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());
222 lua_pop(l,2);
223 luaL_error(l, "Mismatch, got object of unknown type expecting %s",
224 Wrapper<T>::class_name());
226 lua_pop(l,2);
227 return false;
229 lua_pop(l,2);
232 return true;
236 * Create the factory class and static metatable.
238 static void register_class(lua_State* l) {
239 StackCheck s(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
250 // add gc metamethod
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");
262 lua_newtable(l);
263 lua_setfield(l, -2, ".methods");
265 lua_newtable(l);
266 lua_setfield(l, -2, ".get");
268 lua_newtable(l);
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&lt;T&gt; constructor
283 static int constructor_wrapper(lua_State* l) {
284 lua_remove(l, 1);
285 return Wrapper<T>::constructor(l);
289 * Pushes this object's meta table.
291 static void push_meta_table(lua_State* l) {
292 StackCheck s(l, 1);
294 lua_getglobal(l, Wrapper<T>::class_name());
295 lua_pushstring(l, "object_meta_table");
296 lua_rawget(l,-2);
297 lua_remove(l,-2);
301 //END GenericWrapperCommon-----------------------------------------------------
304 //BEGIN GenericWrapper---------------------------------------------------------
306 template <typename T>
307 class GenericWrapper : public GenericWrapperCommon<T> {
308 public:
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);
328 template<typename T>
329 T* GenericWrapper<T>::retrieve(lua_State* l, int index, CheckStrenght check) {
330 if(!GenericWrapperCommon<T>::check_type(l, index, check))
331 return NULL;
333 T** data = reinterpret_cast<T**>( lua_touserdata(l, index) );
334 return data ? *data : NULL;
337 template<typename T>
338 int GenericWrapper<T>::deallocate(lua_State* l) {
339 StackCheck s(l, -1);
341 T* data = retrieve(l);
342 lua_pop(l, 1);
343 delete data;
344 return 0;
347 template<typename T>
348 void GenericWrapper<T>::allocate(lua_State* l, T* x) {
349 StackCheck s(l, 1);
351 // create userdata
352 T** data = reinterpret_cast<T**>( lua_newuserdata(l, sizeof(T*)) );
353 *data = x;
355 // set metatable
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> {
366 public:
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&);
396 template<typename T>
397 T* GenericWrapperByValue<T>::retrieve(lua_State* l, int index, CheckStrenght check) {
398 if(!GenericWrapperCommon<T>::check_type(l, index, check))
399 return NULL;
401 T* data = reinterpret_cast<T*>( lua_touserdata(l, index) );
402 return data;
405 template<typename T>
406 int GenericWrapperByValue<T>::deallocate(lua_State* l) {
407 StackCheck s(l, -1);
409 T* data = retrieve(l);
410 lua_pop(l, 1);
411 data->~T(); //placement delete
412 return 0;
415 template<typename T>
416 void GenericWrapperByValue<T>::create(lua_State* l) {
417 StackCheck s(l, 1);
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);
425 template<typename T>
426 template<typename A1>
427 void GenericWrapperByValue<T>::create(lua_State* l, const A1& a1) {
428 StackCheck s(l, 1);
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);
436 template<typename T>
437 template<typename A1, typename A2>
438 void GenericWrapperByValue<T>::create(lua_State* l, const A1& a1, const A2& a2) {
439 StackCheck s(l, 1);
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);
447 template<typename T>
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) {
450 StackCheck s(l, 1);
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);
458 template<typename T>
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) {
462 StackCheck s(l, 1);
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);
470 template<typename T>
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) {
474 StackCheck s(l, 1);
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-----------------------------------------------------------
485 template<typename T>
486 class Comparable {
487 public:
488 static void register_in_index_table(lua_State* l);
489 static int eq_event(lua_State* l);
492 template<typename T>
493 void Comparable<T>::register_in_index_table(lua_State* l) {
494 Wrapper<T>::set_meta_method(l, &eq_event, "__eq");
497 template<typename T>
498 int Comparable<T>::eq_event(lua_State* l) {
499 int n = lua_gettop(l);
500 if(n != 2)
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);
504 lua_pop(l, n);
505 lua_pushboolean(l, *p1 == *p2);
506 return 1;
509 template<typename T>
510 class Summable {
511 public:
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);
518 template<typename T>
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");
525 template<typename T>
526 int Summable<T>::add_event(lua_State* l) {
527 int n = lua_gettop(l);
528 if(n != 2)
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);
532 lua_pop(l, n);
534 Wrapper<T>::create(l, *p1 + *p2);
536 return 1;
539 template<typename T>
540 int Summable<T>::sub_event(lua_State* l) {
541 int n = lua_gettop(l);
542 if(n != 2)
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);
546 lua_pop(l, n);
548 Wrapper<T>::create(l, *p1 - *p2);
550 return 1;
553 template<typename T>
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 */
558 if(n != 2)
559 luaL_error(l, "Wrong argument count %d for __unm", n);
560 T *p1 = Wrapper<T>::retrieve(l, 1, AssertOk);
561 lua_pop(l, n);
563 Wrapper<T>::create(l, -*p1);
565 return 1;
568 } //end namespace LuaApi
571 #endif //LUAAPI__GENERICWRAPPER_H