Skip to content

Commit

Permalink
拆分binding.h
Browse files Browse the repository at this point in the history
  • Loading branch information
actboy168 committed Dec 9, 2023
1 parent f598377 commit 09ab3cf
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 237 deletions.
238 changes: 238 additions & 0 deletions bee/lua/binding.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
#pragma once

#include <bee/error.h>
#include <bee/nonstd/bit.h>
#include <bee/nonstd/to_underlying.h>
#include <bee/nonstd/unreachable.h>
#include <bee/utility/zstring_view.h>

#include <cstdint>
#include <limits>
#include <lua.hpp>
#include <string>
#if defined(_WIN32)
# include <bee/platform/win/unicode.h>
#endif

namespace bee::lua {
#if defined(_WIN32)
using string_type = std::wstring;
#else
using string_type = std::string;
#endif

inline zstring_view checkstrview(lua_State* L, int idx) {
size_t len = 0;
const char* buf = luaL_checklstring(L, idx, &len);
return { buf, len };
}

inline string_type checkstring(lua_State* L, int idx) {
auto str = checkstrview(L, idx);
#if defined(_WIN32)
return win::u2w(str);
#else
return string_type { str.data(), str.size() };
#endif
}

template <typename T, typename I>
constexpr bool checklimit(I i) {
static_assert(std::is_integral_v<I>);
static_assert(std::is_integral_v<T>);
static_assert(sizeof(I) >= sizeof(T));
if constexpr (sizeof(I) == sizeof(T)) {
return true;
}
else if constexpr (std::numeric_limits<I>::is_signed == std::numeric_limits<T>::is_signed) {
return i >= std::numeric_limits<T>::lowest() && i <= (std::numeric_limits<T>::max)();
}
else if constexpr (std::numeric_limits<I>::is_signed) {
return static_cast<std::make_unsigned_t<I>>(i) >= std::numeric_limits<T>::lowest() && static_cast<std::make_unsigned_t<I>>(i) <= (std::numeric_limits<T>::max)();
}
else {
return static_cast<std::make_signed_t<I>>(i) >= std::numeric_limits<T>::lowest() && static_cast<std::make_signed_t<I>>(i) <= (std::numeric_limits<T>::max)();
}
}

template <typename T>
T checkinteger(lua_State* L, int arg) {
static_assert(std::is_trivial_v<T>);
if constexpr (std::is_enum_v<T>) {
using UT = std::underlying_type_t<T>;
return static_cast<T>(checkinteger<UT>(L, arg));
}
else if constexpr (std::is_integral_v<T>) {
lua_Integer r = luaL_checkinteger(L, arg);
if constexpr (std::is_same_v<T, lua_Integer>) {
return r;
}
else if constexpr (sizeof(T) >= sizeof(lua_Integer)) {
return static_cast<T>(r);
}
else {
if (checklimit<T>(r)) {
return static_cast<T>(r);
}
luaL_error(L, "bad argument '#%d' limit exceeded", arg);
std::unreachable();
}
}
else {
return std::bit_cast<T>(checkinteger<lua_Integer>(L, arg));
}
}
template <typename T, T def>
T optinteger(lua_State* L, int arg) {
static_assert(std::is_trivial_v<T>);
if constexpr (std::is_enum_v<T>) {
using UT = std::underlying_type_t<T>;
return static_cast<T>(optinteger<UT, std::to_underlying(def)>(L, arg));
}
else if constexpr (std::is_integral_v<T>) {
if constexpr (std::is_same_v<T, lua_Integer>) {
return luaL_optinteger(L, arg, def);
}
else if constexpr (sizeof(T) == sizeof(lua_Integer)) {
lua_Integer r = optinteger<lua_Integer, static_cast<lua_Integer>(def)>(L, arg);
return static_cast<T>(r);
}
else if constexpr (sizeof(T) < sizeof(lua_Integer)) {
lua_Integer r = optinteger<lua_Integer, static_cast<lua_Integer>(def)>(L, arg);
if (checklimit<T>(r)) {
return static_cast<T>(r);
}
luaL_error(L, "bad argument '#%d' limit exceeded", arg);
std::unreachable();
}
else {
static_assert(checklimit<lua_Integer>(def));
lua_Integer r = optinteger<lua_Integer, static_cast<lua_Integer>(def)>(L, arg);
return static_cast<T>(r);
}
}
else {
// If std::bit_cast were not constexpr, it would fail here, so let it fail.
return std::bit_cast<T>(optinteger<lua_Integer, std::bit_cast<lua_Integer>(def)>(L, arg));
}
}

template <typename T>
T tolightud(lua_State* L, int arg) {
if constexpr (std::is_integral_v<T>) {
uintptr_t r = std::bit_cast<uintptr_t>(tolightud<void*>(L, arg));
if constexpr (std::is_same_v<T, uintptr_t>) {
return r;
}
else if constexpr (sizeof(T) >= sizeof(uintptr_t)) {
return static_cast<T>(r);
}
else {
if (checklimit<T>(r)) {
return static_cast<T>(r);
}
luaL_error(L, "bad argument #%d limit exceeded", arg);
std::unreachable();
}
}
else if constexpr (std::is_same_v<T, void*>) {
return lua_touserdata(L, arg);
}
else if constexpr (std::is_pointer_v<T>) {
return static_cast<T>(tolightud<void*>(L, arg));
}
else {
return std::bit_cast<T>(tolightud<void*>(L, arg));
}
}

template <typename T>
T checklightud(lua_State* L, int arg) {
luaL_checktype(L, arg, LUA_TLIGHTUSERDATA);
return tolightud<T>(L, arg);
}

template <typename T>
T& toudata(lua_State* L, int arg) {
return *tolightud<T*>(L, arg);
}

template <typename T>
struct udata {};
template <typename T, typename = void>
struct udata_has_name : std::false_type {};
template <typename T>
struct udata_has_name<T, std::void_t<decltype(udata<T>::name)>> : std::true_type {};
template <typename T, typename = void>
struct udata_has_nupvalue : std::false_type {};
template <typename T>
struct udata_has_nupvalue<T, std::void_t<decltype(udata<T>::nupvalue)>> : std::true_type {};

template <typename T>
int destroyudata(lua_State* L) {
toudata<T>(L, 1).~T();
return 0;
}

namespace cxx {
struct status {
int n;
bool err;
status(int n) noexcept
: n(n)
, err(false) {}
status() noexcept
: n(0)
, err(true) {}
explicit operator bool() const noexcept {
return !err;
}
};
static inline status error = {};
using func = status (*)(lua_State* L);
template <func f>
static int cfunc(lua_State* L) {
status s = f(L);
if (!s.err) {
return s.n;
}
return lua_error(L);
}
}

template <typename T>
void getmetatable(lua_State* L) {
if (luaL_newmetatable(L, udata<T>::name)) {
if constexpr (!std::is_trivially_destructible<T>::value) {
lua_pushcfunction(L, destroyudata<T>);
lua_setfield(L, -2, "__gc");
}
udata<T>::metatable(L);
}
}

template <typename T, typename... Args>
T& newudata(lua_State* L, Args&&... args) {
static_assert(udata_has_name<T>::value);
int nupvalue = 0;
if constexpr (udata_has_nupvalue<T>::value) {
nupvalue = udata<T>::nupvalue;
}
T* o = static_cast<T*>(lua_newuserdatauv(L, sizeof(T), nupvalue));
new (o) T(std::forward<Args>(args)...);
getmetatable<T>(L);
lua_setmetatable(L, -2);
return *o;
}

template <typename T>
T& checkudata(lua_State* L, int arg) {
if constexpr (udata_has_name<T>::value) {
return *static_cast<T*>(luaL_checkudata(L, arg, udata<T>::name));
}
else {
luaL_checktype(L, arg, LUA_TUSERDATA);
return toudata<T>(L, arg);
}
}
}
Loading

0 comments on commit 09ab3cf

Please sign in to comment.