C++ Enum Support in LuaBridge2
Recently I was doing some work to add support for Lua scripting to the Ostinato network traffic generator.
Although there are several solutions for Lua bindings for C++ out there, I decided to go with LuaBridge.
Note that there is a fork of LuaBridge called LuaBridge3, but it requires C++17 and with Ostinato I target a wide variety of platforms some of which are old and still use C++11.
So I decided to stick with the original LuaBridge.
LuaBridge however doesn’t support binding C++ enums. A little bit of googling and reading the documentation I found a solution which I will document here with examples.
First we will add support for passing C++ enums into Lua (as a number). Given the following C++ enums -
enum ProtocolIdType {
ProtocolIdTypeLlc,
ProtocolIdTypeEthernet,
ProtocolIdTypeIp,
ProtocolIdTypeTcpUdp
};
enum CksumType {
CksumTypeIp,
CksumTypeIpPseudo,
CksumTypeTcpUdp
};
We add support for these enums by specializing the LuaBridge Stack template class for each enum type we want to support.
// Helper template for all enums we want to support
template <typename T>
struct EnumWrapper {
static typename std::enable_if<std::is_enum<T>::value, void>::type
push(lua_State* L, T value) {
lua_pushnumber (L, static_cast<std::size_t>(value));
}
static typename std::enable_if<std::is_enum<T>::value, T>::type
get(lua_State* L, int index) {
return static_cast<T>(lua_tointeger(L, index));
}
};
// Use EnumWrapper template for each enum type we want to support
namespace luabridge {
template <>
struct Stack<ProtocolIdType>
: EnumWrapper<ProtocolIdType> {};
template <>
struct Stack<CksumType>
: EnumWrapper <AbstractProtocol::CksumType> {};
}
Now you can pass the enums back and forth between C++ and Lua - the C++ enums will be treated as integers in Lua. So, you can call a Lua function pass in a C++ enum value.
LuaRef payloadProtocolId = getGlobal(L, "payloadProtocolId");
uint id = payloadProtocolId(ProtocolIdTypeIp);
LuaRef idType = getGlobal(L, "payloadProtocolIdType");
ProtocolIdType protocolId = idType();
Remember in Lua code these variables are integers. So any code referencing these will need to compare against the integer values.
if payloadProtocolIdType == 1 then
-- do something
end
What if you wanted to use enums instead of integers in Lua? You can export them as Lua global variables by registering them with LuaBridge as a property under a Lua namespace (table).
// Helper template function for registering enum constants with LuaBridge
template<int T>
int enumValue() {
return T;
}
getGlobalNamespace(L_)
.beginNamespace("Protocol")
// Enum ProtocolIdType
.addProperty("ProtocolIdLlc", &enumValue<AbstractProtocol::ProtocolIdLlc>)
.addProperty("ProtocolIdEth", &enumValue<AbstractProtocol::ProtocolIdEth>)
.addProperty("ProtocolIdIp", &enumValue<AbstractProtocol::ProtocolIdIp>)
.addProperty("ProtocolIdTcpUdp", &enumValue<AbstractProtocol::ProtocolIdTcpUdp>)
// Enum CksumType
.addProperty("CksumIp", &enumValue<AbstractProtocol::CksumIp>)
.addProperty("CksumIpPseudo", &enumValue<AbstractProtocol::CksumIpPseudo>)
.addProperty("CksumTcpUdp", &enumValue<AbstractProtocol::CksumTcpUdp>)
.endNamespace();
After this registration, you can now reference the enums in Lua code as global variables.
local protocolId = Protocol.ProtocolIdIp
That’s it. Hope this has been helpful.
Leave a Comment