Created
May 8, 2020 09:18
-
-
Save EvanMu96/7e169117472308c7fe59fc000101b0c6 to your computer and use it in GitHub Desktop.
basic lua binding header helper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "lunatic.h" | |
#include <lua-5.1/lua.hpp> | |
#include <stdio.h> | |
class LuaTest { | |
public: | |
LuaTest() {} | |
LuaTest(lua_State * L) {} | |
static const char className[]; | |
static Lunatic<LuaTest>::RegType methods[]; | |
int TestString(lua_State * L) {printf("this string is printed by c++\n");return 0;} | |
}; | |
class LuaTest2 { | |
public: | |
LuaTest2() {} | |
LuaTest2(lua_State * L) {} | |
static const char className[]; | |
static Lunatic<LuaTest2>::RegType methods[]; | |
int TestString(lua_State * L) {printf("this string is printed by c++\n");return 0;} | |
}; | |
const char LuaTest::className[] = "LuaTest"; | |
const char LuaTest2::className[] = "LuaTest2"; | |
#define method(class, name) {#name, &class::name} | |
Lunatic<LuaTest>::RegType LuaTest::methods[] = { | |
method(LuaTest, TestString), {nullptr, nullptr} | |
}; | |
Lunatic<LuaTest2>::RegType LuaTest2::methods[] = { | |
method(LuaTest2, TestString), {nullptr, nullptr} | |
}; | |
int main() { | |
lua_State * L = luaL_newstate(); | |
luaL_openlibs(L); | |
// ok to bind multiple classes | |
Lunatic<LuaTest>::Register(L); | |
Lunatic<LuaTest2>::Register(L); | |
// do_file better to use a absolute path | |
luaL_dofile(L, "/Users/******************/test.lua"); | |
lua_close(L); | |
return 0; | |
} | |
/* | |
test.lua | |
test = LuaTest() | |
test:TestString() | |
print("test string in lua") | |
*/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <lua-5.1/lua.hpp> | |
template <typename T> | |
class Lunatic { | |
typedef struct {T * pt;} userDataType; | |
public: | |
typedef int (T::*mfp)(lua_State * L); | |
typedef struct{const char * name; mfp mfunc;} RegType; | |
static void Register(lua_State * L) { | |
// 用一个tabble 保存栈索引,这个方法表就是要用来保存要导出的成员函数 | |
lua_newtable(L); | |
int methods = lua_gettop(L); | |
// 在注册表中新建一个元素, metatable保存其栈索引 | |
luaL_newmetatable(L, T::className); | |
int metatable = lua_gettop(L); | |
// 全局表(T::className)=methods表 | |
lua_pushstring(L, T::className); | |
lua_pushvalue(L, methods); | |
lua_settable(L, LUA_GLOBALSINDEX); | |
// 设置metatable 的_metatable元事件 | |
// 将metatable封装起来,防止外部的获取和修改 | |
lua_pushliteral(L, "__metatable"); | |
lua_pushvalue(L, methods); | |
lua_settable(L, metatable); | |
lua_pushliteral(L, "__index"); | |
lua_pushvalue(L, methods); | |
lua_settable(L, metatable); | |
// 设置元表 __tostring和__gc (gc暂且不实现, 我们希望对象的生命周期完全在c++) | |
lua_pushliteral(L, "__tostring"); | |
lua_pushcfunction(L, tostring_T); | |
lua_settable(L, metatable); | |
lua_pushliteral(L, "__gc"); | |
lua_pushcfunction(L, gc_T); | |
lua_settable(L ,metatable); | |
// 设置mt的_call metamethod a()时触发 | |
lua_newtable(L); | |
int mt = lua_gettop(L); | |
lua_pushliteral(L, "__call"); | |
lua_pushcfunction(L, new_T); | |
lua_pushliteral(L, "new"); | |
lua_pushvalue(L, -2); | |
lua_settable(L, methods); | |
lua_settable(L, mt); | |
lua_setmetatable(L, methods); | |
// fill method table with methods from class T | |
for(RegType *l = T::methods; l->name; l++) { | |
lua_pushstring(L, l->name); | |
lua_pushlightuserdata(L, (void*)l); | |
lua_pushcclosure(L, thunk, 1); // 创建closure | |
lua_settable(L, methods); | |
} | |
lua_pop(L, 2); // drop metatabke abd method table | |
} | |
static T * check(lua_State * L, int narg) { | |
userDataType * ud = static_cast<userDataType*> (luaL_checkudata(L, narg, T::className)); | |
if(nullptr == ud) { | |
luaL_typerror(L, narg, T::className); | |
} | |
return ud->pt; | |
} | |
private: | |
Lunatic(); | |
static int thunk(lua_State * L) { | |
T * obj = check(L, 1); | |
lua_remove(L, 1); //remove self | |
RegType * l = static_cast<RegType*>(lua_touserdata(L, lua_upvalueindex(1))); | |
return (obj->*(l->mfunc))(L); //call member function | |
} | |
static int new_T(lua_State * L) { | |
lua_remove(L, 1); | |
T * obj = new T(L); | |
userDataType *ud = static_cast<userDataType*>(lua_newuserdata(L, sizeof(userDataType))); | |
ud->pt = obj; // store pointer to object in userdata | |
luaL_getmetatable(L, T::className); | |
lua_setmetatable(L, -2); | |
return 1; | |
} | |
static int tostring_T (lua_State * L) { | |
char buff[32]; | |
userDataType * ud = static_cast<userDataType*>(lua_touserdata(L, 1)); | |
T * obj = ud->pt; | |
sprintf(buff, "%p", obj); | |
lua_pushfstring(L, "%s (%s)", T::className, buff); | |
return 1; | |
} | |
static int gc_T(lua_State * L) { | |
userDataType * ud = static_cast<userDataType*>(lua_touserdata(L, 1)); | |
T * obj = ud->pt; | |
delete obj; // call dtor | |
return 0; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment