wrapper.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. #pragma once
  2. #include <library/cpp/string_utils/ztstrbuf/ztstrbuf.h>
  3. #include <util/memory/alloc.h>
  4. #include <util/generic/ptr.h>
  5. #include <util/generic/string.h>
  6. #include <util/generic/yexception.h>
  7. #include <util/generic/buffer.h>
  8. #include <util/datetime/base.h>
  9. #include <functional>
  10. #include <contrib/libs/lua/lua.h>
  11. class IInputStream;
  12. class IOutputStream;
  13. class TLuaStateHolder {
  14. struct TDeleteState {
  15. static inline void Destroy(lua_State* state) {
  16. lua_close(state);
  17. }
  18. };
  19. public:
  20. class TError: public yexception {
  21. };
  22. inline TLuaStateHolder(size_t memory_limit = 0)
  23. : AllocFree(memory_limit)
  24. , MyState_(lua_newstate(memory_limit ? AllocLimit : Alloc, (void*)this))
  25. , State_(MyState_.Get())
  26. {
  27. if (!State_) {
  28. ythrow TError() << "can not construct lua state: not enough memory";
  29. }
  30. }
  31. inline TLuaStateHolder(lua_State* state) noexcept
  32. : State_(state)
  33. {
  34. }
  35. inline operator lua_State*() noexcept {
  36. return State_;
  37. }
  38. inline void BootStrap() {
  39. luaL_openlibs(State_);
  40. }
  41. inline void error() {
  42. ythrow TError() << "lua error: " << pop_string();
  43. }
  44. inline bool is_string(int index) {
  45. return lua_isstring(State_, index);
  46. }
  47. inline void is_string_strict(int index) {
  48. if (!is_string(index)) {
  49. ythrow TError() << "internal lua error (not a string)";
  50. }
  51. }
  52. inline TStringBuf to_string(int index) {
  53. size_t len = 0;
  54. const char* data = lua_tolstring(State_, index, &len);
  55. return TStringBuf(data, len);
  56. }
  57. inline TStringBuf to_string(int index, TStringBuf defaultValue) {
  58. return is_string(index) ? to_string(index) : defaultValue;
  59. }
  60. inline TStringBuf to_string_strict(int index) {
  61. is_string_strict(index);
  62. return to_string(index);
  63. }
  64. inline TString pop_string() {
  65. TString ret(to_string(-1));
  66. pop();
  67. return ret;
  68. }
  69. inline TString pop_string(TStringBuf defaultValue) {
  70. TString ret(to_string(-1, defaultValue));
  71. pop();
  72. return ret;
  73. }
  74. inline TString pop_string_strict() {
  75. require(1);
  76. TString ret(to_string_strict(-1));
  77. pop();
  78. return ret;
  79. }
  80. inline TString pop_value() {
  81. require(1);
  82. if (is_bool(-1)) {
  83. return pop_bool() ? "true" : "false";
  84. }
  85. return pop_string_strict();
  86. }
  87. inline void push_string(const char* st) {
  88. lua_pushstring(State_, st ? st : "");
  89. }
  90. inline void push_string(TStringBuf st) {
  91. lua_pushlstring(State_, st.data(), st.size());
  92. }
  93. inline bool is_number(int index) {
  94. return lua_isnumber(State_, index);
  95. }
  96. inline void is_number_strict(int index) {
  97. if (!is_number(index)) {
  98. ythrow TError() << "internal lua error (not a number)";
  99. }
  100. }
  101. template <typename T>
  102. inline T to_number(int index) {
  103. return static_cast<T>(lua_tonumber(State_, index));
  104. }
  105. template <typename T>
  106. inline T to_number(int index, T defaultValue) {
  107. return is_number(index) ? to_number<T>(index) : defaultValue;
  108. }
  109. template <typename T>
  110. inline T to_number_strict(int index) {
  111. is_number_strict(index);
  112. return to_number<T>(index);
  113. }
  114. template <typename T>
  115. inline T pop_number() {
  116. const T ret = to_number<T>(-1);
  117. pop();
  118. return ret;
  119. }
  120. template <typename T>
  121. inline T pop_number(T defaultValue) {
  122. const T ret = to_number<T>(-1, defaultValue);
  123. pop();
  124. return ret;
  125. }
  126. template <typename T>
  127. inline T pop_number_strict() {
  128. require(1);
  129. const T ret = to_number_strict<T>(-1);
  130. pop();
  131. return ret;
  132. }
  133. template <typename T>
  134. inline void push_number(T val) {
  135. lua_pushnumber(State_, static_cast<lua_Number>(val));
  136. }
  137. inline bool is_bool(int index) {
  138. return lua_isboolean(State_, index);
  139. }
  140. inline void is_bool_strict(int index) {
  141. if (!is_bool(index)) {
  142. ythrow TError() << "internal lua error (not a boolean)";
  143. }
  144. }
  145. inline bool to_bool(int index) {
  146. return lua_toboolean(State_, index);
  147. }
  148. inline bool to_bool(int index, bool defaultValue) {
  149. return is_bool(index) ? to_bool(index) : defaultValue;
  150. }
  151. inline bool to_bool_strict(int index) {
  152. is_bool_strict(index);
  153. return to_bool(index);
  154. }
  155. inline bool pop_bool() {
  156. const bool ret = to_bool(-1);
  157. pop();
  158. return ret;
  159. }
  160. inline bool pop_bool(bool defaultValue) {
  161. const bool ret = to_bool(-1, defaultValue);
  162. pop();
  163. return ret;
  164. }
  165. inline bool pop_bool_strict() {
  166. require(1);
  167. const bool ret = to_bool_strict(-1);
  168. pop();
  169. return ret;
  170. }
  171. inline void push_bool(bool val) {
  172. lua_pushboolean(State_, val);
  173. }
  174. inline bool is_nil(int index) {
  175. return lua_isnil(State_, index);
  176. }
  177. inline void is_nil_strict(int index) {
  178. if (!is_nil(index)) {
  179. ythrow TError() << "internal lua error (not a nil)";
  180. }
  181. }
  182. inline bool pop_nil() {
  183. const bool ret = is_nil(-1);
  184. pop();
  185. return ret;
  186. }
  187. inline void pop_nil_strict() {
  188. require(1);
  189. is_nil_strict(-1);
  190. pop();
  191. }
  192. inline void push_nil() {
  193. lua_pushnil(State_);
  194. }
  195. inline bool is_void(int index) {
  196. return lua_islightuserdata(State_, index);
  197. }
  198. inline void is_void_strict(int index) {
  199. if (!is_void(index)) {
  200. ythrow TError() << "internal lua error (not a void*)";
  201. }
  202. }
  203. inline void* to_void(int index) {
  204. return lua_touserdata(State_, index);
  205. }
  206. inline void* to_void(int index, void* defaultValue) {
  207. return is_void(index) ? to_void(index) : defaultValue;
  208. }
  209. inline void* to_void_strict(int index) {
  210. is_void_strict(index);
  211. return to_void(index);
  212. }
  213. inline void* pop_void() {
  214. void* ret = to_void(-1);
  215. pop();
  216. return ret;
  217. }
  218. inline void* pop_void(void* defaultValue) {
  219. void* ret = to_void(-1, defaultValue);
  220. pop();
  221. return ret;
  222. }
  223. inline void* pop_void_strict() {
  224. require(1);
  225. void* ret = to_void_strict(-1);
  226. pop();
  227. return ret;
  228. }
  229. inline void push_void(void* ptr) {
  230. lua_pushlightuserdata(State_, ptr);
  231. }
  232. template <typename T>
  233. inline bool is_userdata(int index) {
  234. return to_userdata<T>(index) != NULL;
  235. }
  236. template <typename T>
  237. inline void is_userdata_strict(int index) {
  238. to_userdata_strict<T>(index);
  239. }
  240. template <typename T>
  241. inline T* to_userdata(int index) {
  242. return static_cast<T*>(luaL_testudata(State_, index, T::LUA_METATABLE_NAME));
  243. }
  244. template <typename T>
  245. inline T* to_userdata_strict(int index) {
  246. T* ret = to_userdata<T>(index);
  247. if (ret == nullptr) {
  248. ythrow TError() << "internal error (not a userdata '" << T::LUA_METATABLE_NAME << "')";
  249. }
  250. return ret;
  251. }
  252. template <typename T>
  253. inline T pop_userdata_strict() {
  254. require(1);
  255. const T ret(*to_userdata_strict<T>(-1));
  256. pop();
  257. return ret;
  258. }
  259. template <typename T>
  260. inline T* push_userdata(const T& x) {
  261. // copy constructor
  262. return new (new_userdata<T>()) T(x);
  263. }
  264. template <typename T, typename... R>
  265. inline T* push_userdata(const R&... r) {
  266. return new (new_userdata<T>()) T(r...);
  267. }
  268. inline void push_global(const char* name) {
  269. lua_getglobal(State_, name);
  270. }
  271. inline void set_global(const char* name, const char* value) {
  272. lua_pushstring(State_, value);
  273. set_global(name);
  274. }
  275. inline void set_global(const char* name, const double value) {
  276. lua_pushnumber(State_, value);
  277. set_global(name);
  278. }
  279. inline void set_global(const char* name) {
  280. lua_setglobal(State_, name);
  281. }
  282. inline void register_function(const char* name, lua_CFunction func) {
  283. lua_register(State_, name, func);
  284. }
  285. inline bool is_table(int index) {
  286. return lua_istable(State_, index);
  287. }
  288. inline void is_table_strict(int index) {
  289. if (!is_table(index)) {
  290. ythrow TError() << "internal lua error (not a table)";
  291. }
  292. }
  293. inline void create_table(int narr = 0, int nrec = 0) {
  294. lua_createtable(State_, narr, nrec);
  295. }
  296. inline void set_table(int index) {
  297. lua_settable(State_, index);
  298. }
  299. inline void get_field(int index, const char* key) {
  300. lua_getfield(State_, index, key);
  301. }
  302. inline void set_field(int index, const char* key) {
  303. lua_setfield(State_, index, key);
  304. }
  305. inline void rawseti(int index, int arr_index) {
  306. lua_rawseti(State_, index, arr_index);
  307. }
  308. inline int check_stack(int extra) {
  309. return lua_checkstack(State_, extra);
  310. }
  311. inline void ensure_stack(int extra) {
  312. if (!check_stack(extra)) {
  313. ythrow TError() << "cannot allocate more lua stack space";
  314. };
  315. }
  316. inline void require(int n) {
  317. if (on_stack() < n) {
  318. ythrow TError() << "lua requirement failed";
  319. }
  320. }
  321. inline void call(int args, int rets) {
  322. if (lua_pcall(State_, args, rets, 0)) {
  323. error();
  324. }
  325. }
  326. void call(int args, int rets, TDuration time_limit, int count = 1000);
  327. void call(int args, int rets, int limit);
  328. inline void remove(int index) {
  329. lua_remove(State_, index);
  330. }
  331. inline int next(int index) {
  332. return lua_next(State_, index);
  333. }
  334. inline void pop(int n = 1) {
  335. lua_pop(State_, Min(n, on_stack()));
  336. }
  337. inline void push_value(int index) {
  338. lua_pushvalue(State_, index);
  339. }
  340. inline int on_stack() {
  341. return lua_gettop(State_);
  342. }
  343. inline void gc() {
  344. lua_gc(State_, LUA_GCCOLLECT, 0);
  345. }
  346. inline TLuaStateHolder new_thread() {
  347. return lua_newthread(State_);
  348. }
  349. inline bool is_thread(int index) {
  350. return lua_isthread(State_, index);
  351. }
  352. inline void is_thread_strict(int index) {
  353. if (!is_thread(index)) {
  354. ythrow TError() << "internal lua error (not a thread)";
  355. }
  356. }
  357. inline TLuaStateHolder to_thread(int index) {
  358. return lua_tothread(State_, index);
  359. }
  360. inline TLuaStateHolder to_thread_strict(int index) {
  361. is_thread_strict(index);
  362. return to_thread(index);
  363. }
  364. void Load(IInputStream* in, TZtStringBuf name);
  365. void Dump(IOutputStream* out);
  366. void DumpStack(IOutputStream* out);
  367. private:
  368. template <typename T>
  369. inline void set_metatable() {
  370. if (luaL_newmetatable(State_, T::LUA_METATABLE_NAME)) {
  371. // metatable isn't registered yet
  372. push_string("__index");
  373. push_value(-2); // pushes the metatable
  374. set_table(-3); // metatable.__index = metatable
  375. luaL_setfuncs(State_, T::LUA_FUNCTIONS, 0);
  376. }
  377. lua_setmetatable(State_, -2);
  378. }
  379. template <typename T>
  380. inline void* new_userdata() {
  381. void* p = lua_newuserdata(State_, sizeof(T));
  382. set_metatable<T>();
  383. return p;
  384. }
  385. private:
  386. static void* Alloc(void* ud, void* ptr, size_t osize, size_t nsize);
  387. static void* AllocLimit(void* ud, void* ptr, size_t osize, size_t nsize);
  388. private:
  389. size_t AllocFree = 0;
  390. THolder<lua_State, TDeleteState> MyState_;
  391. lua_State* State_ = nullptr;
  392. };
  393. namespace NLua {
  394. template <int func(TLuaStateHolder&)>
  395. int FunctionHandler(lua_State* L) {
  396. try {
  397. TLuaStateHolder state(L);
  398. return func(state);
  399. } catch (const yexception& e) {
  400. lua_pushstring(L, e.what());
  401. }
  402. return lua_error(L);
  403. }
  404. template <class T, int (T::*Method)(TLuaStateHolder&)>
  405. int MethodHandler(lua_State* L) {
  406. T* x = static_cast<T*>(luaL_checkudata(L, 1, T::LUA_METATABLE_NAME));
  407. try {
  408. TLuaStateHolder state(L);
  409. return (x->*Method)(state);
  410. } catch (const yexception& e) {
  411. lua_pushstring(L, e.what());
  412. }
  413. return lua_error(L);
  414. }
  415. template <class T, int (T::*Method)(TLuaStateHolder&) const>
  416. int MethodConstHandler(lua_State* L) {
  417. const T* x = static_cast<const T*>(luaL_checkudata(L, 1, T::LUA_METATABLE_NAME));
  418. try {
  419. TLuaStateHolder state(L);
  420. return (x->*Method)(state);
  421. } catch (const yexception& e) {
  422. lua_pushstring(L, e.what());
  423. }
  424. return lua_error(L);
  425. }
  426. template <class T>
  427. int Destructor(lua_State* L) {
  428. T* x = static_cast<T*>(luaL_checkudata(L, 1, T::LUA_METATABLE_NAME));
  429. try {
  430. x->~T();
  431. return 0;
  432. } catch (const yexception& e) {
  433. lua_pushstring(L, e.what());
  434. }
  435. return lua_error(L);
  436. }
  437. TBuffer& Compile(TStringBuf script, TBuffer& buffer);
  438. struct TStackDumper {
  439. TStackDumper(TLuaStateHolder& state)
  440. : State(state)
  441. {
  442. }
  443. TLuaStateHolder& State;
  444. };
  445. struct TMarkedStackDumper: public TStackDumper {
  446. TMarkedStackDumper(TLuaStateHolder& state, TStringBuf mark)
  447. : TStackDumper(state)
  448. , Mark(mark)
  449. {
  450. }
  451. TStringBuf Mark;
  452. };
  453. inline TMarkedStackDumper DumpStack(TLuaStateHolder& state, TStringBuf mark) {
  454. return TMarkedStackDumper(state, mark);
  455. }
  456. inline TStackDumper DumpStack(TLuaStateHolder& state) {
  457. return TStackDumper(state);
  458. }
  459. }