1 /** 2 Internal module for pushing and getting variants (from $(STDMODULE _variant)). 3 Currently, only $(STDREF _variant,Algebraic) is supported. 4 */ 5 module luad.conversions.variant; 6 7 import luad.c.all; 8 9 import luad.stack; 10 import luad.base; 11 import std.traits; 12 import std.variant; 13 import std.typetuple; 14 15 void pushVariant(T)(lua_State* L, ref T value) if(isVariant!T) 16 { 17 if(!value.hasValue()) 18 { 19 lua_pushnil(L); 20 return; 21 } 22 23 foreach(Type; value.AllowedTypes) 24 { 25 if(auto v = value.peek!Type) 26 { 27 pushValue(L, *v); 28 return; 29 } 30 } 31 32 assert(false); 33 } 34 35 T getVariant(T)(lua_State* L, int idx) if (isVariant!T) 36 { 37 auto t = lua_type(L, idx); 38 39 foreach(Type; T.AllowedTypes) 40 if(t == luaTypeOf!Type) 41 return T(getValue!Type(L, idx)); 42 43 assert(false); // TODO: runtime error 44 } 45 46 bool isAllowedType(T)(lua_State* L, int idx) { 47 auto t = lua_type(L, idx); 48 49 foreach(Type; T.AllowedTypes) 50 if(t == luaTypeOf!Type) 51 return true; 52 53 return false; 54 } 55 56 template isVariant(T) 57 { 58 enum isVariant = is(typeof(isVariantImpl(T.init))); 59 static if(isVariant) 60 static assert( 61 T.AllowedTypes.length > 0, 62 "Variant is not supported - use an instance of VariantN with an explicit AllowedTypes list, such as Algebraic" 63 ); 64 } 65 66 private void isVariantImpl(size_t max, AllowedTypes...)(const VariantN!(max, AllowedTypes) v){} 67 68 version(unittest) import luad.testing; 69 70 unittest 71 { 72 lua_State* L = luaL_newstate(); 73 scope(success) lua_close(L); 74 luaL_openlibs(L); 75 76 version(none) 77 { 78 Variant v = 123; 79 pushValue(L, v); 80 assert(popValue!int(L) == 123); 81 } 82 83 alias Algebraic!(real, string, bool) BasicLuaType; 84 85 BasicLuaType v = "test"; 86 pushValue(L, v); 87 assert(lua_isstring(L, -1)); 88 assert(getValue!string(L, -1) == "test"); 89 assert(popValue!BasicLuaType(L) == "test"); 90 91 v = 2.3L; 92 pushValue(L, v); 93 assert(lua_isnumber(L, -1)); 94 lua_setglobal(L, "num"); 95 96 unittest_lua(L, ` 97 assert(num == 2.3) 98 `); 99 100 v = true; 101 pushValue(L, v); 102 assert(lua_isboolean(L, -1)); 103 assert(popValue!bool(L)); 104 105 struct S 106 { 107 int i; 108 double n; 109 string s; 110 111 void f(){} 112 } 113 pushValue(L, Algebraic!(S, int)(S(1, 2.3, "hello"))); 114 assert(lua_istable(L, -1)); 115 lua_setglobal(L, "struct"); 116 117 unittest_lua(L, ` 118 for key, expected in pairs{i = 1, n = 2.3, s = "hello"} do 119 local value = struct[key] 120 assert( 121 value == expected, 122 ("bad table pair: '%s' = '%s' (expected '%s')"):format(key, value, expected) 123 ) 124 end 125 `); 126 } 127