128 lines
2.3 KiB
D
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
|
|
`);
|
|
}
|
|
|