// https://github.com/vinniefalco/LuaBridge // Copyright 2019, Dmitry Tarakanov // Copyright 2012, Vinnie Falco // Copyright 2007, Nathan Reed // SPDX-License-Identifier: MIT #pragma once #include #include #include #ifdef LUABRIDGE_CXX17 #include #endif namespace luabridge { /// Lua stack traits for C++ types. /// /// @tparam T A C++ type. /// template struct Stack; template<> struct Stack { static void push(lua_State*) {} }; //------------------------------------------------------------------------------ /** Receive the lua_State* as an argument. */ template<> struct Stack { static lua_State* get(lua_State* L, int) { return L; } }; //------------------------------------------------------------------------------ /** Stack specialization for a lua_CFunction. */ template<> struct Stack { static void push(lua_State* L, lua_CFunction f) { lua_pushcfunction(L, f); } static lua_CFunction get(lua_State* L, int index) { return lua_tocfunction(L, index); } static bool isInstance(lua_State* L, int index) { return lua_iscfunction(L, index); } }; //------------------------------------------------------------------------------ /** Stack specialization for `int`. */ template<> struct Stack { static void push(lua_State* L, int value) { lua_pushinteger(L, static_cast(value)); } static int get(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static bool isInstance(lua_State* L, int index) { if (lua_type(L, index) != LUA_TNUMBER) { return false; } #if LUA_VERSION_NUM <= 501 return true; #else int isNumber; lua_tointegerx(L, index, &isNumber); return isNumber; #endif } }; //------------------------------------------------------------------------------ /** Stack specialization for `unsigned int`. */ template<> struct Stack { static void push(lua_State* L, unsigned int value) { lua_pushinteger(L, static_cast(value)); } static unsigned int get(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; //------------------------------------------------------------------------------ /** Stack specialization for `unsigned char`. */ template<> struct Stack { static void push(lua_State* L, unsigned char value) { lua_pushinteger(L, static_cast(value)); } static unsigned char get(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; //------------------------------------------------------------------------------ /** Stack specialization for `short`. */ template<> struct Stack { static void push(lua_State* L, short value) { lua_pushinteger(L, static_cast(value)); } static short get(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; //------------------------------------------------------------------------------ /** Stack specialization for `unsigned short`. */ template<> struct Stack { static void push(lua_State* L, unsigned short value) { lua_pushinteger(L, static_cast(value)); } static unsigned short get(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; //------------------------------------------------------------------------------ /** Stack specialization for `long`. */ template<> struct Stack { static void push(lua_State* L, long value) { lua_pushinteger(L, static_cast(value)); } static long get(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; //------------------------------------------------------------------------------ /** Stack specialization for `unsigned long`. */ template<> struct Stack { static void push(lua_State* L, unsigned long value) { lua_pushinteger(L, static_cast(value)); } static unsigned long get(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; //------------------------------------------------------------------------------ /** * Stack specialization for `long long`. */ template<> struct Stack { static void push(lua_State* L, long long value) { lua_pushinteger(L, static_cast(value)); } static long long get(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; //------------------------------------------------------------------------------ /** * Stack specialization for `unsigned long long`. */ template<> struct Stack { static void push(lua_State* L, unsigned long long value) { lua_pushinteger(L, static_cast(value)); } static unsigned long long get(lua_State* L, int index) { return static_cast(luaL_checkinteger(L, index)); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; //------------------------------------------------------------------------------ /** Stack specialization for `float`. */ template<> struct Stack { static void push(lua_State* L, float value) { lua_pushnumber(L, static_cast(value)); } static float get(lua_State* L, int index) { return static_cast(luaL_checknumber(L, index)); } static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TNUMBER; } }; //------------------------------------------------------------------------------ /** Stack specialization for `double`. */ template<> struct Stack { static void push(lua_State* L, double value) { lua_pushnumber(L, static_cast(value)); } static double get(lua_State* L, int index) { return static_cast(luaL_checknumber(L, index)); } static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TNUMBER; } }; //------------------------------------------------------------------------------ /** Stack specialization for `bool`. */ template<> struct Stack { static void push(lua_State* L, bool value) { lua_pushboolean(L, value ? 1 : 0); } static bool get(lua_State* L, int index) { return lua_toboolean(L, index) ? true : false; } static bool isInstance(lua_State* L, int index) { return lua_isboolean(L, index); } }; //------------------------------------------------------------------------------ /** Stack specialization for `char`. */ template<> struct Stack { static void push(lua_State* L, char value) { lua_pushlstring(L, &value, 1); } static char get(lua_State* L, int index) { return luaL_checkstring(L, index)[0]; } static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TSTRING; } }; //------------------------------------------------------------------------------ /** Stack specialization for `const char*`. */ template<> struct Stack { static void push(lua_State* L, char const* str) { if (str != 0) lua_pushstring(L, str); else lua_pushnil(L); } static char const* get(lua_State* L, int index) { return lua_isnil(L, index) ? 0 : luaL_checkstring(L, index); } static bool isInstance(lua_State* L, int index) { return lua_isnil(L, index) || lua_type(L, index) == LUA_TSTRING; } }; //------------------------------------------------------------------------------ /** Stack specialization for `std::string`. */ template<> struct Stack { static void push(lua_State* L, std::string const& str) { lua_pushlstring(L, str.data(), str.size()); } static std::string get(lua_State* L, int index) { size_t len; if (lua_type(L, index) == LUA_TSTRING) { const char* str = lua_tolstring(L, index, &len); return std::string(str, len); } // Lua reference manual: // If the value is a number, then lua_tolstring also changes the actual value in the stack // to a string. (This change confuses lua_next when lua_tolstring is applied to keys during // a table traversal.) lua_pushvalue(L, index); const char* str = lua_tolstring(L, -1, &len); std::string string(str, len); lua_pop(L, 1); // Pop the temporary string return string; } static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TSTRING; } }; #ifdef LUABRIDGE_CXX17 //------------------------------------------------------------------------------ /** Stack specialization for `std::string`. */ template<> struct Stack { static void push(lua_State* L, std::string_view str) { lua_pushlstring(L, str.data(), str.size()); } static std::string_view get(lua_State* L, int index) { size_t len; if (lua_type(L, index) == LUA_TSTRING) { const char* str = lua_tolstring(L, index, &len); return std::string_view(str, len); } return {}; } static bool isInstance(lua_State* L, int index) { return lua_type(L, index) == LUA_TSTRING; } }; #endif // LUABRIDGE_CXX17 namespace detail { template struct StackOpSelector { typedef T ReturnType; static void push(lua_State* L, T& value) { Stack::push(L, value); } static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; template struct StackOpSelector { typedef T ReturnType; static void push(lua_State* L, const T& value) { Stack::push(L, value); } static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; template struct StackOpSelector { typedef T ReturnType; static void push(lua_State* L, T* value) { Stack::push(L, *value); } static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; template struct StackOpSelector { typedef T ReturnType; static void push(lua_State* L, const T* value) { Stack::push(L, *value); } static ReturnType get(lua_State* L, int index) { return Stack::get(L, index); } static bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } }; } // namespace detail template struct Stack { typedef detail::StackOpSelector::value> Helper; typedef typename Helper::ReturnType ReturnType; static void push(lua_State* L, T& value) { Helper::push(L, value); } static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } }; template struct Stack { typedef detail::StackOpSelector::value> Helper; typedef typename Helper::ReturnType ReturnType; static void push(lua_State* L, const T& value) { Helper::push(L, value); } static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } }; template struct Stack { typedef detail::StackOpSelector::value> Helper; typedef typename Helper::ReturnType ReturnType; static void push(lua_State* L, T* value) { Helper::push(L, value); } static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } }; template struct Stack { typedef detail::StackOpSelector::value> Helper; typedef typename Helper::ReturnType ReturnType; static void push(lua_State* L, const T* value) { Helper::push(L, value); } static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); } }; //------------------------------------------------------------------------------ /** * Push an object onto the Lua stack. */ template void push(lua_State* L, T t) { Stack::push(L, t); } //------------------------------------------------------------------------------ /** * Get an object from the Lua stack. */ template T get(lua_State* L, int index) { return Stack::get(L, index); } //------------------------------------------------------------------------------ /** * Check whether an object on the Lua stack is of type T. */ template bool isInstance(lua_State* L, int index) { return Stack::isInstance(L, index); } } // namespace luabridge