diff --git a/bee/lua/binding.h b/bee/lua/binding.h new file mode 100644 index 00000000..cb66e3e2 --- /dev/null +++ b/bee/lua/binding.h @@ -0,0 +1,238 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#if defined(_WIN32) +# include +#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 + constexpr bool checklimit(I i) { + static_assert(std::is_integral_v); + static_assert(std::is_integral_v); + static_assert(sizeof(I) >= sizeof(T)); + if constexpr (sizeof(I) == sizeof(T)) { + return true; + } + else if constexpr (std::numeric_limits::is_signed == std::numeric_limits::is_signed) { + return i >= std::numeric_limits::lowest() && i <= (std::numeric_limits::max)(); + } + else if constexpr (std::numeric_limits::is_signed) { + return static_cast>(i) >= std::numeric_limits::lowest() && static_cast>(i) <= (std::numeric_limits::max)(); + } + else { + return static_cast>(i) >= std::numeric_limits::lowest() && static_cast>(i) <= (std::numeric_limits::max)(); + } + } + + template + T checkinteger(lua_State* L, int arg) { + static_assert(std::is_trivial_v); + if constexpr (std::is_enum_v) { + using UT = std::underlying_type_t; + return static_cast(checkinteger(L, arg)); + } + else if constexpr (std::is_integral_v) { + lua_Integer r = luaL_checkinteger(L, arg); + if constexpr (std::is_same_v) { + return r; + } + else if constexpr (sizeof(T) >= sizeof(lua_Integer)) { + return static_cast(r); + } + else { + if (checklimit(r)) { + return static_cast(r); + } + luaL_error(L, "bad argument '#%d' limit exceeded", arg); + std::unreachable(); + } + } + else { + return std::bit_cast(checkinteger(L, arg)); + } + } + template + T optinteger(lua_State* L, int arg) { + static_assert(std::is_trivial_v); + if constexpr (std::is_enum_v) { + using UT = std::underlying_type_t; + return static_cast(optinteger(L, arg)); + } + else if constexpr (std::is_integral_v) { + if constexpr (std::is_same_v) { + return luaL_optinteger(L, arg, def); + } + else if constexpr (sizeof(T) == sizeof(lua_Integer)) { + lua_Integer r = optinteger(def)>(L, arg); + return static_cast(r); + } + else if constexpr (sizeof(T) < sizeof(lua_Integer)) { + lua_Integer r = optinteger(def)>(L, arg); + if (checklimit(r)) { + return static_cast(r); + } + luaL_error(L, "bad argument '#%d' limit exceeded", arg); + std::unreachable(); + } + else { + static_assert(checklimit(def)); + lua_Integer r = optinteger(def)>(L, arg); + return static_cast(r); + } + } + else { + // If std::bit_cast were not constexpr, it would fail here, so let it fail. + return std::bit_cast(optinteger(def)>(L, arg)); + } + } + + template + T tolightud(lua_State* L, int arg) { + if constexpr (std::is_integral_v) { + uintptr_t r = std::bit_cast(tolightud(L, arg)); + if constexpr (std::is_same_v) { + return r; + } + else if constexpr (sizeof(T) >= sizeof(uintptr_t)) { + return static_cast(r); + } + else { + if (checklimit(r)) { + return static_cast(r); + } + luaL_error(L, "bad argument #%d limit exceeded", arg); + std::unreachable(); + } + } + else if constexpr (std::is_same_v) { + return lua_touserdata(L, arg); + } + else if constexpr (std::is_pointer_v) { + return static_cast(tolightud(L, arg)); + } + else { + return std::bit_cast(tolightud(L, arg)); + } + } + + template + T checklightud(lua_State* L, int arg) { + luaL_checktype(L, arg, LUA_TLIGHTUSERDATA); + return tolightud(L, arg); + } + + template + T& toudata(lua_State* L, int arg) { + return *tolightud(L, arg); + } + + template + struct udata {}; + template + struct udata_has_name : std::false_type {}; + template + struct udata_has_name::name)>> : std::true_type {}; + template + struct udata_has_nupvalue : std::false_type {}; + template + struct udata_has_nupvalue::nupvalue)>> : std::true_type {}; + + template + int destroyudata(lua_State* L) { + toudata(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 + static int cfunc(lua_State* L) { + status s = f(L); + if (!s.err) { + return s.n; + } + return lua_error(L); + } + } + + template + void getmetatable(lua_State* L) { + if (luaL_newmetatable(L, udata::name)) { + if constexpr (!std::is_trivially_destructible::value) { + lua_pushcfunction(L, destroyudata); + lua_setfield(L, -2, "__gc"); + } + udata::metatable(L); + } + } + + template + T& newudata(lua_State* L, Args&&... args) { + static_assert(udata_has_name::value); + int nupvalue = 0; + if constexpr (udata_has_nupvalue::value) { + nupvalue = udata::nupvalue; + } + T* o = static_cast(lua_newuserdatauv(L, sizeof(T), nupvalue)); + new (o) T(std::forward(args)...); + getmetatable(L); + lua_setmetatable(L, -2); + return *o; + } + + template + T& checkudata(lua_State* L, int arg) { + if constexpr (udata_has_name::value) { + return *static_cast(luaL_checkudata(L, arg, udata::name)); + } + else { + luaL_checktype(L, arg, LUA_TUSERDATA); + return toudata(L, arg); + } + } +} diff --git a/binding/binding.h b/binding/binding.h index c1179c82..103a5004 100644 --- a/binding/binding.h +++ b/binding/binding.h @@ -1,242 +1,9 @@ #pragma once -#include -#include -#include -#include -#include - -#include -#include #include -#include #include -#if defined(_WIN32) -# include -#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 - constexpr bool checklimit(I i) { - static_assert(std::is_integral_v); - static_assert(std::is_integral_v); - static_assert(sizeof(I) >= sizeof(T)); - if constexpr (sizeof(I) == sizeof(T)) { - return true; - } - else if constexpr (std::numeric_limits::is_signed == std::numeric_limits::is_signed) { - return i >= std::numeric_limits::lowest() && i <= (std::numeric_limits::max)(); - } - else if constexpr (std::numeric_limits::is_signed) { - return static_cast>(i) >= std::numeric_limits::lowest() && static_cast>(i) <= (std::numeric_limits::max)(); - } - else { - return static_cast>(i) >= std::numeric_limits::lowest() && static_cast>(i) <= (std::numeric_limits::max)(); - } - } - - template - T checkinteger(lua_State* L, int arg) { - static_assert(std::is_trivial_v); - if constexpr (std::is_enum_v) { - using UT = std::underlying_type_t; - return static_cast(checkinteger(L, arg)); - } - else if constexpr (std::is_integral_v) { - lua_Integer r = luaL_checkinteger(L, arg); - if constexpr (std::is_same_v) { - return r; - } - else if constexpr (sizeof(T) >= sizeof(lua_Integer)) { - return static_cast(r); - } - else { - if (checklimit(r)) { - return static_cast(r); - } - luaL_error(L, "bad argument '#%d' limit exceeded", arg); - std::unreachable(); - } - } - else { - return std::bit_cast(checkinteger(L, arg)); - } - } - template - T optinteger(lua_State* L, int arg) { - static_assert(std::is_trivial_v); - if constexpr (std::is_enum_v) { - using UT = std::underlying_type_t; - return static_cast(optinteger(L, arg)); - } - else if constexpr (std::is_integral_v) { - if constexpr (std::is_same_v) { - return luaL_optinteger(L, arg, def); - } - else if constexpr (sizeof(T) == sizeof(lua_Integer)) { - lua_Integer r = optinteger(def)>(L, arg); - return static_cast(r); - } - else if constexpr (sizeof(T) < sizeof(lua_Integer)) { - lua_Integer r = optinteger(def)>(L, arg); - if (checklimit(r)) { - return static_cast(r); - } - luaL_error(L, "bad argument '#%d' limit exceeded", arg); - std::unreachable(); - } - else { - static_assert(checklimit(def)); - lua_Integer r = optinteger(def)>(L, arg); - return static_cast(r); - } - } - else { - // If std::bit_cast were not constexpr, it would fail here, so let it fail. - return std::bit_cast(optinteger(def)>(L, arg)); - } - } - - template - T tolightud(lua_State* L, int arg) { - if constexpr (std::is_integral_v) { - uintptr_t r = std::bit_cast(tolightud(L, arg)); - if constexpr (std::is_same_v) { - return r; - } - else if constexpr (sizeof(T) >= sizeof(uintptr_t)) { - return static_cast(r); - } - else { - if (checklimit(r)) { - return static_cast(r); - } - luaL_error(L, "bad argument #%d limit exceeded", arg); - std::unreachable(); - } - } - else if constexpr (std::is_same_v) { - return lua_touserdata(L, arg); - } - else if constexpr (std::is_pointer_v) { - return static_cast(tolightud(L, arg)); - } - else { - return std::bit_cast(tolightud(L, arg)); - } - } - - template - T checklightud(lua_State* L, int arg) { - luaL_checktype(L, arg, LUA_TLIGHTUSERDATA); - return tolightud(L, arg); - } - - template - T& toudata(lua_State* L, int arg) { - return *tolightud(L, arg); - } - - template - struct udata {}; - template - struct udata_has_name : std::false_type {}; - template - struct udata_has_name::name)>> : std::true_type {}; - template - struct udata_has_nupvalue : std::false_type {}; - template - struct udata_has_nupvalue::nupvalue)>> : std::true_type {}; - - template - int destroyudata(lua_State* L) { - toudata(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 - static int cfunc(lua_State* L) { - status s = f(L); - if (!s.err) { - return s.n; - } - return lua_error(L); - } - } - - template - void getmetatable(lua_State* L) { - if (luaL_newmetatable(L, udata::name)) { - if constexpr (!std::is_trivially_destructible::value) { - lua_pushcfunction(L, destroyudata); - lua_setfield(L, -2, "__gc"); - } - udata::metatable(L); - } - } - - template - T& newudata(lua_State* L, Args&&... args) { - static_assert(udata_has_name::value); - int nupvalue = 0; - if constexpr (udata_has_nupvalue::value) { - nupvalue = udata::nupvalue; - } - T* o = static_cast(lua_newuserdatauv(L, sizeof(T), nupvalue)); - new (o) T(std::forward(args)...); - getmetatable(L); - lua_setmetatable(L, -2); - return *o; - } - - template - T& checkudata(lua_State* L, int arg) { - if constexpr (udata_has_name::value) { - return *static_cast(luaL_checkudata(L, arg, udata::name)); - } - else { - luaL_checktype(L, arg, LUA_TUSERDATA); - return toudata(L, arg); - } - } - struct callfunc { template callfunc(F f, Args... args) { diff --git a/binding/lua_filesystem.cpp b/binding/lua_filesystem.cpp index 89e1cf6f..96d1811d 100644 --- a/binding/lua_filesystem.cpp +++ b/binding/lua_filesystem.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/binding/lua_filewatch.cpp b/binding/lua_filewatch.cpp index c57ac23a..ae41c7b5 100644 --- a/binding/lua_filewatch.cpp +++ b/binding/lua_filewatch.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/binding/lua_platform.cpp b/binding/lua_platform.cpp index 39af058b..54730ebf 100644 --- a/binding/lua_platform.cpp +++ b/binding/lua_platform.cpp @@ -1,3 +1,4 @@ +#include #include #include diff --git a/binding/lua_select.cpp b/binding/lua_select.cpp index 3cd22477..594a53eb 100644 --- a/binding/lua_select.cpp +++ b/binding/lua_select.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #if defined _WIN32 # include #else diff --git a/binding/lua_serialization.cpp b/binding/lua_serialization.cpp index 59196798..30f2d019 100644 --- a/binding/lua_serialization.cpp +++ b/binding/lua_serialization.cpp @@ -1,3 +1,4 @@ +#include #include extern "C" { diff --git a/binding/lua_socket.cpp b/binding/lua_socket.cpp index 01e60e8d..1b448ab4 100644 --- a/binding/lua_socket.cpp +++ b/binding/lua_socket.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/binding/lua_subprocess.cpp b/binding/lua_subprocess.cpp index ce95298b..46de2795 100644 --- a/binding/lua_subprocess.cpp +++ b/binding/lua_subprocess.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -610,8 +611,8 @@ DEFINE_LUAOPEN(subprocess) namespace bee::lua { template <> struct udata { - static inline int nupvalue = 1; - static inline auto name = "bee::subprocess"; - static inline auto metatable = bee::lua_subprocess::process::metatable; + static inline int nupvalue = 1; + static inline auto name = "bee::subprocess"; + static inline auto metatable = bee::lua_subprocess::process::metatable; }; } diff --git a/binding/lua_thread.cpp b/binding/lua_thread.cpp index 851fa398..54687c6a 100644 --- a/binding/lua_thread.cpp +++ b/binding/lua_thread.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/binding/lua_time.cpp b/binding/lua_time.cpp index a0760937..62170db3 100644 --- a/binding/lua_time.cpp +++ b/binding/lua_time.cpp @@ -1,3 +1,4 @@ +#include #include #if defined(_WIN32) diff --git a/binding/lua_unicode.cpp b/binding/lua_unicode.cpp index d5619a7f..30ec84b3 100644 --- a/binding/lua_unicode.cpp +++ b/binding/lua_unicode.cpp @@ -1,3 +1,4 @@ +#include #include #include