diff options
Diffstat (limited to 'plugins/MirLua/src/mlua_metatable.h')
-rw-r--r-- | plugins/MirLua/src/mlua_metatable.h | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/plugins/MirLua/src/mlua_metatable.h b/plugins/MirLua/src/mlua_metatable.h new file mode 100644 index 0000000000..ffedc22134 --- /dev/null +++ b/plugins/MirLua/src/mlua_metatable.h @@ -0,0 +1,155 @@ +#ifndef _LUA_METATABLE_H_
+#define _LUA_METATABLE_H_
+
+#include <map>
+#include <string>
+
+#define LUA_TINTEGER LUA_NUMTAGS + 1
+#define LUA_TSTRINGA LUA_NUMTAGS + 2
+#define LUA_TSTRINGW LUA_NUMTAGS + 3
+
+struct MTField
+{
+ size_t offset;
+ size_t size;
+ int type;
+
+ MTField(size_t offset, size_t size, int type)
+ : offset(offset), size(size), type(type) { }
+};
+
+template<typename T>
+class MT
+{
+private:
+ static const char *name;
+ static std::map<std::string, MTField*> fields;
+
+ template<typename R> static int GetType(R T::*) { return NULL; }
+
+ template<> static int GetType(int T::*) { return LUA_TINTEGER; }
+ template<> static int GetType(unsigned int T::*) { return LUA_TINTEGER; }
+ template<> static int GetType(long T::*) { return LUA_TINTEGER; }
+ template<> static int GetType(unsigned long T::*) { return LUA_TINTEGER; }
+ template<> static int GetType(long long T::*) { return LUA_TINTEGER; }
+ template<> static int GetType(unsigned long long T::*) { return LUA_TINTEGER; }
+
+ template<> static int GetType(char* T::*) { return LUA_TSTRINGA; }
+ template<> static int GetType(wchar_t* T::*) { return LUA_TSTRINGW; }
+
+ template<typename R>
+ static R GetValue(const T *obj, size_t offset, size_t size)
+ {
+ R res;
+ memcpy(&res, ((char*)obj) + offset, size);
+ return res;
+ }
+
+ static int __new(lua_State *L)
+ {
+ T *obj = NULL;
+ T **udata = NULL;
+
+ int type = lua_type(L, 1);
+ switch (type)
+ {
+ case LUA_TLIGHTUSERDATA:
+ obj = (T*)MT::Load(L);
+ if (obj == NULL) break;
+ //case LUA_TNONE:
+ udata = (T**)lua_newuserdata(L, sizeof(T*));
+ *udata = MT::Init(obj);
+ //case LUA_TUSERDATA:
+ // luaL_setmetatable(L, MT::name);
+ // return 1;
+ }
+ lua_pushnil(L);
+
+ return 1;
+ }
+
+ static int __index(lua_State *L)
+ {
+ T *obj = *(T**)luaL_checkudata(L, 1, MT::name);
+ const char *key = lua_tostring(L, 2);
+
+ auto it = fields.find(key);
+ if (it == fields.end())
+ {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ MTField *field = it->second;
+ size_t offset = field->offset;
+ size_t size = field->size;
+
+ switch (field->type)
+ {
+ case LUA_TBOOLEAN:
+ lua_pushboolean(L, GetValue<bool>(obj, offset, size));
+ break;
+ case LUA_TINTEGER:
+ lua_pushinteger(L, GetValue<long long>(obj, offset, size));
+ break;
+ case LUA_TNUMBER:
+ lua_pushnumber(L, GetValue<double>(obj, offset, size));
+ break;
+ case LUA_TSTRING:
+ lua_pushstring(L, GetValue<char*>(obj, offset, size));
+ break;
+ case LUA_TSTRINGA:
+ lua_pushstring(L, ptrA(mir_utf8encode(GetValue<char*>(obj, offset, size))));
+ break;
+ case LUA_TSTRINGW:
+ lua_pushstring(L, ptrA(mir_utf8encodeW(GetValue<wchar_t*>(obj, offset, size))));
+ break;
+ default:
+ lua_pushnil(L);
+ }
+
+ return 1;
+ }
+
+ static int __gc(lua_State *L)
+ {
+ T** obj = (T**)luaL_checkudata(L, 1, MT::name);
+ MT::Free(obj);
+ return 0;
+ }
+
+ static T* Load(lua_State *L) { return (T*)lua_touserdata(L, 1); }
+ static T* Init(T *val) { return val; }
+ static void Free(T *obj) { obj = NULL; }
+
+public:
+ MT(lua_State *L, const char *tname)
+ {
+ MT::name = tname;
+
+ lua_pushcfunction(L, __new);
+ lua_setglobal(L, MT::name);
+
+ luaL_newmetatable(L, MT::name);
+ lua_pushcfunction(L, __index);
+ lua_setfield(L, -2, "__index");
+ }
+
+ template<typename R>
+ MT& Field(R T::*M, const char *name, int type = LUA_TNONE, size_t size = sizeof(R))
+ {
+ size_t offset = reinterpret_cast<size_t>(&(((T*)0)->*M));
+ if (type == LUA_TNONE) type = GetType(M);
+ if (type != LUA_TNONE)
+ fields[name] = new MTField(offset, size, type);
+ return *this;
+ }
+};
+
+template<typename T>
+const char *MT<T>::name;
+
+template<typename T>
+std::map<std::string, MTField*> MT<T>::fields;
+
+#endif //_LUA_METATABLE_H_
|