Binding Lua to C using Templates Lux Cardell
Binding Lua to C++ using Templates Lux Cardell
The Basics of Lua Loosely typed scripting language Designed to be lightweight, fast, and embeddable Compound objects structured as hash tables Object orientation implemented through metatables
The Interface The Lua C API allows function binding through a specific function signature: int Binding. Function(lua_State * L); The lua_State struct is the environment object used by the Lua interpreter, and the int return value denotes the number of values pushed as results onto the Lua stack.
A Basic Binding Function a = 10 b = 5 Bound. Funcs. add(a, b) int add(int a, int b); int foo(lua_State * L) { int result = add(lua_tointeger(L, 1), lua_tointeger(L, 2)); lua_pushinteger(L, result); return 1; }
Declaration of the Binder Template template<typename Return, typename. . . Args> struct Binder { template<Return(Func)(Args. . . )> static int Static. Binding(lua_State * L); };
Helper Functions template<typename T> bool Check. Single. Arg(lua_State * L, int i); template<typename Arg, typename. . . Rest> bool Check. Args(lua_State * L, int i = 1); template<typename Arg, typename. . . Rest> std: : tuple<Arg, Rest. . . > Pop. Args(lua_State * L, int i = 1); template<typename Result> void Push. Result(lua_State * L, Result value);
Converting Arguments from Lua to C++ struct Lua. Value { enum Val. Type { vt. Bool, vt. Int, vt. Number, vt. String }; Val. Type type; union Value { int i; float f; bool b; std: : string s; } value; Lua. Value(lua_State * L, int i); template<typename T> T Get. Value(); };
What needs to be done? Check the validity of the arguments Number of arguments Types of arguments Get the arguments from the Lua stack Call the function with the correct arguments Push the return value onto the Lua stack
template<typename Return, typename. . . Args> template<Return(Func)(Args. . . )> int Binder<Return, Args. . . >: : Static. Binding(lua_State * L) { const int stack = lua_gettop(L); if (stack != sizeof. . . (Args)) { std: : cout << “Incorrect argument countn”; return 0; } if constexpr (sizeof. . . (Args) != 0) { if (Check. Args<Args. . . >(L) == false) { std: : cout << “Incorrect argument typen”; return 0; } }
If there are no arguments, just call the function if constexpr (sizeof. . . (Args) == 0) { if constexpr (std: : is_void<Return>: : value == true) { Func(); return 0; } else { Return result = Func(); Push. Result(L, result); return 1; } }
Otherwise, get the arguments from the Lua stack else { std: : tuple<Args. . . > args = Pop. Args<Args. . . >(L); if constexpr (std: : is_void<Return>: : value == true) { std: : apply(Func, args); return 0; } else { Return result = std: : apply(Func, args); Push. Result(L, result); return 1; } } }
Checking the Types Due to the nature of the Lua C API, this function must be individually instantiated for each type being supported. template<> bool Check. Single. Arg<int>(lua_State * L, int i) { return lua_isinteger(L, i); } template<> bool Check. Single. Arg<float>(lua_State * L, int i) { return lua_isnumber(L, i); }
Unpacking the Arguments Since the argument types are stored in a parameter pack, extracting them will take a recursive template: template<typename Arg, typename. . . Rest> bool Check. Args(lua_State * L, int i) { if (!Check. Single. Arg<Arg>(L, i)) return false; if constexpr (sizeof. . . (Rest) == 0) return true; else return Check. Args<Rest. . . >(L, i+1); }
Building a tuple of arguments template<typename Arg, typename. . . Rest> std: : tuple<Arg, Rest. . . > Pop. Args(lua_State * L, int i) { Lua. Value val(L, i); std: : tuple<Arg> a(val. Get. Value<Arg>()); if constexpr (sizeof. . . (Rest) == 0) return a; else return std: : tuple_cat(a, Pop. Args<Rest. . . >(L, i+1)); }
Pushing a Return Value This must also be instantiated for each supported type template<> void Push. Result(lua_State * L, int value) { lua_pushinteger(L, value); } template<> void Push. Result(lua_State * L, float value) { lua_pushnumber(L, value); }
Limitations Only works with explicitly supported data types Not very reference friendly Doesn’t account for nil values, treats it like an argument error rather than a default Doesn’t support Lua’s userdata type Doesn’t support multiple return values or returning arrays
Thank you for listening! All code is available on Git. Hub: https: //github. com/lux-cardell/Lua. Binder Find me on Linked. In: https: //linkedin. com/in/lux-cardell
- Slides: 17