Skip to content

Commit 5f58914

Browse files
committed
Added support for enum's.
Enums are held in Lua as strings. No support for enum values that are not valid keys. No support for bitfields (yet?). Conversion function performance could be improved (linear search >_<).
1 parent ff8dfe5 commit 5f58914

3 files changed

Lines changed: 194 additions & 1 deletion

File tree

luad/conversions/enums.d

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/**
2+
Internal module for pushing and getting _enums.
3+
4+
... info?
5+
*/
6+
module luad.conversions.enums;
7+
8+
import luad.c.all;
9+
import luad.stack;
10+
11+
import std.traits;
12+
import std.conv;
13+
import std.range;
14+
import std.string;
15+
16+
struct KeyValuePair(ValueType)
17+
{
18+
string key;
19+
ValueType value;
20+
}
21+
22+
// produce a tuple of KeyValuePair's for an enum.
23+
template EnumKeyValuePair(Enum)
24+
{
25+
template impl(size_t len, size_t offset, Items...)
26+
{
27+
static if(offset == len)
28+
alias impl = TypeTuple!();
29+
else
30+
alias impl = TypeTuple!(KeyValuePair!Enum(Items[offset], Items[len + offset]), impl!(len, offset + 1, Items));
31+
}
32+
33+
alias Keys = TypeTuple!(__traits(allMembers, Enum));
34+
alias Values = EnumMembers!Enum;
35+
static assert(Keys.length == Values.length);
36+
37+
alias EnumKeyValuePair = impl!(Keys.length, 0, TypeTuple!(Keys, Values));
38+
}
39+
40+
immutable(KeyValuePair!Enum)[] getKeyValuePairs(Enum)() pure nothrow @nogc
41+
{
42+
static immutable(KeyValuePair!Enum[]) kvp = [ EnumKeyValuePair!Enum ];
43+
return kvp;
44+
}
45+
46+
// TODO: These linear lookups are pretty crappy... we can do better, but this get's us working.
47+
Enum getEnumValue(Enum)(lua_State* L, const(char)[] value) if(is(Enum == enum))
48+
{
49+
value = value.strip;
50+
if(!value.empty)
51+
{
52+
auto kvp = getKeyValuePairs!Enum();
53+
foreach(ref i; kvp)
54+
{
55+
if(!icmp(i.key, value)) // case inseneitive enum keys...
56+
return i.value;
57+
}
58+
}
59+
luaL_error(L, "invalid enum key '%s' for enum type %s", value.ptr, Enum.stringof.ptr);
60+
return Enum.init;
61+
}
62+
63+
string getEnumFromValue(Enum)(Enum value)
64+
{
65+
auto kvp = getKeyValuePairs!Enum();
66+
foreach(ref i; kvp)
67+
{
68+
if(value == i.value)
69+
return i.key;
70+
}
71+
return null;
72+
}
73+
74+
/+ TODO: I'd quite like to support bitfields too...
75+
uint getBitfieldValue(Enum)(const(char)[] flags)
76+
{
77+
uint value;
78+
foreach(token; flags.splitter('|').map!(a => a.strip).filter!(a => !a.empty))
79+
{
80+
Enum val = getEnumValue!Enum(token);
81+
if(val != cast(Enum)-1)
82+
value |= val;
83+
}
84+
return value;
85+
}
86+
87+
string getBitfieldFromValue(Enum)(uint bits)
88+
{
89+
string bitfield;
90+
foreach(i; 0..32)
91+
{
92+
uint bit = 1 << i;
93+
if(!(bits & bit))
94+
continue;
95+
96+
string key = getEnumFromValue(cast(Enum)bit);
97+
if(key)
98+
{
99+
if(!bitfield)
100+
bitfield = key;
101+
else
102+
bitfield = bitfield ~ "|" ~ key;
103+
}
104+
}
105+
return bitfield;
106+
}
107+
+/
108+
109+
void pushEnum(T)(lua_State* L, T value) if (is(T == enum))
110+
{
111+
string key = getEnumFromValue(value);
112+
if(key)
113+
lua_pushlstring(L, key.ptr, key.length);
114+
else
115+
luaL_error(L, "invalid value for enum type %s", T.stringof.ptr);
116+
}
117+
118+
T getEnum(T)(lua_State* L, int idx) if(is(T == enum))
119+
{
120+
// TODO: check to see if idx is a number, if it is, convert it directly?
121+
122+
size_t len;
123+
const(char)* s = lua_tolstring(L, idx, &len);
124+
return getEnumValue!T(L, s[0..len]);
125+
}
126+
127+
void pushStaticTypeInterface(T)(lua_State* L) if(is(T == enum))
128+
{
129+
lua_newtable(L);
130+
131+
// TODO: we could get fancy and make an __index table of keys, so that they are read-only
132+
// ... but for now, we'll just populate a table with the keys as strings
133+
134+
// set 'init'
135+
string initVal = getEnumFromValue(T.init);
136+
lua_pushlstring(L, initVal.ptr, initVal.length);
137+
lua_setfield(L, -2, "init");
138+
139+
// TODO: integral enums also have 'min' and 'max'
140+
141+
// we'll create tables for the keys and valyes arrays.
142+
lua_newtable(L); // keys
143+
lua_newtable(L); // values
144+
145+
// add the enum keys
146+
auto kvp = getKeyValuePairs!T();
147+
foreach(int i, ref e; kvp)
148+
{
149+
// set the key to the key string (lua will carry enums by string)
150+
lua_pushlstring(L, e.key.ptr, e.key.length);
151+
lua_setfield(L, -4, e.key.ptr);
152+
153+
// push the key to the keys array
154+
lua_pushlstring(L, e.key.ptr, e.key.length);
155+
lua_rawseti(L, -3, i+1);
156+
157+
// push the value to the values array
158+
pushValue!(OriginalType!T)(L, e.value);
159+
lua_rawseti(L, -2, i+1);
160+
}
161+
162+
lua_setfield(L, -3, "values");
163+
lua_setfield(L, -2, "keys");
164+
}
165+
166+
version(unittest)
167+
{
168+
import luad.base;
169+
170+
//...
171+
}
172+
173+
unittest
174+
{
175+
import luad.testing;
176+
177+
lua_State* L = luaL_newstate();
178+
scope(success) lua_close(L);
179+
luaL_openlibs(L);
180+
181+
//...
182+
}

luad/stack.d

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import luad.conversions.arrays;
7171
import luad.conversions.structs;
7272
import luad.conversions.assocarrays;
7373
import luad.conversions.classes;
74+
import luad.conversions.enums;
7475
import luad.conversions.variant;
7576

7677
/**
@@ -90,6 +91,9 @@ void pushValue(T)(lua_State* L, T value)
9091
else static if(is(T == Nil))
9192
lua_pushnil(L);
9293

94+
else static if(is(T == enum))
95+
pushEnum(L, value);
96+
9397
else static if(is(T == bool))
9498
lua_pushboolean(L, cast(bool)value);
9599

@@ -157,7 +161,10 @@ template isVoidArray(T)
157161
*/
158162
template luaTypeOf(T)
159163
{
160-
static if(is(T == bool))
164+
static if(is(T == enum))
165+
enum luaTypeOf = LUA_TSTRING;
166+
167+
else static if(is(T == bool))
161168
enum luaTypeOf = LUA_TBOOLEAN;
162169

163170
else static if(is(T == Nil))
@@ -251,6 +258,9 @@ T getValue(T, alias typeMismatchHandler = defaultTypeMismatch)(lua_State* L, int
251258
else static if(is(T == Nil))
252259
return nil;
253260

261+
else static if(is(T == enum))
262+
return getEnum!T(L, idx);
263+
254264
else static if(is(T == bool))
255265
return lua_toboolean(L, idx);
256266

luad/state.d

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import std.typecons : isTuple;
88
import luad.c.all;
99
import luad.stack;
1010
import luad.conversions.classes;
11+
import luad.conversions.enums;
1112

1213
import luad.base, luad.table, luad.lfunction, luad.dynamic, luad.error;
1314

0 commit comments

Comments
 (0)