mirror of
https://gitlab.com/niansa/SomeBot.git
synced 2025-03-06 20:48:26 +01:00
1471 lines
41 KiB
C++
1471 lines
41 KiB
C++
// https://github.com/kunitoki/LuaBridge3
|
|
// Copyright 2020, Lucio Asnaghi
|
|
// Copyright 2019, Dmitry Tarakanov
|
|
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
|
// Copyright 2007, Nathan Reed
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#pragma once
|
|
|
|
#include "LuaHelpers.h"
|
|
#include "Errors.h"
|
|
#include "Expected.h"
|
|
#include "Result.h"
|
|
#include "Userdata.h"
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <limits>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <system_error>
|
|
#include <type_traits>
|
|
#include <tuple>
|
|
#include <utility>
|
|
|
|
namespace luabridge {
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack restorer.
|
|
*/
|
|
class StackRestore final
|
|
{
|
|
public:
|
|
StackRestore(lua_State* L)
|
|
: m_L(L)
|
|
, m_stackTop(lua_gettop(L))
|
|
{
|
|
}
|
|
|
|
~StackRestore()
|
|
{
|
|
if (m_doRestoreStack)
|
|
lua_settop(m_L, m_stackTop);
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
m_doRestoreStack = false;
|
|
}
|
|
|
|
private:
|
|
lua_State* const m_L = nullptr;
|
|
int m_stackTop = 0;
|
|
bool m_doRestoreStack = true;
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Lua stack traits for C++ types.
|
|
*
|
|
* @tparam T A C++ type.
|
|
*/
|
|
template <class T, class>
|
|
struct Stack;
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Specialization for void type.
|
|
*/
|
|
template <>
|
|
struct Stack<void>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State*)
|
|
{
|
|
return {};
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Specialization for nullptr_t.
|
|
*/
|
|
template <>
|
|
struct Stack<std::nullptr_t>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, std::nullptr_t)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
lua_pushnil(L);
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<std::nullptr_t> get(lua_State* L, int index)
|
|
{
|
|
if (! lua_isnil(L, index))
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
return lua_isnil(L, index);
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Receive the lua_State* as an argument.
|
|
*/
|
|
template <>
|
|
struct Stack<lua_State*>
|
|
{
|
|
[[nodiscard]] static TypeResult<lua_State*> get(lua_State* L, int)
|
|
{
|
|
return L;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for a lua_CFunction.
|
|
*/
|
|
template <>
|
|
struct Stack<lua_CFunction>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, lua_CFunction f)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
lua_pushcfunction_x(L, f);
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<lua_CFunction> get(lua_State* L, int index)
|
|
{
|
|
if (! lua_iscfunction(L, index))
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
return lua_tocfunction(L, index);
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
return lua_iscfunction(L, index);
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `bool`.
|
|
*/
|
|
template <>
|
|
struct Stack<bool>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, bool value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
lua_pushboolean(L, value ? 1 : 0);
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<bool> get(lua_State* L, int index)
|
|
{
|
|
return lua_toboolean(L, index) ? true : false;
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
return lua_isboolean(L, index);
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `std::byte`.
|
|
*/
|
|
template <>
|
|
struct Stack<std::byte>
|
|
{
|
|
static_assert(sizeof(std::byte) < sizeof(lua_Integer));
|
|
|
|
[[nodiscard]] static Result push(lua_State* L, std::byte value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
pushunsigned(L, std::to_integer<std::make_unsigned_t<lua_Integer>>(value));
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<std::byte> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<unsigned char>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<std::byte>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<unsigned char>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `char`.
|
|
*/
|
|
template <>
|
|
struct Stack<char>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, char value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
lua_pushlstring(L, &value, 1);
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<char> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TSTRING)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
std::size_t length = 0;
|
|
const char* str = lua_tolstring(L, index, &length);
|
|
|
|
if (str == nullptr || length != 1)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
return str[0];
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TSTRING)
|
|
{
|
|
std::size_t len;
|
|
luaL_checklstring(L, index, &len);
|
|
return len == 1;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `int8_t`.
|
|
*/
|
|
template <>
|
|
struct Stack<int8_t>
|
|
{
|
|
static_assert(sizeof(int8_t) < sizeof(lua_Integer));
|
|
|
|
[[nodiscard]] static Result push(lua_State* L, int8_t value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
lua_pushinteger(L, static_cast<lua_Integer>(value));
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<int8_t> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<int8_t>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<int8_t>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<int8_t>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `unsigned char`.
|
|
*/
|
|
template <>
|
|
struct Stack<unsigned char>
|
|
{
|
|
static_assert(sizeof(unsigned char) < sizeof(lua_Integer));
|
|
|
|
[[nodiscard]] static Result push(lua_State* L, unsigned char value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
pushunsigned(L, value);
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<unsigned char> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<unsigned char>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<unsigned char>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<unsigned char>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `short`.
|
|
*/
|
|
template <>
|
|
struct Stack<short>
|
|
{
|
|
static_assert(sizeof(short) < sizeof(lua_Integer));
|
|
|
|
[[nodiscard]] static Result push(lua_State* L, short value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
lua_pushinteger(L, static_cast<lua_Integer>(value));
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<short> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<short>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<short>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<short>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `unsigned short`.
|
|
*/
|
|
template <>
|
|
struct Stack<unsigned short>
|
|
{
|
|
static_assert(sizeof(unsigned short) < sizeof(lua_Integer));
|
|
|
|
[[nodiscard]] static Result push(lua_State* L, unsigned short value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
pushunsigned(L, value);
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<unsigned short> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<unsigned short>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<unsigned short>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<unsigned short>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `int`.
|
|
*/
|
|
template <>
|
|
struct Stack<int>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, int value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (! is_integral_representable_by(value))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
lua_pushinteger(L, static_cast<lua_Integer>(value));
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<int> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<int>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<int>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<int>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `unsigned int`.
|
|
*/
|
|
template <>
|
|
struct Stack<unsigned int>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, unsigned int value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (! is_integral_representable_by(value))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
pushunsigned(L, value);
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<unsigned int> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<unsigned int>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<unsigned int>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<unsigned int>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `long`.
|
|
*/
|
|
template <>
|
|
struct Stack<long>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, long value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (! is_integral_representable_by(value))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
lua_pushinteger(L, static_cast<lua_Integer>(value));
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<long> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<long>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<long>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<long>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `unsigned long`.
|
|
*/
|
|
template <>
|
|
struct Stack<unsigned long>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, unsigned long value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (! is_integral_representable_by(value))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
pushunsigned(L, value);
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<unsigned long> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<unsigned long>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<unsigned long>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<unsigned long>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `long long`.
|
|
*/
|
|
template <>
|
|
struct Stack<long long>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, long long value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (! is_integral_representable_by(value))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
lua_pushinteger(L, static_cast<lua_Integer>(value));
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<long long> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<long long>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<long long>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<long long>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `unsigned long long`.
|
|
*/
|
|
template <>
|
|
struct Stack<unsigned long long>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, unsigned long long value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (! is_integral_representable_by(value))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
pushunsigned(L, value);
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<unsigned long long> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<unsigned long long>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<unsigned long long>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<unsigned long long>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
#if 0 // defined(__SIZEOF_INT128__)
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `__int128_t`.
|
|
*/
|
|
template <>
|
|
struct Stack<__int128_t>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, __int128_t value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (! is_integral_representable_by(value))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
lua_pushinteger(L, static_cast<lua_Integer>(value));
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<__int128_t> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<__int128_t>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<__int128_t>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<__int128_t>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `__uint128_t`.
|
|
*/
|
|
template <>
|
|
struct Stack<__uint128_t>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, __uint128_t value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (! is_integral_representable_by(value))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
lua_pushinteger(L, static_cast<lua_Integer>(value));
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<__uint128_t> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_integral_representable_by<__uint128_t>(L, index))
|
|
return makeErrorCode(ErrorCode::IntegerDoesntFitIntoLuaInteger);
|
|
|
|
return static_cast<__uint128_t>(lua_tointeger(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_integral_representable_by<__uint128_t>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
#endif
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `float`.
|
|
*/
|
|
template <>
|
|
struct Stack<float>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, float value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (! is_floating_point_representable_by(value))
|
|
return makeErrorCode(ErrorCode::FloatingPointDoesntFitIntoLuaNumber);
|
|
|
|
lua_pushnumber(L, static_cast<lua_Number>(value));
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<float> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_floating_point_representable_by<float>(L, index))
|
|
return makeErrorCode(ErrorCode::FloatingPointDoesntFitIntoLuaNumber);
|
|
|
|
return static_cast<float>(lua_tonumber(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_floating_point_representable_by<float>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `double`.
|
|
*/
|
|
template <>
|
|
struct Stack<double>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, double value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (! is_floating_point_representable_by(value))
|
|
return makeErrorCode(ErrorCode::FloatingPointDoesntFitIntoLuaNumber);
|
|
|
|
lua_pushnumber(L, static_cast<lua_Number>(value));
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<double> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_floating_point_representable_by<double>(L, index))
|
|
return makeErrorCode(ErrorCode::FloatingPointDoesntFitIntoLuaNumber);
|
|
|
|
return static_cast<double>(lua_tonumber(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_floating_point_representable_by<double>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `long double`.
|
|
*/
|
|
template <>
|
|
struct Stack<long double>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, long double value)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (! is_floating_point_representable_by(value))
|
|
return makeErrorCode(ErrorCode::FloatingPointDoesntFitIntoLuaNumber);
|
|
|
|
lua_pushnumber(L, static_cast<lua_Number>(value));
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<long double> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TNUMBER)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (! is_floating_point_representable_by<long double>(L, index))
|
|
return makeErrorCode(ErrorCode::FloatingPointDoesntFitIntoLuaNumber);
|
|
|
|
return static_cast<long double>(lua_tonumber(L, index));
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNUMBER)
|
|
return is_floating_point_representable_by<long double>(L, index);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `const char*`.
|
|
*/
|
|
template <>
|
|
struct Stack<const char*>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, const char* str)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
if (str != nullptr)
|
|
lua_pushstring(L, str);
|
|
else
|
|
lua_pushlstring(L, "", 0);
|
|
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<const char*> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TSTRING)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
std::size_t length = 0;
|
|
const char* str = lua_tolstring(L, index, &length);
|
|
if (str == nullptr)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
return str;
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
return lua_type(L, index) == LUA_TSTRING;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `std::string_view`.
|
|
*/
|
|
template <>
|
|
struct Stack<std::string_view>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, std::string_view str)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
lua_pushlstring(L, str.data(), str.size());
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<std::string_view> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) != LUA_TSTRING)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
std::size_t length = 0;
|
|
const char* str = lua_tolstring(L, index, &length);
|
|
if (str == nullptr)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
return std::string_view{ str, length };
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
return lua_type(L, index) == LUA_TSTRING;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `std::string`.
|
|
*/
|
|
template <>
|
|
struct Stack<std::string>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, const std::string& str)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
lua_pushlstring(L, str.data(), str.size());
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<std::string> get(lua_State* L, int index)
|
|
{
|
|
std::size_t length = 0;
|
|
const char* str = nullptr;
|
|
|
|
if (lua_type(L, index) == LUA_TSTRING)
|
|
{
|
|
str = lua_tolstring(L, index, &length);
|
|
}
|
|
else
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
// 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);
|
|
str = lua_tolstring(L, -1, &length);
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
if (str == nullptr)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
return std::string{ str, length };
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
return lua_type(L, index) == LUA_TSTRING;
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `std::optional`.
|
|
*/
|
|
template <class T>
|
|
struct Stack<std::optional<T>>
|
|
{
|
|
using Type = std::optional<T>;
|
|
|
|
[[nodiscard]] static Result push(lua_State* L, const Type& value)
|
|
{
|
|
if (value)
|
|
{
|
|
StackRestore stackRestore(L);
|
|
|
|
auto result = Stack<T>::push(L, *value);
|
|
if (! result)
|
|
return result;
|
|
|
|
stackRestore.reset();
|
|
return {};
|
|
}
|
|
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
lua_pushnil(L);
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<Type> get(lua_State* L, int index)
|
|
{
|
|
if (lua_type(L, index) == LUA_TNIL)
|
|
return std::nullopt;
|
|
|
|
auto result = Stack<T>::get(L, index);
|
|
if (! result)
|
|
return result.error();
|
|
|
|
return *result;
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
return lua_isnil(L, index) || Stack<T>::isInstance(L, index);
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `std::pair`.
|
|
*/
|
|
template <class T1, class T2>
|
|
struct Stack<std::pair<T1, T2>>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, const std::pair<T1, T2>& t)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 3))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
StackRestore stackRestore(L);
|
|
|
|
lua_createtable(L, 2, 0);
|
|
|
|
auto result1 = push_element<0>(L, t);
|
|
if (! result1)
|
|
return result1;
|
|
|
|
auto result2 = push_element<1>(L, t);
|
|
if (! result2)
|
|
return result2;
|
|
|
|
stackRestore.reset();
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<std::pair<T1, T2>> get(lua_State* L, int index)
|
|
{
|
|
const StackRestore stackRestore(L);
|
|
|
|
if (!lua_istable(L, index))
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (get_length(L, index) != 2)
|
|
return makeErrorCode(ErrorCode::InvalidTableSizeInCast);
|
|
|
|
std::pair<T1, T2> value;
|
|
|
|
int absIndex = lua_absindex(L, index);
|
|
lua_pushnil(L);
|
|
|
|
auto result1 = pop_element<0>(L, absIndex, value);
|
|
if (! result1)
|
|
return result1.error();
|
|
|
|
auto result2 = pop_element<1>(L, absIndex, value);
|
|
if (! result2)
|
|
return result2.error();
|
|
|
|
return value;
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
return lua_type(L, index) == LUA_TTABLE && get_length(L, index) == 2;
|
|
}
|
|
|
|
private:
|
|
template <std::size_t Index>
|
|
static Result push_element(lua_State* L, const std::pair<T1, T2>& p)
|
|
{
|
|
static_assert(Index < 2);
|
|
|
|
using T = std::tuple_element_t<Index, std::pair<T1, T2>>;
|
|
|
|
lua_pushinteger(L, static_cast<lua_Integer>(Index + 1));
|
|
|
|
auto result = Stack<T>::push(L, std::get<Index>(p));
|
|
if (! result)
|
|
{
|
|
lua_pushnil(L);
|
|
lua_settable(L, -3);
|
|
return result;
|
|
}
|
|
|
|
lua_settable(L, -3);
|
|
|
|
return {};
|
|
}
|
|
|
|
template <std::size_t Index>
|
|
static Result pop_element(lua_State* L, int absIndex, std::pair<T1, T2>& p)
|
|
{
|
|
static_assert(Index < 2);
|
|
|
|
using T = std::tuple_element_t<Index, std::pair<T1, T2>>;
|
|
|
|
if (lua_next(L, absIndex) == 0)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
auto result = Stack<T>::get(L, -1);
|
|
if (! result)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
std::get<Index>(p) = std::move(*result);
|
|
lua_pop(L, 1);
|
|
|
|
return {};
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `std::tuple`.
|
|
*/
|
|
template <class... Types>
|
|
struct Stack<std::tuple<Types...>>
|
|
{
|
|
[[nodiscard]] static Result push(lua_State* L, const std::tuple<Types...>& t)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 3))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
StackRestore stackRestore(L);
|
|
|
|
lua_createtable(L, static_cast<int>(Size), 0);
|
|
|
|
auto result = push_element(L, t);
|
|
if (! result)
|
|
return result;
|
|
|
|
stackRestore.reset();
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static TypeResult<std::tuple<Types...>> get(lua_State* L, int index)
|
|
{
|
|
const StackRestore stackRestore(L);
|
|
|
|
if (!lua_istable(L, index))
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
if (get_length(L, index) != static_cast<int>(Size))
|
|
return makeErrorCode(ErrorCode::InvalidTableSizeInCast);
|
|
|
|
std::tuple<Types...> value;
|
|
|
|
int absIndex = lua_absindex(L, index);
|
|
lua_pushnil(L);
|
|
|
|
auto result = pop_element(L, absIndex, value);
|
|
if (! result)
|
|
return result.error();
|
|
|
|
return value;
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
return lua_type(L, index) == LUA_TTABLE && get_length(L, index) == static_cast<int>(Size);
|
|
}
|
|
|
|
private:
|
|
static constexpr std::size_t Size = std::tuple_size_v<std::tuple<Types...>>;
|
|
|
|
template <std::size_t Index = 0>
|
|
static auto push_element(lua_State*, const std::tuple<Types...>&)
|
|
-> std::enable_if_t<Index == sizeof...(Types), Result>
|
|
{
|
|
return {};
|
|
}
|
|
|
|
template <std::size_t Index = 0>
|
|
static auto push_element(lua_State* L, const std::tuple<Types...>& t)
|
|
-> std::enable_if_t<Index < sizeof...(Types), Result>
|
|
{
|
|
using T = std::tuple_element_t<Index, std::tuple<Types...>>;
|
|
|
|
lua_pushinteger(L, static_cast<lua_Integer>(Index + 1));
|
|
|
|
auto result = Stack<T>::push(L, std::get<Index>(t));
|
|
if (! result)
|
|
{
|
|
lua_pushnil(L);
|
|
lua_settable(L, -3);
|
|
return result;
|
|
}
|
|
|
|
lua_settable(L, -3);
|
|
|
|
return push_element<Index + 1>(L, t);
|
|
}
|
|
|
|
template <std::size_t Index = 0>
|
|
static auto pop_element(lua_State*, int, std::tuple<Types...>&)
|
|
-> std::enable_if_t<Index == sizeof...(Types), Result>
|
|
{
|
|
return {};
|
|
}
|
|
|
|
template <std::size_t Index = 0>
|
|
static auto pop_element(lua_State* L, int absIndex, std::tuple<Types...>& t)
|
|
-> std::enable_if_t<Index < sizeof...(Types), Result>
|
|
{
|
|
using T = std::tuple_element_t<Index, std::tuple<Types...>>;
|
|
|
|
if (lua_next(L, absIndex) == 0)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
auto result = Stack<T>::get(L, -1);
|
|
if (! result)
|
|
return makeErrorCode(ErrorCode::InvalidTypeCast);
|
|
|
|
std::get<Index>(t) = std::move(*result);
|
|
lua_pop(L, 1);
|
|
|
|
return pop_element<Index + 1>(L, absIndex, t);
|
|
}
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Stack specialization for `T[N]`.
|
|
*/
|
|
template <class T, std::size_t N>
|
|
struct Stack<T[N]>
|
|
{
|
|
static_assert(N > 0, "Unsupported zero sized array");
|
|
|
|
[[nodiscard]] static Result push(lua_State* L, const T (&value)[N])
|
|
{
|
|
if constexpr (std::is_same_v<T, char>)
|
|
{
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 1))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
lua_pushlstring(L, value, N - 1);
|
|
return {};
|
|
}
|
|
|
|
#if LUABRIDGE_SAFE_STACK_CHECKS
|
|
if (! lua_checkstack(L, 2))
|
|
return makeErrorCode(ErrorCode::LuaStackOverflow);
|
|
#endif
|
|
|
|
StackRestore stackRestore(L);
|
|
|
|
lua_createtable(L, static_cast<int>(N), 0);
|
|
|
|
for (std::size_t i = 0; i < N; ++i)
|
|
{
|
|
lua_pushinteger(L, static_cast<lua_Integer>(i + 1));
|
|
|
|
auto result = Stack<T>::push(L, value[i]);
|
|
if (! result)
|
|
return result;
|
|
|
|
lua_settable(L, -3);
|
|
}
|
|
|
|
stackRestore.reset();
|
|
return {};
|
|
}
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index)
|
|
{
|
|
return lua_type(L, index) == LUA_TTABLE && get_length(L, index) == static_cast<int>(N);
|
|
}
|
|
};
|
|
|
|
namespace detail {
|
|
|
|
template <class T>
|
|
struct StackOpSelector<T&, false>
|
|
{
|
|
using ReturnType = TypeResult<T>;
|
|
|
|
static Result push(lua_State* L, T& value) { return 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>
|
|
{
|
|
using ReturnType = TypeResult<T>;
|
|
|
|
static Result push(lua_State* L, const T& value) { return 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>
|
|
{
|
|
using ReturnType = TypeResult<T>;
|
|
|
|
static Result push(lua_State* L, T* value) { return 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>
|
|
{
|
|
using ReturnType = TypeResult<T>;
|
|
|
|
static Result push(lua_State* L, const T* value) { return 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&, std::enable_if_t<!std::is_array_v<T&>>>
|
|
{
|
|
using Helper = detail::StackOpSelector<T&, detail::IsUserdata<T>::value>;
|
|
using ReturnType = typename Helper::ReturnType;
|
|
|
|
[[nodiscard]] static Result push(lua_State* L, T& value) { return Helper::push(L, value); }
|
|
|
|
[[nodiscard]] static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index) { return Helper::template isInstance<T>(L, index); }
|
|
};
|
|
|
|
template <class T>
|
|
struct Stack<const T&, std::enable_if_t<!std::is_array_v<const T&>>>
|
|
{
|
|
using Helper = detail::StackOpSelector<const T&, detail::IsUserdata<T>::value>;
|
|
using ReturnType = typename Helper::ReturnType;
|
|
|
|
[[nodiscard]] static Result push(lua_State* L, const T& value) { return Helper::push(L, value); }
|
|
|
|
[[nodiscard]] static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index) { return Helper::template isInstance<T>(L, index); }
|
|
};
|
|
|
|
template <class T>
|
|
struct Stack<T*>
|
|
{
|
|
using Helper = detail::StackOpSelector<T*, detail::IsUserdata<T>::value>;
|
|
using ReturnType = typename Helper::ReturnType;
|
|
|
|
[[nodiscard]] static Result push(lua_State* L, T* value) { return Helper::push(L, value); }
|
|
|
|
[[nodiscard]] static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index) { return Helper::template isInstance<T>(L, index); }
|
|
};
|
|
|
|
template<class T>
|
|
struct Stack<const T*>
|
|
{
|
|
using Helper = detail::StackOpSelector<const T*, detail::IsUserdata<T>::value>;
|
|
using ReturnType = typename Helper::ReturnType;
|
|
|
|
[[nodiscard]] static Result push(lua_State* L, const T* value) { return Helper::push(L, value); }
|
|
|
|
[[nodiscard]] static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
|
|
|
|
[[nodiscard]] static bool isInstance(lua_State* L, int index) { return Helper::template isInstance<T>(L, index); }
|
|
};
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Push an object onto the Lua stack.
|
|
*/
|
|
template <class T>
|
|
[[nodiscard]] Result push(lua_State* L, const T& t)
|
|
{
|
|
return Stack<T>::push(L, t);
|
|
}
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Get an object from the Lua stack.
|
|
*/
|
|
template <class T>
|
|
[[nodiscard]] TypeResult<T> get(lua_State* L, int index)
|
|
{
|
|
return Stack<T>::get(L, index);
|
|
}
|
|
|
|
//=================================================================================================
|
|
/**
|
|
* @brief Check whether an object on the Lua stack is of type T.
|
|
*/
|
|
template <class T>
|
|
[[nodiscard]] bool isInstance(lua_State* L, int index)
|
|
{
|
|
return Stack<T>::isInstance(L, index);
|
|
}
|
|
|
|
} // namespace luabridge
|