LuaWrapper.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*
  2. * LuaWrapper.h, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #pragma once
  11. #include "LuaCallWrapper.h"
  12. /*
  13. * Original code is LunaWrapper by nornagon.
  14. * https://lua-users.org/wiki/LunaWrapper
  15. * Published under the BSD 2-clause license
  16. * https://opensource.org/licenses/BSD-2-Clause
  17. *
  18. */
  19. namespace scripting
  20. {
  21. namespace detail
  22. {
  23. struct CustomRegType
  24. {
  25. const char * name;
  26. lua_CFunction functor;
  27. bool isStatic;
  28. };
  29. template <typename P, typename U>
  30. struct Dispatcher
  31. {
  32. using ProxyType = P;
  33. using UDataType = U;
  34. static void setIndexTable(lua_State * L)
  35. {
  36. lua_pushstring(L, "__index");
  37. lua_newtable(L);
  38. for(auto & reg : ProxyType::REGISTER_CUSTOM)
  39. {
  40. if(!reg.isStatic)
  41. {
  42. lua_pushstring(L, reg.name);
  43. lua_pushcclosure(L, reg.functor, 0);
  44. lua_rawset(L, -3);
  45. }
  46. }
  47. lua_rawset(L, -3);
  48. }
  49. static void pushStaticTable(lua_State * L)
  50. {
  51. lua_newtable(L);
  52. lua_newtable(L);
  53. lua_pushstring(L, "__index");
  54. {
  55. lua_newtable(L);
  56. for(auto & reg : ProxyType::REGISTER_CUSTOM)
  57. {
  58. if(reg.isStatic)
  59. {
  60. lua_pushstring(L, reg.name);
  61. lua_pushcclosure(L, reg.functor, 0);
  62. lua_rawset(L, -3);
  63. }
  64. }
  65. }
  66. lua_rawset(L, -3);
  67. lua_pushstring(L, "__newindex");
  68. lua_pushnil(L);
  69. lua_rawset(L, -3);
  70. lua_setmetatable(L, -2);
  71. }
  72. static int destructor(lua_State * L)
  73. {
  74. static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();
  75. void * objPtr = luaL_checkudata(L, 1, KEY);
  76. if(objPtr)
  77. {
  78. auto obj = static_cast<UDataType *>(objPtr);
  79. obj->reset();
  80. }
  81. lua_settop(L, 0);
  82. return 0;
  83. }
  84. };
  85. }
  86. class RegistarBase : public api::Registar
  87. {
  88. public:
  89. protected:
  90. virtual void adjustMetatable(lua_State * L) const
  91. {
  92. }
  93. virtual void adjustStaticTable(lua_State * L) const
  94. {
  95. }
  96. };
  97. template<class T, class Proxy = T>
  98. class OpaqueWrapper : public RegistarBase
  99. {
  100. public:
  101. using ObjectType = typename std::remove_cv<T>::type;
  102. using UDataType = ObjectType *;
  103. using CUDataType = const ObjectType *;
  104. using CustomRegType = detail::CustomRegType;
  105. void pushMetatable(lua_State * L) const override final
  106. {
  107. static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();
  108. static auto S_KEY = api::TypeRegistry::get()->getKey<CUDataType>();
  109. LuaStack S(L);
  110. if(luaL_newmetatable(L, KEY) != 0)
  111. adjustMetatable(L);
  112. S.balance();
  113. if(luaL_newmetatable(L, S_KEY) != 0)
  114. adjustMetatable(L);
  115. S.balance();
  116. detail::Dispatcher<Proxy, UDataType>::pushStaticTable(L);
  117. adjustStaticTable(L);
  118. }
  119. protected:
  120. void adjustMetatable(lua_State * L) const override
  121. {
  122. detail::Dispatcher<Proxy, UDataType>::setIndexTable(L);
  123. }
  124. };
  125. template<class T, class Proxy = T>
  126. class SharedWrapper : public RegistarBase
  127. {
  128. public:
  129. using ObjectType = typename std::remove_cv<T>::type;
  130. using UDataType = std::shared_ptr<T>;
  131. using CustomRegType = detail::CustomRegType;
  132. static int constructor(lua_State * L)
  133. {
  134. LuaStack S(L);
  135. S.clear();//we do not accept any parameters in constructor
  136. auto obj = std::make_shared<T>();
  137. S.push(obj);
  138. return 1;
  139. }
  140. void pushMetatable(lua_State * L) const override final
  141. {
  142. static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();
  143. LuaStack S(L);
  144. if(luaL_newmetatable(L, KEY) != 0)
  145. {
  146. adjustMetatable(L);
  147. S.push("__gc");
  148. lua_pushcfunction(L, &(detail::Dispatcher<Proxy, UDataType>::destructor));
  149. lua_rawset(L, -3);
  150. }
  151. S.balance();
  152. detail::Dispatcher<Proxy, UDataType>::pushStaticTable(L);
  153. adjustStaticTable(L);
  154. }
  155. protected:
  156. void adjustMetatable(lua_State * L) const override
  157. {
  158. detail::Dispatcher<Proxy, UDataType>::setIndexTable(L);
  159. }
  160. };
  161. template<class T, class Proxy = T>
  162. class UniqueOpaqueWrapper : public api::Registar
  163. {
  164. public:
  165. using ObjectType = typename std::remove_cv<T>::type;
  166. using UDataType = std::unique_ptr<T>;
  167. using CustomRegType = detail::CustomRegType;
  168. void pushMetatable(lua_State * L) const override final
  169. {
  170. static auto KEY = api::TypeRegistry::get()->getKey<UDataType>();
  171. LuaStack S(L);
  172. if(luaL_newmetatable(L, KEY) != 0)
  173. {
  174. // detail::Dispatcher<Proxy, UDataType>::setIndexTable(L);
  175. S.push("__gc");
  176. lua_pushcfunction(L, &(detail::Dispatcher<Proxy, UDataType>::destructor));
  177. lua_rawset(L, -3);
  178. }
  179. S.balance();
  180. detail::Dispatcher<Proxy, UDataType>::pushStaticTable(L);
  181. }
  182. };
  183. }