536 lines
14 KiB
C++
536 lines
14 KiB
C++
// 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
|