LuaDataModel.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. /*
  2. * This source file is part of RmlUi, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://github.com/mikke89/RmlUi
  5. *
  6. * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
  7. * Copyright (c) 2019-2023 The RmlUi Team, and contributors
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. */
  28. #include "LuaDataModel.h"
  29. #include <RmlUi/Core/Context.h>
  30. #include <RmlUi/Core/DataModelHandle.h>
  31. #include <RmlUi/Core/DataVariable.h>
  32. #include <RmlUi/Lua/Utilities.h>
  33. #define RMLDATAMODEL "RMLDATAMODEL"
  34. namespace Rml {
  35. namespace Lua {
  36. namespace luabind {
  37. #if LUA_VERSION_NUM < 503
  38. static void lua_reverse(lua_State* L, int a, int b)
  39. {
  40. for (; a < b; ++a, --b)
  41. {
  42. lua_pushvalue(L, a);
  43. lua_pushvalue(L, b);
  44. lua_replace(L, a);
  45. lua_replace(L, b);
  46. }
  47. }
  48. void lua_rotate(lua_State* L, int idx, int n)
  49. {
  50. int n_elems = 0;
  51. idx = lua_absindex(L, idx);
  52. n_elems = lua_gettop(L) - idx + 1;
  53. if (n < 0)
  54. {
  55. n += n_elems;
  56. }
  57. if (n > 0 && n < n_elems)
  58. {
  59. luaL_checkstack(L, 2, "not enough stack slots available");
  60. n = n_elems - n;
  61. lua_reverse(L, idx, idx + n - 1);
  62. lua_reverse(L, idx + n, idx + n_elems - 1);
  63. lua_reverse(L, idx, idx + n_elems - 1);
  64. }
  65. }
  66. #endif
  67. using call_t = Rml::Function<void(void)>;
  68. inline int errhandler(lua_State* L)
  69. {
  70. const char* msg = lua_tostring(L, 1);
  71. if (msg == NULL)
  72. {
  73. if (luaL_callmeta(L, 1, "__tostring") && lua_type(L, -1) == LUA_TSTRING)
  74. return 1;
  75. else
  76. msg = lua_pushfstring(L, "(error object is a %s value)", luaL_typename(L, 1));
  77. }
  78. luaL_traceback(L, L, msg, 1);
  79. return 1;
  80. }
  81. inline void errfunc(const char* msg)
  82. {
  83. Log::Message(Log::LT_WARNING, "%s", msg);
  84. }
  85. inline int function_call(lua_State* L)
  86. {
  87. call_t& f = *(call_t*)lua_touserdata(L, 1);
  88. f();
  89. return 0;
  90. }
  91. inline bool invoke(lua_State* L, call_t f, int argn = 0)
  92. {
  93. if (!lua_checkstack(L, 3))
  94. {
  95. errfunc("stack overflow");
  96. lua_pop(L, argn);
  97. return false;
  98. }
  99. lua_pushcfunction(L, errhandler);
  100. lua_pushcfunction(L, function_call);
  101. lua_pushlightuserdata(L, &f);
  102. lua_rotate(L, -argn - 3, 3);
  103. if (lua_pcall(L, 1 + argn, 0, lua_gettop(L) - argn - 2) != LUA_OK)
  104. {
  105. errfunc(lua_tostring(L, -1));
  106. lua_pop(L, 2);
  107. return false;
  108. }
  109. lua_pop(L, 1);
  110. return true;
  111. }
  112. } // namespace luabind
  113. class LuaScalarDef;
  114. class LuaTableDef;
  115. struct LuaDataModel {
  116. DataModelConstructor constructor;
  117. DataModelHandle handle;
  118. lua_State* dataL;
  119. LuaScalarDef* scalarDef;
  120. LuaTableDef* tableDef;
  121. int top;
  122. };
  123. class LuaTableDef : public VariableDefinition {
  124. public:
  125. LuaTableDef(const struct LuaDataModel* model);
  126. bool Get(void* ptr, Variant& variant) override;
  127. bool Set(void* ptr, const Variant& variant) override;
  128. int Size(void* ptr) override;
  129. DataVariable Child(void* ptr, const DataAddressEntry& address) override;
  130. protected:
  131. const struct LuaDataModel* model;
  132. };
  133. class LuaScalarDef final : public LuaTableDef {
  134. public:
  135. LuaScalarDef(const struct LuaDataModel* model);
  136. DataVariable Child(void* ptr, const DataAddressEntry& address) override;
  137. };
  138. LuaTableDef::LuaTableDef(const struct LuaDataModel* model) : VariableDefinition(DataVariableType::Scalar), model(model) {}
  139. bool LuaTableDef::Get(void* ptr, Variant& variant)
  140. {
  141. lua_State* L = model->dataL;
  142. if (!L)
  143. return false;
  144. int id = (int)(intptr_t)ptr;
  145. GetVariant(L, id, &variant);
  146. return true;
  147. }
  148. bool LuaTableDef::Set(void* ptr, const Variant& variant)
  149. {
  150. int id = (int)(intptr_t)ptr;
  151. lua_State* L = model->dataL;
  152. if (!L)
  153. return false;
  154. PushVariant(L, &variant);
  155. lua_replace(L, id);
  156. return true;
  157. }
  158. static int lLuaTableDefSize(lua_State* L)
  159. {
  160. lua_pushinteger(L, luaL_len(L, 1));
  161. return 1;
  162. }
  163. static int lLuaTableDefChild(lua_State* L)
  164. {
  165. lua_gettable(L, 1);
  166. return 1;
  167. }
  168. int LuaTableDef::Size(void* ptr)
  169. {
  170. lua_State* L = model->dataL;
  171. if (!L)
  172. return 0;
  173. int id = (int)(intptr_t)ptr;
  174. if (lua_type(L, id) != LUA_TTABLE)
  175. {
  176. return 0;
  177. }
  178. if (!lua_checkstack(L, 4))
  179. {
  180. return 0;
  181. }
  182. lua_pushcfunction(L, lLuaTableDefSize);
  183. lua_pushvalue(L, id);
  184. if (LUA_OK != lua_pcall(L, 1, 1, 0))
  185. {
  186. lua_pop(L, 1);
  187. return 0;
  188. }
  189. int size = (int)lua_tointeger(L, -1);
  190. lua_pop(L, 1);
  191. return size;
  192. }
  193. DataVariable LuaTableDef::Child(void* ptr, const DataAddressEntry& address)
  194. {
  195. lua_State* L = model->dataL;
  196. if (!L)
  197. return DataVariable{};
  198. int id = (int)(intptr_t)ptr;
  199. if (lua_type(L, id) != LUA_TTABLE)
  200. {
  201. return DataVariable{};
  202. }
  203. if (!lua_checkstack(L, 4))
  204. {
  205. return DataVariable{};
  206. }
  207. lua_pushcfunction(L, lLuaTableDefChild);
  208. lua_pushvalue(L, id);
  209. if (address.index == -1)
  210. {
  211. lua_pushlstring(L, address.name.data(), address.name.size());
  212. }
  213. else
  214. {
  215. lua_pushinteger(L, (lua_Integer)address.index + 1);
  216. }
  217. if (LUA_OK != lua_pcall(L, 2, 1, 0))
  218. {
  219. lua_pop(L, 1);
  220. return DataVariable{};
  221. }
  222. return DataVariable(model->tableDef, (void*)(intptr_t)lua_gettop(L));
  223. }
  224. LuaScalarDef::LuaScalarDef(const struct LuaDataModel* model) : LuaTableDef(model) {}
  225. DataVariable LuaScalarDef::Child(void* ptr, const DataAddressEntry& address)
  226. {
  227. lua_State* L = model->dataL;
  228. if (!L)
  229. return DataVariable{};
  230. lua_settop(L, model->top);
  231. return LuaTableDef::Child(ptr, address);
  232. }
  233. static void BindVariable(struct LuaDataModel* D, lua_State* L)
  234. {
  235. lua_State* dataL = D->dataL;
  236. if (!lua_checkstack(dataL, 4))
  237. {
  238. luaL_error(L, "Memory Error");
  239. }
  240. int id = lua_gettop(dataL) + 1;
  241. D->top = id;
  242. // L top : key value
  243. lua_xmove(L, dataL, 1); // move value to dataL with index(id)
  244. lua_pushvalue(L, -1); // dup key
  245. lua_xmove(L, dataL, 1);
  246. lua_pushinteger(dataL, id);
  247. lua_rawset(dataL, 1);
  248. const char* key = lua_tostring(L, -1);
  249. if (lua_type(dataL, D->top) == LUA_TFUNCTION)
  250. {
  251. D->constructor.BindEventCallback(key, [=](DataModelHandle, Event& event, const VariantList& varlist) {
  252. lua_pushvalue(dataL, id);
  253. lua_xmove(dataL, L, 1);
  254. luabind::invoke(
  255. L,
  256. [&]() {
  257. LuaType<Event>::push(L, &event, false);
  258. for (auto const& variant : varlist)
  259. {
  260. PushVariant(L, &variant);
  261. }
  262. lua_call(L, (int)varlist.size() + 1, 0);
  263. },
  264. 1);
  265. });
  266. }
  267. else
  268. {
  269. D->constructor.BindCustomDataVariable(key, DataVariable(D->scalarDef, (void*)(intptr_t)id));
  270. }
  271. }
  272. static int getId(lua_State* L, lua_State* dataL)
  273. {
  274. lua_pushvalue(dataL, 1);
  275. lua_xmove(dataL, L, 1);
  276. lua_pushvalue(L, 2);
  277. lua_rawget(L, -2);
  278. if (lua_type(L, -1) != LUA_TNUMBER)
  279. {
  280. luaL_error(L, "DataModel has no key : %s", lua_tostring(L, 2));
  281. }
  282. int id = (int)lua_tointeger(L, -1);
  283. lua_pop(L, 2);
  284. return id;
  285. }
  286. static int lDataModelGet(lua_State* L)
  287. {
  288. struct LuaDataModel* D = (struct LuaDataModel*)lua_touserdata(L, 1);
  289. lua_State* dataL = D->dataL;
  290. if (dataL == nullptr)
  291. luaL_error(L, "DataModel closed");
  292. int id = getId(L, dataL);
  293. lua_pushvalue(dataL, id);
  294. lua_xmove(dataL, L, 1);
  295. return 1;
  296. }
  297. static int lDataModelSet(lua_State* L)
  298. {
  299. struct LuaDataModel* D = (struct LuaDataModel*)lua_touserdata(L, 1);
  300. lua_State* dataL = D->dataL;
  301. if (dataL == NULL)
  302. luaL_error(L, "DataModel released");
  303. lua_settop(dataL, D->top);
  304. lua_pushvalue(L, 2);
  305. lua_xmove(L, dataL, 1);
  306. lua_rawget(dataL, 1);
  307. if (lua_type(dataL, -1) == LUA_TNUMBER)
  308. {
  309. int id = (int)lua_tointeger(dataL, -1);
  310. lua_pop(dataL, 1);
  311. lua_xmove(L, dataL, 1);
  312. lua_replace(dataL, id);
  313. D->handle.DirtyVariable(lua_tostring(L, 2));
  314. return 0;
  315. }
  316. lua_pop(dataL, 1);
  317. BindVariable(D, L);
  318. return 0;
  319. }
  320. bool OpenLuaDataModel(lua_State* L, Context* context, int name_index, int table_index)
  321. {
  322. String name = luaL_checkstring(L, name_index);
  323. luaL_checktype(L, table_index, LUA_TTABLE);
  324. DataModelConstructor constructor = context->CreateDataModel(name);
  325. if (!constructor)
  326. {
  327. constructor = context->GetDataModel(name);
  328. if (!constructor)
  329. {
  330. return false;
  331. }
  332. }
  333. struct LuaDataModel* D = (struct LuaDataModel*)lua_newuserdata(L, sizeof(*D));
  334. D->dataL = nullptr;
  335. D->scalarDef = nullptr;
  336. D->tableDef = nullptr;
  337. D->constructor = constructor;
  338. D->handle = constructor.GetModelHandle();
  339. D->scalarDef = new LuaScalarDef(D);
  340. D->tableDef = new LuaTableDef(D);
  341. D->dataL = lua_newthread(L);
  342. D->top = 1;
  343. lua_newtable(D->dataL);
  344. lua_pushnil(L);
  345. while (lua_next(L, table_index) != 0)
  346. {
  347. BindVariable(D, L);
  348. }
  349. lua_setuservalue(L, -2);
  350. if (luaL_newmetatable(L, RMLDATAMODEL))
  351. {
  352. luaL_Reg l[] = {
  353. {"__index", lDataModelGet},
  354. {"__newindex", lDataModelSet},
  355. {nullptr, nullptr},
  356. };
  357. luaL_setfuncs(L, l, 0);
  358. }
  359. lua_setmetatable(L, -2);
  360. return true;
  361. }
  362. // If you create all the Data Models from lua, you can store these LuaDataModel objects in a table,
  363. // and call CloseLuaDataModel for each after Context released.
  364. // We don't put it in __gc, becuase LuaDataModel can be free before DataModel if you are not careful.
  365. // scalarDef will free by CloseLuaDataModel, but DataModel need it.
  366. void CloseLuaDataModel(lua_State* L)
  367. {
  368. luaL_checkudata(L, -1, RMLDATAMODEL);
  369. struct LuaDataModel* D = (struct LuaDataModel*)lua_touserdata(L, -1);
  370. D->dataL = nullptr;
  371. D->top = 0;
  372. delete D->scalarDef;
  373. D->scalarDef = nullptr;
  374. delete D->tableDef;
  375. D->tableDef = nullptr;
  376. lua_pushnil(L);
  377. lua_setuservalue(L, -2);
  378. }
  379. } // namespace Lua
  380. } // namespace Rml