// https://github.com/vinniefalco/LuaBridge
// Copyright 2019, Dmitry Tarakanov
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
// Copyright 2007, Nathan Reed
// SPDX-License-Identifier: MIT
#pragma once
#include <LuaBridge/detail/LuaHelpers.h>
#include <LuaBridge/detail/Userdata.h>
#include <string>
#ifdef LUABRIDGE_CXX17
#include <string_view>
#endif
namespace luabridge {
/// Lua stack traits for C++ types.
///
/// @tparam T A C++ type.
///
template<class T>
struct Stack;
template<>
struct Stack<void>
{
static void push(lua_State*) {}
};
//------------------------------------------------------------------------------
/**
Receive the lua_State* as an argument.
*/
template<>
struct Stack<lua_State*>
{
static lua_State* get(lua_State* L, int) { return L; }
};
//------------------------------------------------------------------------------
/**
Stack specialization for a lua_CFunction.
*/
template<>
struct Stack<lua_CFunction>
{
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<int>
{
static void push(lua_State* L, int value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static int get(lua_State* L, int index)
{
return static_cast<int>(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<unsigned int>
{
static void push(lua_State* L, unsigned int value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned int get(lua_State* L, int index)
{
return static_cast<unsigned int>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `unsigned char`.
*/
template<>
struct Stack<unsigned char>
{
static void push(lua_State* L, unsigned char value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned char get(lua_State* L, int index)
{
return static_cast<unsigned char>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `short`.
*/
template<>
struct Stack<short>
{
static void push(lua_State* L, short value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static short get(lua_State* L, int index)
{
return static_cast<short>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `unsigned short`.
*/
template<>
struct Stack<unsigned short>
{
static void push(lua_State* L, unsigned short value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned short get(lua_State* L, int index)
{
return static_cast<unsigned short>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `long`.
*/
template<>
struct Stack<long>
{
static void push(lua_State* L, long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static long get(lua_State* L, int index)
{
return static_cast<long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `unsigned long`.
*/
template<>
struct Stack<unsigned long>
{
static void push(lua_State* L, unsigned long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned long get(lua_State* L, int index)
{
return static_cast<unsigned long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
* Stack specialization for `long long`.
*/
template<>
struct Stack<long long>
{
static void push(lua_State* L, long long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static long long get(lua_State* L, int index)
{
return static_cast<long long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
* Stack specialization for `unsigned long long`.
*/
template<>
struct Stack<unsigned long long>
{
static void push(lua_State* L, unsigned long long value)
{
lua_pushinteger(L, static_cast<lua_Integer>(value));
}
static unsigned long long get(lua_State* L, int index)
{
return static_cast<unsigned long long>(luaL_checkinteger(L, index));
}
static bool isInstance(lua_State* L, int index) { return Stack<int>::isInstance(L, index); }
};
//------------------------------------------------------------------------------
/**
Stack specialization for `float`.
*/
template<>
struct Stack<float>
{
static void push(lua_State* L, float value)
{
lua_pushnumber(L, static_cast<lua_Number>(value));
}
static float get(lua_State* L, int index)
{
return static_cast<float>(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<double>
{
static void push(lua_State* L, double value)
{
lua_pushnumber(L, static_cast<lua_Number>(value));
}
static double get(lua_State* L, int index)
{
return static_cast<double>(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<bool>
{
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<char>
{
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<char const*>
{
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<std::string>
{
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<std::string_view>
{
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<class T>
struct StackOpSelector<T&, false>
{
typedef T ReturnType;
static void push(lua_State* L, T& value) { Stack<T>::push(L, value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
template<class T>
struct StackOpSelector<const T&, false>
{
typedef T ReturnType;
static void push(lua_State* L, const T& value) { Stack<T>::push(L, value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
template<class T>
struct StackOpSelector<T*, false>
{
typedef T ReturnType;
static void push(lua_State* L, T* value) { Stack<T>::push(L, *value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
template<class T>
struct StackOpSelector<const T*, false>
{
typedef T ReturnType;
static void push(lua_State* L, const T* value) { Stack<T>::push(L, *value); }
static ReturnType get(lua_State* L, int index) { return Stack<T>::get(L, index); }
static bool isInstance(lua_State* L, int index) { return Stack<T>::isInstance(L, index); }
};
} // namespace detail
template<class T>
struct Stack<T&>
{
typedef detail::StackOpSelector<T&, detail::IsUserdata<T>::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<class T>
struct Stack<const T&>
{
typedef detail::StackOpSelector<const T&, detail::IsUserdata<T>::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<class T>
struct Stack<T*>
{
typedef detail::StackOpSelector<T*, detail::IsUserdata<T>::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<class T>
struct Stack<const T*>
{
typedef detail::StackOpSelector<const T*, detail::IsUserdata<T>::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<class T>
void push(lua_State* L, T t)
{
Stack<T>::push(L, t);
}
//------------------------------------------------------------------------------
/**
* Get an object from the Lua stack.
*/
template<class T>
T get(lua_State* L, int index)
{
return Stack<T>::get(L, index);
}
//------------------------------------------------------------------------------
/**
* Check whether an object on the Lua stack is of type T.
*/
template<class T>
bool isInstance(lua_State* L, int index)
{
return Stack<T>::isInstance(L, index);
}
} // namespace luabridge