Pioneer
Loading...
Searching...
No Matches
LuaFlags.h
Go to the documentation of this file.
1// Copyright © 2008-2023 Pioneer Developers. See AUTHORS.txt for details
2// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
3
4#pragma once
5
6#include "utils.h"
7#include <lua.hpp>
8#include <stdexcept>
9#include <string>
10#include <vector>
11
12template <typename FlagType>
13struct LuaFlags {
14 std::vector<std::pair<const char *, FlagType>> LUT;
15 std::string typeName;
16 int lookupTableRef = LUA_NOREF;
17
18 LuaFlags(std::initializer_list<std::pair<const char *, FlagType>> init) :
19 LUT(init) {}
20
21 void Register(lua_State *l, std::string name)
22 {
23 if (lookupTableRef != LUA_NOREF)
24 throw std::runtime_error(std::string("Class ") + name + " is already registered.");
25
26 lua_newtable(l);
27 typeName = name;
28
29 for (auto &pair : LUT) {
30 lua_pushstring(l, pair.first);
31 lua_pushinteger(l, static_cast<unsigned int>(pair.second));
32 lua_settable(l, -3);
33 }
34
35 // luaL_ref pops the table off the stack.
36 lookupTableRef = luaL_ref(l, LUA_REGISTRYINDEX);
37 }
38
39 void Unregister(lua_State *l)
40 {
41 luaL_unref(l, LUA_REGISTRYINDEX, lookupTableRef);
42 lookupTableRef = LUA_NOREF;
43 }
44
45 FlagType LookupTable(lua_State *l, int index)
46 {
47 FlagType flagAccum = FlagType(0);
48 index = lua_absindex(l, index);
49 if (!lua_istable(l, index) || lookupTableRef == LUA_NOREF) return flagAccum;
50
51 lua_checkstack(l, 2);
52 lua_pushinteger(l, lookupTableRef);
53 lua_gettable(l, LUA_REGISTRYINDEX);
54
55 int table_idx = 1;
56 while (true) {
57 lua_pushinteger(l, table_idx++);
58 lua_gettable(l, index);
59
60 if (!lua_isstring(l, -1)) {
61 lua_pop(l, 1);
62 break;
63 }
64
65 flagAccum = static_cast<FlagType>(flagAccum | checkFlag(l, -1, -2));
66 }
67
68 lua_pop(l, 1);
69 return flagAccum;
70 }
71
72 FlagType LookupEnum(lua_State *l, int index)
73 {
74 FlagType flagAccum = FlagType(0);
75 index = lua_absindex(l, index);
76 if (!lua_isstring(l, index) || lookupTableRef == LUA_NOREF) return flagAccum;
77
78 lua_checkstack(l, 2);
79 lua_pushinteger(l, lookupTableRef);
80 lua_gettable(l, LUA_REGISTRYINDEX);
81
82 return checkFlag(l, index, -1);
83 }
84
85private:
86 inline FlagType checkFlag(lua_State *l, int index, int lookup_index)
87 {
88 lookup_index = lua_absindex(l, lookup_index);
89 lua_pushvalue(l, index);
90 lua_gettable(l, lookup_index);
91 if (lua_isnumber(l, -1)) {
92 // bitwise operations implicitly convert to int, so we must explicitly convert back to FlagType.
93 FlagType fl_ret = static_cast<FlagType>(lua_tointeger(l, -1));
94 lua_pop(l, 2); // clean up the stack!
95 return fl_ret;
96 } else {
97 lua_pop(l, 1);
98 std::string index_name = lua_tostring(l, index);
99 lua_pop(l, 2); // clean up the stack!
100 luaL_error(l, "Unknown %s %s", typeName.c_str(), index_name.c_str());
101 }
102 return FlagType(0);
103 }
104};
Definition LuaFlags.h:13
FlagType LookupEnum(lua_State *l, int index)
Definition LuaFlags.h:72
void Unregister(lua_State *l)
Definition LuaFlags.h:39
void Register(lua_State *l, std::string name)
Definition LuaFlags.h:21
LuaFlags(std::initializer_list< std::pair< const char *, FlagType > > init)
Definition LuaFlags.h:18
FlagType LookupTable(lua_State *l, int index)
Definition LuaFlags.h:45
std::vector< std::pair< const char *, FlagType > > LUT
Definition LuaFlags.h:14
std::string typeName
Definition LuaFlags.h:15
int lookupTableRef
Definition LuaFlags.h:16