#pragma once
#include <functional>
#include <vector>
#include "lua.hpp"
namespace sunny {
template <typename T>
class luna {
private:
using member_func_t = std::function<int(lua_State*, T&)>;
member_func_t func_;
public:
static std::vector<member_func_t> methods_;
static const char* class_name_;
static void register_class(lua_State* L) {
luaL_newmetatable(L, class_name_);
int metatable = lua_gettop(L);
lua_pushstring(L, "__index");
lua_pushcfunction(L, &luna<T>::find);
lua_settable(L, metatable);
}
static void push(lua_State* L, T* instance) {
auto a = static_cast<T**>(lua_newuserdata(L, sizeof(T*)));
*a = instance;
luaL_getmetatable(L, class_name_);
lua_setmetatable(L, -2);
}
static void add_member_func(lua_State* L, const char* name, member_func_t func) {
methods_.push_back(func);
int metatable = lua_gettop(L);
lua_pushstring(L, name);
lua_pushnumber(L, methods_.size() - 1);
lua_settable(L, metatable);
}
private:
static int find(lua_State* L) {
lua_getmetatable(L, 1);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
if (lua_isnumber(L, -1)) {
int _index = lua_tonumber(L, -1);
auto obj = static_cast<T**>(lua_touserdata(L, 1));
lua_pushnumber(L, _index);
lua_pushlightuserdata(L, obj);
lua_pushcclosure(L, &luna<T>::call, 2);
return 1;
}
return 1;
}
static int call(lua_State* L) {
int i = (int)lua_tonumber(L, lua_upvalueindex(1));
auto obj = static_cast<T**>(lua_touserdata(L, lua_upvalueindex(2)));
return methods_[i](L, *(*obj));
}
};
#define ADD_MEMBER_FUNC(CLASS_NAME, FUNC_NAME, LUA_FUNC_NAME) \
luna<CLASS_NAME>::add_member_func(state_, #FUNC_NAME, [](lua_State* L, CLASS_NAME& obj) { \
LUA_FUNC_NAME(L, obj.FUNC_NAME()); \
return 1; \
})
#define ADD_MEMBER_FUNC_TO_INTEGER(CLASS_NAME, FUNC_NAME) ADD_MEMBER_FUNC(CLASS_NAME, FUNC_NAME, lua_pushinteger)
#define ADD_MEMBER_FUNC_TO_NUMBER(CLASS_NAME, FUNC_NAME) ADD_MEMBER_FUNC(CLASS_NAME, FUNC_NAME, lua_pushnumber)
#define ADD_MEMBER_FUNC_TO_STRING(CLASS_NAME, FUNC_NAME) \
luna<CLASS_NAME>::add_member_func(state_, #FUNC_NAME, [](lua_State* L, CLASS_NAME& obj) { \
lua_pushstring(L, obj.FUNC_NAME().c_str()); \
return 1; \
})
#define ADD_MEMBER_FUNC_TO_BOOLEAN(CLASS_NAME, FUNC_NAME) ADD_MEMBER_FUNC(CLASS_NAME, FUNC_NAME, lua_pushboolean)
} // namespace sunny
Lunar参考链接
Luna参考链接