Files
lunch-games/source/luad/conversions/variant.d
2025-04-29 01:59:15 +02:00

128 lines
2.3 KiB
D

/**
Internal module for pushing and getting variants (from $(STDMODULE _variant)).
Currently, only $(STDREF _variant,Algebraic) is supported.
*/
module luad.conversions.variant;
import luad.c.all;
import luad.stack;
import luad.base;
import std.traits;
import std.variant;
import std.typetuple;
void pushVariant(T)(lua_State* L, ref T value) if(isVariant!T)
{
if(!value.hasValue())
{
lua_pushnil(L);
return;
}
foreach(Type; value.AllowedTypes)
{
if(auto v = value.peek!Type)
{
pushValue(L, *v);
return;
}
}
assert(false);
}
T getVariant(T)(lua_State* L, int idx) if (isVariant!T)
{
auto t = lua_type(L, idx);
foreach(Type; T.AllowedTypes)
if(t == luaTypeOf!Type)
return T(getValue!Type(L, idx));
assert(false); // TODO: runtime error
}
bool isAllowedType(T)(lua_State* L, int idx) {
auto t = lua_type(L, idx);
foreach(Type; T.AllowedTypes)
if(t == luaTypeOf!Type)
return true;
return false;
}
template isVariant(T)
{
enum isVariant = is(typeof(isVariantImpl(T.init)));
static if(isVariant)
static assert(
T.AllowedTypes.length > 0,
"Variant is not supported - use an instance of VariantN with an explicit AllowedTypes list, such as Algebraic"
);
}
private void isVariantImpl(size_t max, AllowedTypes...)(const VariantN!(max, AllowedTypes) v){}
version(unittest) import luad.testing;
unittest
{
lua_State* L = luaL_newstate();
scope(success) lua_close(L);
luaL_openlibs(L);
version(none)
{
Variant v = 123;
pushValue(L, v);
assert(popValue!int(L) == 123);
}
alias Algebraic!(real, string, bool) BasicLuaType;
BasicLuaType v = "test";
pushValue(L, v);
assert(lua_isstring(L, -1));
assert(getValue!string(L, -1) == "test");
assert(popValue!BasicLuaType(L) == "test");
v = 2.3L;
pushValue(L, v);
assert(lua_isnumber(L, -1));
lua_setglobal(L, "num");
unittest_lua(L, `
assert(num == 2.3)
`);
v = true;
pushValue(L, v);
assert(lua_isboolean(L, -1));
assert(popValue!bool(L));
struct S
{
int i;
double n;
string s;
void f(){}
}
pushValue(L, Algebraic!(S, int)(S(1, 2.3, "hello")));
assert(lua_istable(L, -1));
lua_setglobal(L, "struct");
unittest_lua(L, `
for key, expected in pairs{i = 1, n = 2.3, s = "hello"} do
local value = struct[key]
assert(
value == expected,
("bad table pair: '%s' = '%s' (expected '%s')"):format(key, value, expected)
)
end
`);
}