Skip to content

Instantly share code, notes, and snippets.

@LunaTheFoxgirl
Created January 20, 2019 06:22
Show Gist options
  • Save LunaTheFoxgirl/c9141a1620eaea1c12072bc32885173e to your computer and use it in GitHub Desktop.
Save LunaTheFoxgirl/c9141a1620eaea1c12072bc32885173e to your computer and use it in GitHub Desktop.
Template magic for Lua.
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