Sélectionner une révision Git
CRTPLuaScriptObject.hh
CRTPLuaScriptObject.hh 6,48 Kio
#pragma once
#include "LuaContext.hh"
#include "lua.hpp"
#include <vector>
#include <cstdio>
namespace Vivy::Script
{
// clang-format off
#define LUA_DECL_METHOD(class, name) luaL_Reg{ #name, class ::name }
#define LUA_DECL_CREATE(class) luaL_Reg{ "new", class ::CREATE }
#define script_class(theClassName) \
class theClassName final : public CRTPLuaScriptObject<theClassName>
#define method_list static constexpr inline auto
#define LUA_SCRIPTABLE_CLASS(theClassName) \
VIVY_UNMOVABLE_OBJECT(theClassName) \
static constexpr char className[] = #theClassName; \
friend CRTPLuaScriptObject<theClassName>; \
theClassName(lua_State *) noexcept; \
~theClassName() noexcept;
// clang-format on
// CRTP to expose objects to Lua
template <class Object> class CRTPLuaScriptObject {
protected:
static int GC(lua_State *L) noexcept
{
const Object *obj = reinterpret_cast<const Object *>(lua_topointer(L, 1));
auto *context = LuaContext::getContext(L);
err(context) << "Call destructor for " << Object::className << "\n";
obj->~Object();
return 0;
}
static int CREATE(lua_State *L) noexcept
{
Object *obj = reinterpret_cast<Object *>(lua_newuserdata(L, sizeof(Object)));
new (obj) Object(L);
luaL_getmetatable(L, Object::className);
lua_setmetatable(L, -2);
return 1;
}
static Object *CHECK(lua_State *L, int index) noexcept
{
luaL_checktype(L, index, LUA_TUSERDATA);
auto *context = LuaContext::getContext(L);
Object *obj = reinterpret_cast<Object *>(luaL_checkudata(L, index, Object::className));
if (obj == nullptr) {
err(context) << "Type error, userdata is not of class " << Object::className << "\n";
luaL_typeerror(L, index, Object::className);
}
return obj;
}
static inline constexpr luaL_Reg luaRegDefaultGC = { "__gc", GC };
public:
static void Register(lua_State *L) noexcept
{
auto *context = LuaContext::getContext(L);
// Fill the method table, newclass = {}
lua_newtable(L);
const int methodtable = lua_gettop(L);