LuaBinder.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <anki/util/Assert.h>
  7. #include <anki/util/StdTypes.h>
  8. #include <anki/util/Allocator.h>
  9. #include <anki/util/String.h>
  10. #include <anki/util/Functions.h>
  11. #include <lua.hpp>
  12. #ifndef ANKI_LUA_HPP
  13. #error "Wrong LUA header included"
  14. #endif
  15. namespace anki
  16. {
  17. /// LUA userdata.
  18. class UserData
  19. {
  20. public:
  21. /// @note NEVER ADD A DESTRUCTOR. LUA cannot call that.
  22. ~UserData() = delete;
  23. I64 getSig() const
  24. {
  25. return m_sig;
  26. }
  27. void initGarbageCollected(I64 sig)
  28. {
  29. m_sig = sig;
  30. m_addressAndGarbageCollect = GC_MASK;
  31. }
  32. void initPointed(I64 sig, void* ptrToObject)
  33. {
  34. m_sig = sig;
  35. U64 addr = ptrToNumber(ptrToObject);
  36. ANKI_ASSERT(
  37. (addr & GC_MASK) == 0 && "Address too high, cannot encode a flag");
  38. m_addressAndGarbageCollect = addr;
  39. }
  40. Bool isGarbageCollected() const
  41. {
  42. return m_addressAndGarbageCollect == GC_MASK;
  43. }
  44. template<typename T>
  45. T* getData()
  46. {
  47. T* out = nullptr;
  48. if(isGarbageCollected())
  49. {
  50. // Garbage collected
  51. PtrSize mem = ptrToNumber(this);
  52. mem += getAlignedRoundUp(alignof(T), sizeof(UserData));
  53. out = numberToPtr<T*>(mem);
  54. }
  55. else
  56. {
  57. // Pointed
  58. PtrSize mem = static_cast<PtrSize>(m_addressAndGarbageCollect);
  59. out = numberToPtr<T*>(mem);
  60. }
  61. ANKI_ASSERT(out);
  62. ANKI_ASSERT(isAligned(alignof(T), out));
  63. return out;
  64. }
  65. template<typename T>
  66. static PtrSize computeSizeForGarbageCollected()
  67. {
  68. return getAlignedRoundUp(alignof(T), sizeof(UserData)) + sizeof(T);
  69. }
  70. private:
  71. static constexpr U64 GC_MASK = 1ul << 63ul;
  72. I64 m_sig = 0; ///< Signature to identify the user data.
  73. /// Encodes an address and a flag for garbage collection.
  74. /// High bit is the GC flag and the rest are an address.
  75. U64 m_addressAndGarbageCollect = 0;
  76. };
  77. /// Lua binder class. A wrapper on top of LUA
  78. class LuaBinder
  79. {
  80. public:
  81. template<typename T>
  82. using Allocator = ChainAllocator<T>;
  83. LuaBinder();
  84. ~LuaBinder();
  85. ANKI_USE_RESULT Error create(Allocator<U8>& alloc, void* parent);
  86. lua_State* getLuaState()
  87. {
  88. return m_l;
  89. }
  90. Allocator<U8> getAllocator() const
  91. {
  92. return m_alloc;
  93. }
  94. void* getParent() const
  95. {
  96. return m_parent;
  97. }
  98. /// Expose a variable to the lua state
  99. template<typename T>
  100. void exposeVariable(const char* name, T* y);
  101. /// Evaluate a string
  102. ANKI_USE_RESULT Error evalString(const CString& str);
  103. /// For debugging purposes
  104. static void stackDump(lua_State* l);
  105. /// Make sure that the arguments match the argsCount number
  106. static void checkArgsCount(lua_State* l, I argsCount);
  107. /// Create a new LUA class
  108. static void createClass(lua_State* l, const char* className);
  109. /// Add new function in a class that it's already in the stack
  110. static void pushLuaCFuncMethod(
  111. lua_State* l, const char* name, lua_CFunction luafunc);
  112. /// Add a new static function in the class.
  113. static void pushLuaCFuncStaticMethod(lua_State* l,
  114. const char* className,
  115. const char* name,
  116. lua_CFunction luafunc);
  117. /// Add a new function.
  118. static void pushLuaCFunc(
  119. lua_State* l, const char* name, lua_CFunction luafunc);
  120. /// Get a number from the stack.
  121. template<typename TNumber>
  122. static ANKI_USE_RESULT Error checkNumber(
  123. lua_State* l, I stackIdx, TNumber& number);
  124. /// Get a string from the stack.
  125. static ANKI_USE_RESULT Error checkString(
  126. lua_State* l, I32 stackIdx, const char*& out);
  127. /// Get some user data from the stack.
  128. /// The function uses the type signature to validate the type and not the
  129. /// typeName. That is supposed to be faster.
  130. static ANKI_USE_RESULT Error checkUserData(lua_State* l,
  131. I32 stackIdx,
  132. const char* typeName,
  133. I64 typeSignature,
  134. UserData*& out);
  135. /// Allocate memory.
  136. static void* luaAlloc(lua_State* l, size_t size, U32 alignment);
  137. /// Free memory.
  138. static void luaFree(lua_State* l, void* ptr);
  139. template<typename TWrapedType>
  140. static I64 getWrappedTypeSignature();
  141. template<typename TWrapedType>
  142. static const char* getWrappedTypeName();
  143. private:
  144. Allocator<U8> m_alloc;
  145. lua_State* m_l = nullptr;
  146. void* m_parent = nullptr; ///< Point to the ScriptManager
  147. static void* luaAllocCallback(
  148. void* userData, void* ptr, PtrSize osize, PtrSize nsize);
  149. static ANKI_USE_RESULT Error checkNumberInternal(
  150. lua_State* l, I32 stackIdx, lua_Number& number);
  151. };
  152. //==============================================================================
  153. template<typename TNumber>
  154. inline Error LuaBinder::checkNumber(lua_State* l, I stackIdx, TNumber& number)
  155. {
  156. lua_Number lnum;
  157. Error err = checkNumberInternal(l, stackIdx, lnum);
  158. if(!err)
  159. {
  160. number = lnum;
  161. }
  162. return err;
  163. }
  164. //==============================================================================
  165. template<typename T>
  166. inline void LuaBinder::exposeVariable(const char* name, T* y)
  167. {
  168. void* ptr = lua_newuserdata(m_l, sizeof(UserData));
  169. UserData* ud = static_cast<UserData*>(ptr);
  170. ud->initPointed(getWrappedTypeSignature<T>(), y);
  171. luaL_setmetatable(m_l, getWrappedTypeName<T>());
  172. lua_setglobal(m_l, name);
  173. }
  174. } // end namespace anki