op0x90gang

Lua Native Function Wrapper

Feb 9th, 2021 (edited)
664
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.44 KB | None | 0 0
  1. /*
  2.     Was too lazy to put this on my github, so here's pastebin
  3.     What is this:
  4.         This calls C functions from lua directly, with no need to make wrapper stubs for every function
  5.         It's designed for Lua 5.2 so don't complain when this isn't working on Lua 5.1
  6.  
  7.     Usage (I'll use printf in this example):
  8.         lua_State* L = luaL_newstate(L);
  9.         luaL_openlibs(L);
  10.         native::opennative(L);
  11.         native::new_native(L, &printf);
  12.         lua_setglobal(L, "printf");
  13.    
  14.     And just like that you can call printf from Lua with no need for a wrapper function.
  15.  
  16. */
  17.  
  18. namespace native
  19. {
  20. #ifdef _M_IX86
  21.     typedef std::uint32_t uint_t;
  22. #else
  23.     typedef std::uint64_t uint_t;
  24. #endif
  25.  
  26.     enum class calling_convention
  27.     {
  28.         none_t,
  29.         cdecl_t,
  30.         stdcall_t,
  31.         fastcall_t,
  32.         thiscall_t
  33.     };
  34.  
  35.     struct native
  36.     {
  37.         calling_convention cc;
  38.         uint_t address;
  39.  
  40.         native(calling_convention cc, uint_t address) : cc(cc), address(address) {}
  41.     };
  42.  
  43.     template<std::size_t argc, typename... T>
  44.     uint_t call_t(uint_t func, calling_convention cc, uint_t* args, std::size_t f_argc, T... a)
  45.     {
  46.         if constexpr (argc != 0)
  47.         {
  48.             if (f_argc)
  49.                 return call_t<argc - 1>(func, cc, args + 1, f_argc - 1, a..., *args);
  50.             else
  51.             {
  52.                 switch (cc)
  53.                 {
  54.                     case calling_convention::cdecl_t:
  55.                         return ((uint_t(__cdecl*)(T...))func)(a...);
  56.                     case calling_convention::fastcall_t:
  57.                         return ((uint_t(__fastcall*)(T...))func)(a...);
  58.                     case calling_convention::stdcall_t:
  59.                         return ((uint_t(__stdcall*)(T...))func)(a...);
  60.                     case calling_convention::thiscall_t:
  61.                         return ((uint_t(__thiscall*)(T...))func)(a...);
  62.                 }
  63.             }
  64.         }
  65.  
  66.         else if (cc == calling_convention::none_t)
  67.             return ((uint_t(*)())func)();
  68.  
  69.         return 0;
  70.     }
  71.  
  72.     __forceinline native* luaL_checknative(lua_State* L, int idx)
  73.     {
  74.         return reinterpret_cast<native*>(luaL_checkudata(L, idx, "Native"));
  75.     }
  76.  
  77.     const void* luaL_topointer(lua_State* L, int idx)
  78.     {
  79.         switch (lua_type(L, idx))
  80.         {
  81.             case LUA_TSTRING:
  82.                 return reinterpret_cast<const void*>(lua_tolstring(L, idx, 0));
  83.             case LUA_TLIGHTUSERDATA:
  84.             case LUA_TUSERDATA:
  85.             case LUA_TTABLE:
  86.             case LUA_TFUNCTION:
  87.             case LUA_TTHREAD:
  88.                 return lua_topointer(L, idx);
  89.             default: return 0;
  90.         }
  91.     }
  92.  
  93.     int new_native_decl(lua_State* L)
  94.     {
  95.         native* function = reinterpret_cast<native*>(lua_newuserdata(L, sizeof(native)));
  96.         luaL_getmetatable(L, "Native");
  97.         lua_setmetatable(L, -2);
  98.         return 1;
  99.     }
  100.  
  101.     int call(lua_State* L)
  102.     {
  103.         native* func = luaL_checknative(L, 1);
  104.         int nargs = lua_gettop(L) - 1;
  105.  
  106.         uint_t* alloc = nargs ? new uint_t[nargs] : nullptr;
  107.         for (int idx = 0; idx < nargs; idx++)
  108.             alloc[idx] = reinterpret_cast<uint_t>(luaL_topointer(L, idx + 2));
  109.  
  110.         uint_t ret = call_t<16>(func->address, func->cc, alloc, nargs);
  111.         lua_pushunsigned(L, ret);
  112.         return 1;
  113.     }
  114.  
  115.     int tostring(lua_State* L)
  116.     {
  117.         native* f = luaL_checknative(L, 1);
  118.         lua_pushfstring(L, "function: %p", f->address);
  119.         return 1;
  120.     }
  121.  
  122.     const luaL_Reg metamethods[] =
  123.     {
  124.         {"__tostring", tostring},
  125.         {"__call", call}
  126.     };
  127.  
  128.     void opennative(lua_State* L)
  129.     {
  130.         luaL_newmetatable(L, "Native");
  131.         lua_pushvalue(L, -1);
  132.         lua_setfield(L, -2, "__index");
  133.         luaL_openlib(L, NULL, metamethods, 0);
  134.     }
  135.  
  136.     void new_native(lua_State* L, void* function, calling_convention cc = calling_convention::cdecl_t)
  137.     {
  138.         new_native_decl(L);
  139.         native* ptr = luaL_checknative(L, -1);
  140.         ptr->address = reinterpret_cast<uint_t>(function);
  141.         ptr->cc = cc;
  142.     }
  143. }
Advertisement
Add Comment
Please, Sign In to add comment