Created
January 20, 2019 06:22
-
-
Save LunaTheFoxgirl/c9141a1620eaea1c12072bc32885173e to your computer and use it in GitHub Desktop.
Template magic for Lua.
This file contains hidden or 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
private mixin template luaUserData(T, string name = "") { | |
import std.stdio; | |
enum NAME = name != "" ? name : T.stringof; | |
private: | |
T* data; | |
public: | |
// TODO: Make this a template constraint? | |
LuaStateFunction __new = (state) { | |
// __index function | |
LuaStateFunction __index = (state) { | |
// Index. | |
string index = lua_tostring(state, -1).text; | |
if (index != "selfPtr") { | |
// get self pointer | |
lua_pushstring(state, toStringz("selfPtr")); | |
lua_rawget(state, 1); | |
// self pointer. | |
T* tPtr = (cast(T*)lua_touserdata(state, -1)); | |
// Trait dark magic hide your children. | |
static foreach (element; __traits(derivedMembers, T)) { | |
// Make sure only public members are considered | |
static if (__traits(compiles, __traits(getMember, T, element))) { | |
// They also need to have the @Expose attribute | |
static if (hasUDA!(__traits(getMember, T, element), Expose)) { | |
// And the the right index. | |
if (element == index) { | |
// Finally return it. | |
mixin(q{g_push!(typeof(__traits(getMember, T, element)))(state, tPtr.%s);}.format(element)); | |
return 1; | |
} | |
} | |
} | |
} | |
} | |
// return other things users might've set. | |
lua_pushstring(state, toStringz(index)); | |
lua_rawget(state, 1); | |
return 1; | |
}; | |
// __newindex function | |
LuaStateFunction __newindex = (state) { | |
// Get value | |
Variant val = stackToVariant(state); | |
// ! remember to pop first | |
lua_pop(state, 1); | |
// get index. | |
string index = stackToVariant(state).coerce!string; | |
if (index != "selfPtr") { | |
// Push string of self pointer. | |
lua_pushstring(state, toStringz("selfPtr")); | |
lua_rawget(state, 1); | |
T* tPtr = (cast(T*)lua_touserdata(state, -1)); | |
// Trait dark magic hide your children. | |
static foreach (element; __traits(derivedMembers, T)) { | |
// Make sure only public members are considered | |
static if (__traits(compiles, __traits(getMember, T, element))) { | |
// They also need to have the @Expose attribute | |
static if (hasUDA!(__traits(getMember, T, element), Expose)) { | |
// And the the right index. | |
if (element == index) { | |
// Finally change it. | |
mixin(q{tPtr.%s = val.coerce!%s;}.format(element, typeof(__traits(getMember, T, element)).stringof)); | |
return 0; | |
} | |
} | |
} | |
} | |
} | |
// WE DON'T WANT THE USER TO CHANGE THE SELFPTR. | |
return 0; | |
}; | |
// constructor begin | |
Variant[] params; | |
immutable(int) stack = lua_gettop(state); | |
foreach (i; 0 .. stack) { | |
params ~= stackToVariant(state); | |
} | |
lua_pop(state, stack); | |
// Instantiate T. | |
static if (is(T == struct)) { | |
T* tInstance = new T; | |
tInstance.instantiate(params); | |
} else { | |
T tInstance = new T; | |
tInstance.instantiate(params); | |
} | |
// Create local table. | |
LuaLocalTable table = new LuaLocalTable(state); | |
int mtabId = lua_gettop(state); | |
table.set!(string, T*)("selfPtr", tInstance); | |
LuaMetaTable metaTable = new LuaMetaTable(state, "A"); | |
int mttabId = lua_gettop(state); | |
metaTable.set!(string, LuaStateFunction)("__index", __index); | |
metaTable.set!(string, LuaStateFunction)("__newindex", __newindex); | |
metaTable.setMetatable(); | |
lua_pop(state, 1); | |
return lua_gettop(state); | |
}; | |
T get() { | |
return *data; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment