// https://github.com/kunitoki/LuaBridge3 // Copyright 2025, Lucio Asnaghi // SPDX-License-Identifier: MIT // clang-format off #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Begin File: Source/LuaBridge/detail/Config.h #if !(__cplusplus >= 201703L || (defined(_MSC_VER) && _HAS_CXX17)) #error LuaBridge 3 requires a compliant C++17 compiler, or C++17 has not been enabled ! #endif #if !defined(LUABRIDGE_HAS_EXCEPTIONS) #if defined(_MSC_VER) #if _CPPUNWIND || _HAS_EXCEPTIONS #define LUABRIDGE_HAS_EXCEPTIONS 1 #else #define LUABRIDGE_HAS_EXCEPTIONS 0 #endif #elif defined(__clang__) #if __EXCEPTIONS && __has_feature(cxx_exceptions) #define LUABRIDGE_HAS_EXCEPTIONS 1 #else #define LUABRIDGE_HAS_EXCEPTIONS 0 #endif #elif defined(__GNUC__) #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) #define LUABRIDGE_HAS_EXCEPTIONS 1 #else #define LUABRIDGE_HAS_EXCEPTIONS 0 #endif #endif #endif #if LUABRIDGE_HAS_EXCEPTIONS #define LUABRIDGE_IF_EXCEPTIONS(...) __VA_ARGS__ #define LUABRIDGE_IF_NO_EXCEPTIONS(...) #else #define LUABRIDGE_IF_EXCEPTIONS(...) #define LUABRIDGE_IF_NO_EXCEPTIONS(...) __VA_ARGS__ #endif #if defined(LUAU_FASTMATH_BEGIN) #define LUABRIDGE_ON_LUAU 1 #elif defined(LUAJIT_VERSION) #define LUABRIDGE_ON_LUAJIT 1 #elif defined(RAVI_OPTION_STRING2) #define LUABRIDGE_ON_RAVI 1 #elif defined(LUA_VERSION_NUM) #define LUABRIDGE_ON_LUA 1 #else #error "Lua headers must be included prior to LuaBridge ones" #endif #if defined(__OBJC__) #define LUABRIDGE_ON_OBJECTIVE_C 1 #endif #if !defined(LUABRIDGE_SAFE_STACK_CHECKS) #define LUABRIDGE_SAFE_STACK_CHECKS 1 #endif #if !defined(LUABRIDGE_SAFE_LUA_C_EXCEPTION_HANDLING) #define LUABRIDGE_SAFE_LUA_C_EXCEPTION_HANDLING 0 #endif #if !defined(LUABRIDGE_RAISE_UNREGISTERED_CLASS_USAGE) #if LUABRIDGE_HAS_EXCEPTIONS #define LUABRIDGE_RAISE_UNREGISTERED_CLASS_USAGE 1 #else #define LUABRIDGE_RAISE_UNREGISTERED_CLASS_USAGE 0 #endif #endif #if !defined(LUABRIDGE_ASSERT) #if defined(NDEBUG) && !defined(LUABRIDGE_FORCE_ASSERT_RELEASE) #define LUABRIDGE_ASSERT(expr) ((void)(expr)) #else #define LUABRIDGE_ASSERT(expr) assert(expr) #endif #endif // End File: Source/LuaBridge/detail/Config.h // Begin File: Source/LuaBridge/detail/LuaHelpers.h namespace luabridge { template constexpr void unused(Args&&...) { } #if LUABRIDGE_ON_LUAU inline int luaL_ref(lua_State* L, int idx) { LUABRIDGE_ASSERT(idx == LUA_REGISTRYINDEX); const int ref = lua_ref(L, -1); lua_pop(L, 1); return ref; } inline void luaL_unref(lua_State* L, int idx, int ref) { unused(idx); lua_unref(L, ref); } template inline void* lua_newuserdata_x(lua_State* L, size_t sz) { return lua_newuserdatadtor(L, sz, [](void* x) { T* object = static_cast(x); object->~T(); }); } inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname) { lua_pushcfunction(L, fn, debugname); } inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n) { lua_pushcclosure(L, fn, debugname, n); } inline int lua_error_x(lua_State* L) { lua_error(L); return 0; } inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar) { return lua_getinfo(L, level, "nlS", ar); } inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar) { return lua_getinfo(L, level, what, ar); } #else using ::luaL_ref; using ::luaL_unref; template inline void* lua_newuserdata_x(lua_State* L, size_t sz) { return lua_newuserdata(L, sz); } inline void lua_pushcfunction_x(lua_State *L, lua_CFunction fn, const char* debugname) { unused(debugname); lua_pushcfunction(L, fn); } inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debugname, int n) { unused(debugname); lua_pushcclosure(L, fn, n); } inline int lua_error_x(lua_State* L) { return lua_error(L); } inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar) { return lua_getstack(L, level, ar); } inline int lua_getstack_info_x(lua_State* L, int level, const char* what, lua_Debug* ar) { lua_getstack(L, level, ar); return lua_getinfo(L, what, ar); } #endif #if LUA_VERSION_NUM < 503 inline lua_Number to_numberx(lua_State* L, int idx, int* isnum) { lua_Number n = lua_tonumber(L, idx); if (isnum) *isnum = (n != 0 || lua_isnumber(L, idx)); return n; } inline lua_Integer to_integerx(lua_State* L, int idx, int* isnum) { int ok = 0; lua_Number n = to_numberx(L, idx, &ok); if (ok) { const auto int_n = static_cast(n); if (n == static_cast(int_n)) { if (isnum) *isnum = 1; return int_n; } } if (isnum) *isnum = 0; return 0; } #endif #if LUA_VERSION_NUM < 502 using lua_Unsigned = std::make_unsigned_t; #if ! LUABRIDGE_ON_LUAU inline int lua_absindex(lua_State* L, int idx) { if (idx > LUA_REGISTRYINDEX && idx < 0) return lua_gettop(L) + idx + 1; else return idx; } #endif inline int lua_rawgetp(lua_State* L, int idx, const void* p) { idx = lua_absindex(L, idx); luaL_checkstack(L, 1, "not enough stack slots"); lua_pushlightuserdata(L, const_cast(p)); lua_rawget(L, idx); return lua_type(L, -1); } inline void lua_rawsetp(lua_State* L, int idx, const void* p) { idx = lua_absindex(L, idx); luaL_checkstack(L, 1, "not enough stack slots"); lua_pushlightuserdata(L, const_cast(p)); lua_insert(L, -2); lua_rawset(L, idx); } #define LUA_OPEQ 1 #define LUA_OPLT 2 #define LUA_OPLE 3 inline int lua_compare(lua_State* L, int idx1, int idx2, int op) { switch (op) { case LUA_OPEQ: return lua_equal(L, idx1, idx2); case LUA_OPLT: return lua_lessthan(L, idx1, idx2); case LUA_OPLE: return lua_equal(L, idx1, idx2) || lua_lessthan(L, idx1, idx2); default: return 0; } } #if ! LUABRIDGE_ON_LUAJIT inline void* luaL_testudata(lua_State* L, int ud, const char* tname) { void* p = lua_touserdata(L, ud); if (p == nullptr) return nullptr; if (! lua_getmetatable(L, ud)) return nullptr; luaL_getmetatable(L, tname); if (! lua_rawequal(L, -1, -2)) p = nullptr; lua_pop(L, 2); return p; } #endif inline int get_length(lua_State* L, int idx) { return static_cast(lua_objlen(L, idx)); } #else inline int get_length(lua_State* L, int idx) { lua_len(L, idx); const int len = static_cast(luaL_checknumber(L, -1)); lua_pop(L, 1); return len; } #endif #ifndef LUA_OK #define LUABRIDGE_LUA_OK 0 #else #define LUABRIDGE_LUA_OK LUA_OK #endif template std::error_code throw_or_error_code(ErrorType error) { #if LUABRIDGE_HAS_EXCEPTIONS throw T(makeErrorCode(error).message().c_str()); #else return makeErrorCode(error); #endif } template std::error_code throw_or_error_code(lua_State* L, ErrorType error) { #if LUABRIDGE_HAS_EXCEPTIONS throw T(L, makeErrorCode(error)); #else return unused(L), makeErrorCode(error); #endif } template void throw_or_assert(Args&&... args) { #if LUABRIDGE_HAS_EXCEPTIONS throw T(std::forward(args)...); #else unused(std::forward(args)...); LUABRIDGE_ASSERT(false); #endif } template void pushunsigned(lua_State* L, T value) { static_assert(std::is_unsigned_v); lua_pushinteger(L, static_cast(value)); } inline lua_Number tonumber(lua_State* L, int idx, int* isnum) { #if ! LUABRIDGE_ON_LUAU && LUA_VERSION_NUM > 502 return lua_tonumberx(L, idx, isnum); #else return to_numberx(L, idx, isnum); #endif } inline lua_Integer tointeger(lua_State* L, int idx, int* isnum) { #if ! LUABRIDGE_ON_LUAU && LUA_VERSION_NUM > 502 return lua_tointegerx(L, idx, isnum); #else return to_integerx(L, idx, isnum); #endif } inline constexpr char main_thread_name[] = "__luabridge_main_thread"; inline void register_main_thread(lua_State* threadL) { #if LUA_VERSION_NUM < 502 if (threadL == nullptr) lua_pushnil(threadL); else lua_pushthread(threadL); lua_setglobal(threadL, main_thread_name); #else unused(threadL); #endif } inline lua_State* main_thread(lua_State* threadL) { #if LUA_VERSION_NUM < 502 lua_getglobal(threadL, main_thread_name); if (lua_isthread(threadL, -1)) { auto L = lua_tothread(threadL, -1); lua_pop(threadL, 1); return L; } LUABRIDGE_ASSERT(false); lua_pop(threadL, 1); return threadL; #else lua_rawgeti(threadL, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); lua_State* L = lua_tothread(threadL, -1); lua_pop(threadL, 1); return L; #endif } inline int rawgetfield(lua_State* L, int index, const char* key) { LUABRIDGE_ASSERT(lua_istable(L, index)); index = lua_absindex(L, index); lua_pushstring(L, key); #if LUA_VERSION_NUM <= 502 lua_rawget(L, index); return lua_type(L, -1); #else return lua_rawget(L, index); #endif } inline void rawsetfield(lua_State* L, int index, const char* key) { LUABRIDGE_ASSERT(lua_istable(L, index)); index = lua_absindex(L, index); lua_pushstring(L, key); lua_insert(L, -2); lua_rawset(L, index); } [[nodiscard]] inline bool isfulluserdata(lua_State* L, int index) { return lua_isuserdata(L, index) && !lua_islightuserdata(L, index); } [[nodiscard]] inline bool equalstates(lua_State* L1, lua_State* L2) { return lua_topointer(L1, LUA_REGISTRYINDEX) == lua_topointer(L2, LUA_REGISTRYINDEX); } [[nodiscard]] inline int table_length(lua_State* L, int index) { LUABRIDGE_ASSERT(lua_istable(L, index)); int items_count = 0; lua_pushnil(L); while (lua_next(L, index) != 0) { ++items_count; lua_pop(L, 1); } return items_count; } template [[nodiscard]] T* align(void* ptr) noexcept { const auto address = reinterpret_cast(ptr); const auto offset = address % alignof(T); const auto aligned_address = (offset == 0) ? address : (address + alignof(T) - offset); return reinterpret_cast(aligned_address); } template , int> = 0> [[nodiscard]] bool is_aligned(T address) noexcept { static_assert(Alignment > 0u); return (reinterpret_cast(address) & (Alignment - 1u)) == 0u; } template [[nodiscard]] constexpr size_t maximum_space_needed_to_align() noexcept { return sizeof(T) + alignof(T) - 1; } template int lua_deleteuserdata_aligned(lua_State* L) { LUABRIDGE_ASSERT(isfulluserdata(L, 1)); T* aligned = align(lua_touserdata(L, 1)); aligned->~T(); return 0; } template void* lua_newuserdata_aligned(lua_State* L, Args&&... args) { using U = std::remove_reference_t; #if LUABRIDGE_ON_LUAU void* pointer = lua_newuserdatadtor(L, maximum_space_needed_to_align(), [](void* x) { U* aligned = align(x); aligned->~U(); }); #else void* pointer = lua_newuserdata_x(L, maximum_space_needed_to_align()); lua_newtable(L); lua_pushcfunction_x(L, &lua_deleteuserdata_aligned, ""); rawsetfield(L, -2, "__gc"); lua_setmetatable(L, -2); #endif U* aligned = align(pointer); new (aligned) U(std::forward(args)...); return pointer; } inline int raise_lua_error(lua_State* L, const char* fmt, ...) { va_list argp; va_start(argp, fmt); lua_pushvfstring(L, fmt, argp); va_end(argp); const char* message = lua_tostring(L, -1); if (message != nullptr) { if (auto str = std::string_view(message); !str.empty() && str[0] == '[') return lua_error_x(L); } bool pushed_error = false; for (int level = 1; level <= 2; ++level) { lua_Debug ar; #if LUABRIDGE_ON_LUAU if (lua_getinfo(L, level, "sl", &ar) == 0) continue; #else if (lua_getstack(L, level, &ar) == 0 || lua_getinfo(L, "Sl", &ar) == 0) continue; #endif if (ar.currentline <= 0) continue; lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); pushed_error = true; break; } if (! pushed_error) lua_pushliteral(L, ""); lua_pushvalue(L, -2); lua_remove(L, -3); lua_concat(L, 2); return lua_error_x(L); } template constexpr bool is_integral_representable_by(T value) { constexpr bool same_signedness = (std::is_unsigned_v && std::is_unsigned_v) || (!std::is_unsigned_v && !std::is_unsigned_v); if constexpr (sizeof(T) == sizeof(U)) { if constexpr (same_signedness) return true; if constexpr (std::is_unsigned_v) return value <= static_cast((std::numeric_limits::max)()); return value >= static_cast((std::numeric_limits::min)()) && static_cast(value) <= (std::numeric_limits::max)(); } if constexpr (sizeof(T) < sizeof(U)) { return static_cast(value) >= (std::numeric_limits::min)() && static_cast(value) <= (std::numeric_limits::max)(); } if constexpr (std::is_unsigned_v) return value <= static_cast((std::numeric_limits::max)()); return value >= static_cast((std::numeric_limits::min)()) && value <= static_cast((std::numeric_limits::max)()); } template bool is_integral_representable_by(lua_State* L, int index) { int isValid = 0; const auto value = tointeger(L, index, &isValid); return isValid ? is_integral_representable_by(value) : false; } template constexpr bool is_floating_point_representable_by(T value) { if constexpr (sizeof(T) == sizeof(U)) return true; if constexpr (sizeof(T) < sizeof(U)) return static_cast(value) >= -(std::numeric_limits::max)() && static_cast(value) <= (std::numeric_limits::max)(); return value >= static_cast(-(std::numeric_limits::max)()) && value <= static_cast((std::numeric_limits::max)()); } template bool is_floating_point_representable_by(lua_State* L, int index) { int isValid = 0; const auto value = tonumber(L, index, &isValid); return isValid ? is_floating_point_representable_by(value) : false; } } // End File: Source/LuaBridge/detail/LuaHelpers.h // Begin File: Source/LuaBridge/detail/Errors.h namespace luabridge { namespace detail { static inline constexpr char error_lua_stack_overflow[] = "stack overflow"; } enum class ErrorCode { ClassNotRegistered = 1, LuaStackOverflow, LuaFunctionCallFailed, IntegerDoesntFitIntoLuaInteger, FloatingPointDoesntFitIntoLuaNumber, InvalidTypeCast, InvalidTableSizeInCast }; namespace detail { struct ErrorCategory : std::error_category { const char* name() const noexcept override { return "luabridge"; } std::string message(int ev) const override { switch (static_cast(ev)) { case ErrorCode::ClassNotRegistered: return "The class is not registered in LuaBridge"; case ErrorCode::LuaStackOverflow: return "The lua stack has overflow"; case ErrorCode::LuaFunctionCallFailed: return "The lua function invocation raised an error"; case ErrorCode::IntegerDoesntFitIntoLuaInteger: return "The native integer can't fit inside a lua integer"; case ErrorCode::FloatingPointDoesntFitIntoLuaNumber: return "The native floating point can't fit inside a lua number"; case ErrorCode::InvalidTypeCast: return "The lua object can't be cast to desired type"; case ErrorCode::InvalidTableSizeInCast: return "The lua table has different size than expected"; default: return "Unknown error"; } } static const ErrorCategory& getInstance() noexcept { static ErrorCategory category; return category; } }; } inline std::error_code makeErrorCode(ErrorCode e) { return { static_cast(e), detail::ErrorCategory::getInstance() }; } inline std::error_code make_error_code(ErrorCode e) { return { static_cast(e), detail::ErrorCategory::getInstance() }; } } namespace std { template <> struct is_error_code_enum : true_type {}; } // End File: Source/LuaBridge/detail/Errors.h // Begin File: Source/LuaBridge/detail/Expected.h #if LUABRIDGE_HAS_EXCEPTIONS #endif namespace luabridge { namespace detail { using std::swap; template T* construct_at(T* ptr, Args&&... args) noexcept(std::is_nothrow_constructible::value) { return static_cast(::new (const_cast(static_cast(ptr))) T(std::forward(args)...)); } template struct is_swappable_with_impl : std::false_type { }; template struct is_swappable_with_impl(), std::declval()))>> : std::true_type { }; template struct is_nothrow_swappable_with_impl { static constexpr bool value = noexcept(swap(std::declval(), std::declval())) && noexcept(swap(std::declval(), std::declval())); using type = std::bool_constant; }; template struct is_swappable_with : std::conjunction< is_swappable_with_impl, std::add_lvalue_reference_t>, is_swappable_with_impl, std::add_lvalue_reference_t>>::type { }; template struct is_nothrow_swappable_with : std::conjunction, is_nothrow_swappable_with_impl>::type { }; template struct is_nothrow_swappable : std::is_nothrow_swappable_with, std::add_lvalue_reference_t> { }; template struct has_member_message : std::false_type { }; template struct has_member_message().message())>> : std::true_type { }; template inline static constexpr bool has_member_message_v = has_member_message::value; } template class Expected; struct UnexpectType { constexpr UnexpectType() = default; }; static constexpr auto unexpect = UnexpectType(); namespace detail { template , bool = (std::is_void_v || std::is_trivial_v) && std::is_trivial_v> union expected_storage { public: template >> constexpr expected_storage() noexcept : value_() { } template constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept : value_(std::forward(args)...) { } template constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept : error_(std::forward(args)...) { } ~expected_storage() = default; constexpr const T& value() const noexcept { return value_; } constexpr T& value() noexcept { return value_; } constexpr const E& error() const noexcept { return error_; } constexpr E& error() noexcept { return error_; } private: T value_; E error_; }; template union expected_storage { public: constexpr expected_storage() noexcept : dummy_(0) { } template constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept : error_(std::forward(args)...) { } ~expected_storage() = default; constexpr const E& error() const noexcept { return error_; } constexpr E& error() noexcept { return error_; } private: char dummy_; E error_; }; template union expected_storage { public: constexpr expected_storage() noexcept(std::is_nothrow_default_constructible_v) : value_() { } template constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : value_(std::forward(args)...) { } template constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : error_(std::forward(args)...) { } ~expected_storage() { } constexpr const T& value() const noexcept { return value_; } constexpr T& value() noexcept { return value_; } constexpr const E& error() const noexcept { return error_; } constexpr E& error() noexcept { return error_; } private: T value_; E error_; }; template union expected_storage { public: constexpr explicit expected_storage() noexcept : dummy_(0) { } template constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : value_(std::forward(args)...) { } template constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : error_(std::forward(args)...) { } ~expected_storage() { } constexpr const T& value() const noexcept { return value_; } constexpr T& value() noexcept { return value_; } constexpr const E& error() const noexcept { return error_; } constexpr E& error() noexcept { return error_; } private: char dummy_; T value_; E error_; }; template union expected_storage { public: constexpr expected_storage() noexcept : dummy_(0) { } template constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : error_(std::forward(args)...) { } ~expected_storage() = default; constexpr const E& error() const noexcept { return error_; } constexpr E& error() noexcept { return error_; } private: char dummy_; E error_; }; template class expected_base_trivial { using this_type = expected_base_trivial; protected: using storage_type = expected_storage; constexpr expected_base_trivial() noexcept : valid_(true) { } template constexpr expected_base_trivial(std::in_place_t, Args&&... args) noexcept : storage_(std::in_place, std::forward(args)...) , valid_(true) { } template constexpr expected_base_trivial(UnexpectType, Args&&... args) noexcept : storage_(unexpect, std::forward(args)...) , valid_(false) { } expected_base_trivial(const expected_base_trivial& other) noexcept { if (other.valid_) { construct(std::in_place, other.value()); } else { construct(unexpect, other.error()); } } expected_base_trivial(expected_base_trivial&& other) noexcept { if (other.valid_) { construct(std::in_place, std::move(other.value())); } else { construct(unexpect, std::move(other.error())); } } ~expected_base_trivial() noexcept = default; constexpr const T& value() const noexcept { return storage_.value(); } constexpr T& value() noexcept { return storage_.value(); } constexpr const E& error() const noexcept { return storage_.error(); } constexpr E& error() noexcept { return storage_.error(); } constexpr const T* valuePtr() const noexcept { return std::addressof(value()); } constexpr T* valuePtr() noexcept { return std::addressof(value()); } constexpr const E* errorPtr() const noexcept { return std::addressof(error()); } constexpr E* errorPtr() noexcept { return std::addressof(error()); } constexpr bool valid() const noexcept { return valid_; } template inline T& construct(std::in_place_t, Args&&... args) noexcept { valid_ = true; return *detail::construct_at(valuePtr(), std::forward(args)...); } template inline E& construct(UnexpectType, Args&&... args) noexcept { valid_ = false; return *detail::construct_at(errorPtr(), std::forward(args)...); } inline void destroy() noexcept { } private: storage_type storage_; bool valid_; }; template class expected_base_non_trivial { using this_type = expected_base_non_trivial; protected: using storage_type = expected_storage; constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) : valid_(true) { } template constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(std::in_place, std::forward(args)...) , valid_(true) { } template constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(unexpect, std::forward(args)...) , valid_(false) { } expected_base_non_trivial(const expected_base_non_trivial& other) { if (other.valid_) { construct(std::in_place, other.value()); } else { construct(unexpect, other.error()); } } expected_base_non_trivial(expected_base_non_trivial&& other) noexcept { if (other.valid_) { construct(std::in_place, std::move(other.value())); } else { construct(unexpect, std::move(other.error())); } } ~expected_base_non_trivial() { destroy(); } constexpr const T& value() const noexcept { return storage_.value(); } constexpr T& value() noexcept { return storage_.value(); } constexpr const E& error() const noexcept { return storage_.error(); } constexpr E& error() noexcept { return storage_.error(); } constexpr const T* valuePtr() const noexcept { return std::addressof(value()); } constexpr T* valuePtr() noexcept { return std::addressof(value()); } constexpr const E* errorPtr() const noexcept { return std::addressof(error()); } constexpr E* errorPtr() noexcept { return std::addressof(error()); } constexpr bool valid() const noexcept { return valid_; } template inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = true; return *detail::construct_at(valuePtr(), std::forward(args)...); } template inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = false; return *detail::construct_at(errorPtr(), std::forward(args)...); } inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) { if (valid_) { std::destroy_at(valuePtr()); } else { std::destroy_at(errorPtr()); } } private: storage_type storage_; bool valid_; }; template class expected_base_non_trivial { using this_type = expected_base_non_trivial; protected: using storage_type = expected_storage; constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) : valid_(true) { } template constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(std::in_place, std::forward(args)...) , valid_(true) { } template constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(unexpect, std::forward(args)...) , valid_(false) { } expected_base_non_trivial(const expected_base_non_trivial& other) = delete; expected_base_non_trivial(expected_base_non_trivial&& other) noexcept { if (other.valid_) { construct(std::in_place, std::move(other.value())); } else { construct(unexpect, std::move(other.error())); } } ~expected_base_non_trivial() { destroy(); } constexpr const T& value() const noexcept { return storage_.value(); } constexpr T& value() noexcept { return storage_.value(); } constexpr const E& error() const noexcept { return storage_.error(); } constexpr E& error() noexcept { return storage_.error(); } constexpr const T* valuePtr() const noexcept { return std::addressof(value()); } constexpr T* valuePtr() noexcept { return std::addressof(value()); } constexpr const E* errorPtr() const noexcept { return std::addressof(error()); } constexpr E* errorPtr() noexcept { return std::addressof(error()); } constexpr bool valid() const noexcept { return valid_; } template inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = true; return *detail::construct_at(valuePtr(), std::forward(args)...); } template inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = false; return *detail::construct_at(errorPtr(), std::forward(args)...); } inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) { if (valid_) { std::destroy_at(valuePtr()); } else { std::destroy_at(errorPtr()); } } private: storage_type storage_; bool valid_; }; template class expected_base_non_trivial { using this_type = expected_base_non_trivial; protected: using storage_type = expected_storage; template >> constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) : valid_(true) { } template constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(std::in_place, std::forward(args)...) , valid_(true) { } template constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(unexpect, std::forward(args)...) , valid_(false) { } expected_base_non_trivial(const expected_base_non_trivial& other) { if (other.valid_) { construct(std::in_place, other.value()); } else { construct(unexpect, other.error()); } } expected_base_non_trivial(expected_base_non_trivial&& other) = delete; ~expected_base_non_trivial() { destroy(); } constexpr const T& value() const noexcept { return storage_.value(); } constexpr T& value() noexcept { return storage_.value(); } constexpr const E& error() const noexcept { return storage_.error(); } constexpr E& error() noexcept { return storage_.error(); } constexpr const T* valuePtr() const noexcept { return std::addressof(value()); } constexpr T* valuePtr() noexcept { return std::addressof(value()); } constexpr const E* errorPtr() const noexcept { return std::addressof(error()); } constexpr E* errorPtr() noexcept { return std::addressof(error()); } constexpr bool valid() const noexcept { return valid_; } template inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = true; return *detail::construct_at(valuePtr(), std::forward(args)...); } template inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = false; return *detail::construct_at(errorPtr(), std::forward(args)...); } inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) { if (valid_) { std::destroy_at(valuePtr()); } else { std::destroy_at(errorPtr()); } } private: storage_type storage_; bool valid_; }; template class expected_base_non_trivial { using this_type = expected_base_non_trivial; protected: using storage_type = expected_storage; template >> constexpr expected_base_non_trivial() noexcept(std::is_nothrow_default_constructible_v) : valid_(true) { } template constexpr expected_base_non_trivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(std::in_place, std::forward(args)...) , valid_(true) { } template constexpr expected_base_non_trivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : storage_(unexpect, std::forward(args)...) , valid_(false) { } expected_base_non_trivial(const expected_base_non_trivial& other) = delete; expected_base_non_trivial(expected_base_non_trivial&& other) = delete; ~expected_base_non_trivial() { destroy(); } constexpr const T& value() const noexcept { return storage_.value(); } constexpr T& value() noexcept { return storage_.value(); } constexpr const E& error() const noexcept { return storage_.error(); } constexpr E& error() noexcept { return storage_.error(); } constexpr const T* valuePtr() const noexcept { return std::addressof(value()); } constexpr T* valuePtr() noexcept { return std::addressof(value()); } constexpr const E* errorPtr() const noexcept { return std::addressof(error()); } constexpr E* errorPtr() noexcept { return std::addressof(error()); } constexpr bool valid() const noexcept { return valid_; } template inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = true; return *detail::construct_at(valuePtr(), std::forward(args)...); } template inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) { valid_ = false; return *detail::construct_at(errorPtr(), std::forward(args)...); } inline void destroy() noexcept(std::is_nothrow_destructible_v&& std::is_nothrow_destructible_v) { if (valid_) { std::destroy_at(valuePtr()); } else { std::destroy_at(errorPtr()); } } private: storage_type storage_; bool valid_; }; template using expected_base = std::conditional_t< (std::is_void_v || std::is_trivially_destructible_v) && std::is_trivially_destructible_v, expected_base_trivial, expected_base_non_trivial>; } template class Unexpected { static_assert(!std::is_reference_v && !std::is_void_v, "Unexpected type can't be a reference or void"); public: Unexpected() = delete; constexpr explicit Unexpected(E&& e) noexcept(std::is_nothrow_move_constructible_v) : error_(std::move(e)) { } constexpr explicit Unexpected(const E& e) noexcept(std::is_nothrow_copy_constructible_v) : error_(e) { } constexpr const E& value() const& noexcept { return error_; } constexpr E& value() & noexcept { return error_; } constexpr const E&& value() const&& noexcept { return std::move(error_); } constexpr E&& value() && noexcept { return std::move(error_); } private: E error_; }; template constexpr bool operator==(const Unexpected& lhs, const Unexpected& rhs) noexcept { return lhs.value() == rhs.value(); } template constexpr bool operator!=(const Unexpected& lhs, const Unexpected& rhs) noexcept { return lhs.value() != rhs.value(); } template constexpr inline Unexpected> makeUnexpected(E&& error) noexcept(std::is_nothrow_constructible_v>, E>) { return Unexpected>{ std::forward(error) }; } #if LUABRIDGE_HAS_EXCEPTIONS template class BadExpectedAccess; template <> class BadExpectedAccess : public std::runtime_error { template friend class BadExpectedAccess; BadExpectedAccess(std::in_place_t) noexcept : std::runtime_error("Bad access to expected value") { } public: BadExpectedAccess() noexcept : BadExpectedAccess(std::in_place) { } explicit BadExpectedAccess(const std::string& message) noexcept : std::runtime_error(message) { } }; template class BadExpectedAccess : public std::runtime_error { public: explicit BadExpectedAccess(E error) noexcept(std::is_nothrow_constructible_v) : std::runtime_error([](const E& error) { if constexpr (detail::has_member_message_v) return error.message(); else return "Bad access to expected value"; }(error)) , error_(std::move(error)) { } const E& error() const& noexcept { return error_; } E& error() & noexcept { return error_; } E&& error() && noexcept { return std::move(error_); } private: E error_; }; #endif template struct is_expected : std::false_type { }; template struct is_expected> : std::true_type { }; template struct is_unexpected : std::false_type { }; template struct is_unexpected> : std::true_type { }; template class Expected : public detail::expected_base, std::is_move_constructible_v> { static_assert(!std::is_reference_v && !std::is_void_v, "Unexpected type can't be a reference or void"); using base_type = detail::expected_base, std::is_move_constructible_v>; using this_type = Expected; public: using value_type = T; using error_type = E; using unexpected_type = Unexpected; template struct rebind { using type = Expected; }; template >> constexpr Expected() noexcept(std::is_nothrow_default_constructible_v) : base_type() { } constexpr Expected(const Expected& other) noexcept(std::is_nothrow_copy_constructible_v) = default; constexpr Expected(Expected&& other) noexcept(std::is_nothrow_move_constructible_v) = default; template Expected(const Expected& other) { if (other.hasValue()) { this->construct(std::in_place, other.value()); } else { this->construct(unexpect, other.error()); } } template Expected(Expected&& other) { if (other.hasValue()) { this->construct(std::in_place, std::move(other.value())); } else { this->construct(unexpect, std::move(other.error())); } } template && std::is_constructible_v && !std::is_same_v, std::in_place_t> && !is_expected>::value && !is_unexpected>::value, int> = 0> constexpr Expected(U&& value) noexcept(std::is_nothrow_constructible_v) : base_type(std::in_place, std::forward(value)) { } template constexpr explicit Expected(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v) : base_type(std::in_place, std::forward(args)...) { } template constexpr explicit Expected(std::in_place_t, std::initializer_list ilist, Args&&... args) noexcept(std::is_nothrow_constructible_v, Args...>) : base_type(std::in_place, ilist, std::forward(args)...) { } template constexpr Expected(const Unexpected& u) noexcept(std::is_nothrow_constructible_v) : base_type(unexpect, u.value()) { } template constexpr Expected(Unexpected&& u) noexcept(std::is_nothrow_constructible_v) : base_type(unexpect, std::move(u.value())) { } template constexpr explicit Expected(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v) : base_type(unexpect, std::forward(args)...) { } template constexpr explicit Expected(UnexpectType, std::initializer_list ilist, Args&&... args) noexcept(std::is_nothrow_constructible_v, Args...>) : base_type(unexpect, ilist, std::forward(args)...) { } Expected& operator=(const Expected& other) { if (other.hasValue()) { assign(std::in_place, other.value()); } else { assign(unexpect, other.error()); } return *this; } Expected& operator=(Expected&& other) noexcept { if (other.hasValue()) { assign(std::in_place, std::move(other.value())); } else { assign(unexpect, std::move(other.error())); } return *this; } template >::value && !is_unexpected>::value, int> = 0> Expected& operator=(U&& value) { assign(std::in_place, std::forward(value)); return *this; } template Expected& operator=(const Unexpected& u) { assign(unexpect, u.value()); return *this; } template Expected& operator=(Unexpected&& u) { assign(unexpect, std::move(u.value())); return *this; } template T& emplace(Args&&... args) noexcept(noexcept(std::declval().assign(std::in_place, std::forward(args)...))) { return assign(std::in_place, std::forward(args)...); } template T& emplace(std::initializer_list ilist, Args&&... args) noexcept(noexcept(std::declval().assign(std::in_place, ilist, std::forward(args)...))) { return assign(std::in_place, ilist, std::forward(args)...); } void swap(Expected& other) noexcept(detail::is_nothrow_swappable::value && detail::is_nothrow_swappable::value) { using std::swap; if (hasValue()) { if (other.hasValue()) { swap(value(), other.value()); } else { E error = std::move(other.error()); other.assign(std::in_place, std::move(value())); assign(unexpect, std::move(error)); } } else { if (other.hasValue()) { other.swap(*this); } else { swap(error(), other.error()); } } } constexpr const T* operator->() const { return base_type::valuePtr(); } constexpr T* operator->() { return base_type::valuePtr(); } constexpr const T& operator*() const& { return value(); } constexpr T& operator*() & { return value(); } constexpr const T&& operator*() const&& { return std::move(value()); } constexpr T&& operator*() && { return std::move(value()); } constexpr explicit operator bool() const noexcept { return hasValue(); } constexpr bool hasValue() const noexcept { return base_type::valid(); } constexpr const T& value() const& LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { #if LUABRIDGE_HAS_EXCEPTIONS if (!hasValue()) throw BadExpectedAccess(error()); #endif return base_type::value(); } constexpr T& value() & LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { #if LUABRIDGE_HAS_EXCEPTIONS if (!hasValue()) throw BadExpectedAccess(error()); #endif return base_type::value(); } constexpr const T&& value() const&& LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { #if LUABRIDGE_HAS_EXCEPTIONS if (!hasValue()) throw BadExpectedAccess(error()); #endif return std::move(base_type::value()); } constexpr T&& value() && LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { #if LUABRIDGE_HAS_EXCEPTIONS if (!hasValue()) throw BadExpectedAccess(error()); #endif return std::move(base_type::value()); } constexpr const E& error() const& noexcept { return base_type::error(); } constexpr E& error() & noexcept { return base_type::error(); } constexpr const E&& error() const&& noexcept { return std::move(base_type::error()); } constexpr E&& error() && noexcept { return std::move(base_type::error()); } template constexpr T valueOr(U&& defaultValue) const& { return hasValue() ? value() : static_cast(std::forward(defaultValue)); } template T valueOr(U&& defaultValue) && { return hasValue() ? std::move(value()) : static_cast(std::forward(defaultValue)); } private: template auto assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval().destroy()) && noexcept(std::declval().construct(tag, std::forward(args)...))) -> decltype(std::declval().construct(tag, std::forward(args)...)) { this->destroy(); return this->construct(tag, std::forward(args)...); } }; template class Expected : public detail::expected_base, std::is_move_constructible_v> { static_assert(!std::is_reference_v && !std::is_void_v, "Unexpected type can't be a reference or void"); using base_type = detail::expected_base, std::is_move_constructible_v>; using this_type = Expected; public: using value_type = void; using error_type = E; using unexpected_type = Unexpected; template struct rebind { using type = Expected; }; constexpr Expected() = default; constexpr Expected(const Expected& other) = default; constexpr Expected(Expected&& other) = default; template Expected(const Expected& other) { if (other.hasValue()) { this->valid_ = true; } else { this->construct(unexpect, other.error()); } } template Expected(Expected&& other) { if (other.hasValue()) { this->valid_ = true; } else { this->construct(unexpect, std::move(other.error())); } } template constexpr Expected(const Unexpected& u) : base_type(unexpect, u.value()) { } template constexpr Expected(Unexpected&& u) : base_type(unexpect, std::move(u.value())) { } template constexpr explicit Expected(UnexpectType, Args&&... args) : base_type(unexpect, std::forward(args)...) { } template constexpr explicit Expected(UnexpectType, std::initializer_list ilist, Args&&... args) : base_type(unexpect, ilist, std::forward(args)...) { } Expected& operator=(const Expected& other) { if (other.hasValue()) { assign(std::in_place); } else { assign(unexpect, other.error()); } return *this; } Expected& operator=(Expected&& other) { if (other.hasValue()) { assign(std::in_place); } else { assign(unexpect, std::move(other.error())); } return *this; } template Expected& operator=(const Unexpected& u) { assign(unexpect, u.value()); return *this; } template Expected& operator=(Unexpected&& u) { assign(unexpect, std::move(u.value())); return *this; } void swap(Expected& other) noexcept(detail::is_nothrow_swappable::value) { using std::swap; if (hasValue()) { if (!other.hasValue()) { assign(unexpect, std::move(other.error())); other.assign(std::in_place); } } else { if (other.hasValue()) { other.swap(*this); } else { swap(error(), other.error()); } } } constexpr explicit operator bool() const noexcept { return hasValue(); } constexpr bool hasValue() const noexcept { return base_type::valid(); } constexpr const E& error() const& noexcept { return base_type::error(); } constexpr E& error() & noexcept { return base_type::error(); } constexpr const E&& error() const&& noexcept { return std::move(base_type::error()); } constexpr E&& error() && noexcept { return std::move(base_type::error()); } private: template void assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval().destroy()) && noexcept(std::declval().construct(tag, std::forward(args)...))) { this->destroy(); this->construct(tag, std::forward(args)...); } }; template constexpr bool operator==(const Expected& lhs, const Expected& rhs) { return (lhs && rhs) ? *lhs == *rhs : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false); } template constexpr bool operator==(const Expected& lhs, const Expected& rhs) { return (lhs && rhs) ? true : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false); } template constexpr bool operator!=(const Expected& lhs, const Expected& rhs) { return !(lhs == rhs); } template constexpr bool operator==(const Expected& lhs, const T& rhs) { return lhs ? *lhs == rhs : false; } template constexpr bool operator==(const T& lhs, const Expected& rhs) { return rhs == lhs; } template constexpr bool operator!=(const Expected& lhs, const T& rhs) { return !(lhs == rhs); } template constexpr bool operator!=(const T& lhs, const Expected& rhs) { return rhs != lhs; } template constexpr bool operator==(const Expected& lhs, const Unexpected& rhs) { return lhs ? false : lhs.error() == rhs.value(); } template constexpr bool operator==(const Unexpected& lhs, const Expected& rhs) { return rhs == lhs; } template constexpr bool operator!=(const Expected& lhs, const Unexpected& rhs) { return !(lhs == rhs); } template constexpr bool operator!=(const Unexpected& lhs, const Expected& rhs) { return rhs != lhs; } } // End File: Source/LuaBridge/detail/Expected.h // Begin File: Source/LuaBridge/detail/Result.h namespace luabridge { struct Result { Result() noexcept = default; Result(std::error_code ec) noexcept : m_ec(ec) { } Result(const Result&) noexcept = default; Result(Result&&) noexcept = default; Result& operator=(const Result&) noexcept = default; Result& operator=(Result&&) noexcept = default; explicit operator bool() const noexcept { return !m_ec; } std::error_code error() const noexcept { return m_ec; } operator std::error_code() const noexcept { return m_ec; } std::string message() const { return m_ec.message(); } #if LUABRIDGE_HAS_EXCEPTIONS void throw_on_error() const { if (m_ec) throw std::system_error(m_ec); } #endif private: std::error_code m_ec; }; template struct TypeResult { TypeResult() noexcept = default; template && !std::is_same_v, std::error_code>>> TypeResult(U&& value) noexcept : m_value(std::in_place, std::forward(value)) { } TypeResult(std::error_code ec) noexcept : m_value(makeUnexpected(ec)) { } TypeResult(const TypeResult&) = default; TypeResult(TypeResult&&) = default; TypeResult& operator=(const TypeResult&) = default; TypeResult& operator=(TypeResult&&) = default; explicit operator bool() const noexcept { return m_value.hasValue(); } const T& value() const { return m_value.value(); } T& operator*() & { return m_value.value(); } T operator*() && { return std::move(m_value.value()); } const T& operator*() const& { return m_value.value(); } T operator*() const&& { return std::move(m_value.value()); } template T valueOr(U&& defaultValue) const& { return m_value.valueOr(std::forward(defaultValue)); } template T valueOr(U&& defaultValue) && { return m_value.valueOr(std::forward(defaultValue)); } std::error_code error() const { return m_value.error(); } operator std::error_code() const { return m_value.error(); } std::string message() const { return m_value.error().message(); } #if LUABRIDGE_HAS_EXCEPTIONS void throw_on_error() const { if (! m_value.hasValue()) throw std::system_error(m_value.error()); } #endif private: Expected m_value; }; template inline bool operator==(const TypeResult& lhs, const U& rhs) noexcept { return lhs ? *lhs == rhs : false; } template inline bool operator==(const U& lhs, const TypeResult& rhs) noexcept { return rhs == lhs; } template inline bool operator!=(const TypeResult& lhs, const U& rhs) noexcept { return !(lhs == rhs); } template inline bool operator!=(const U& lhs, const TypeResult& rhs) noexcept { return !(rhs == lhs); } } // End File: Source/LuaBridge/detail/Result.h // Begin File: Source/LuaBridge/detail/ClassInfo.h #if defined __clang__ || defined __GNUC__ #define LUABRIDGE_PRETTY_FUNCTION __PRETTY_FUNCTION__ #define LUABRIDGE_PRETTY_FUNCTION_PREFIX '=' #define LUABRIDGE_PRETTY_FUNCTION_SUFFIX ']' #elif defined _MSC_VER #define LUABRIDGE_PRETTY_FUNCTION __FUNCSIG__ #define LUABRIDGE_PRETTY_FUNCTION_PREFIX '<' #define LUABRIDGE_PRETTY_FUNCTION_SUFFIX '>' #endif namespace luabridge { namespace detail { [[nodiscard]] constexpr auto fnv1a(const char* s, std::size_t count) noexcept { uint32_t seed = 2166136261u; for (std::size_t i = 0; i < count; ++i) seed = static_cast(static_cast(seed ^ static_cast(*s++)) * 16777619u); if constexpr (sizeof(void*) == 8) return static_cast(seed); else return seed; } template [[nodiscard]] static constexpr auto typeName(T* = nullptr) noexcept { constexpr std::string_view prettyName{ LUABRIDGE_PRETTY_FUNCTION }; constexpr auto first = prettyName.find_first_not_of(' ', prettyName.find_first_of(LUABRIDGE_PRETTY_FUNCTION_PREFIX) + 1); return prettyName.substr(first, prettyName.find_last_of(LUABRIDGE_PRETTY_FUNCTION_SUFFIX) - first); } template ().find_first_of('.')> [[nodiscard]] static constexpr auto typeHash(T* = nullptr) noexcept { constexpr auto stripped = typeName(); return fnv1a(stripped.data(), stripped.size()); } [[nodiscard]] inline void* getExceptionsKey() noexcept { return reinterpret_cast(0xc7); } [[nodiscard]] inline const void* getTypeKey() noexcept { return reinterpret_cast(0x71); } [[nodiscard]] inline const void* getConstKey() noexcept { return reinterpret_cast(0xc07); } [[nodiscard]] inline const void* getClassKey() noexcept { return reinterpret_cast(0xc1a); } [[nodiscard]] inline const void* getClassOptionsKey() noexcept { return reinterpret_cast(0xc2b); } [[nodiscard]] inline const void* getPropgetKey() noexcept { return reinterpret_cast(0x6e7); } [[nodiscard]] inline const void* getPropsetKey() noexcept { return reinterpret_cast(0x5e7); } [[nodiscard]] inline const void* getStaticKey() noexcept { return reinterpret_cast(0x57a); } [[nodiscard]] inline const void* getParentKey() noexcept { return reinterpret_cast(0xdad); } [[nodiscard]] inline const void* getIndexFallbackKey() { return reinterpret_cast(0x81ca); } [[nodiscard]] inline const void* getIndexExtensibleKey() { return reinterpret_cast(0x81cb); } [[nodiscard]] inline const void* getNewIndexFallbackKey() { return reinterpret_cast(0x8107); } [[nodiscard]] inline const void* getNewIndexExtensibleKey() { return reinterpret_cast(0x8108); } template [[nodiscard]] const void* getStaticRegistryKey() noexcept { static auto value = typeHash(); return reinterpret_cast(value); } template [[nodiscard]] const void* getClassRegistryKey() noexcept { static auto value = typeHash() ^ 1; return reinterpret_cast(value); } template [[nodiscard]] const void* getConstRegistryKey() noexcept { static auto value = typeHash() ^ 2; return reinterpret_cast(value); } } } // End File: Source/LuaBridge/detail/ClassInfo.h // Begin File: Source/LuaBridge/detail/LuaException.h namespace luabridge { class LuaException : public std::exception { public: LuaException(lua_State* L, std::error_code code) : m_L(L) , m_code(code) { } ~LuaException() noexcept override { } const char* what() const noexcept override { return m_what.c_str(); } static void raise(lua_State* L, std::error_code code) { LUABRIDGE_ASSERT(areExceptionsEnabled(L)); #if LUABRIDGE_HAS_EXCEPTIONS throw LuaException(L, code, FromLua{}); #else unused(L, code); std::abort(); #endif } static bool areExceptionsEnabled(lua_State* L) noexcept { lua_pushlightuserdata(L, detail::getExceptionsKey()); lua_gettable(L, LUA_REGISTRYINDEX); const bool enabled = lua_isboolean(L, -1) ? static_cast(lua_toboolean(L, -1)) : false; lua_pop(L, 1); return enabled; } static void enableExceptions(lua_State* L) noexcept { lua_pushlightuserdata(L, detail::getExceptionsKey()); lua_pushboolean(L, true); lua_settable(L, LUA_REGISTRYINDEX); #if LUABRIDGE_HAS_EXCEPTIONS && LUABRIDGE_ON_LUAJIT lua_pushlightuserdata(L, (void*)luajitWrapperCallback); luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); lua_pop(L, 1); #endif #if LUABRIDGE_ON_LUAU auto callbacks = lua_callbacks(L); callbacks->panic = +[](lua_State* L, int) { panicHandlerCallback(L); }; #else lua_atpanic(L, panicHandlerCallback); #endif } lua_State* state() const { return m_L; } private: struct FromLua {}; LuaException(lua_State* L, std::error_code code, FromLua) : m_L(L) , m_code(code) { whatFromStack(); } void whatFromStack() { std::stringstream ss; const char* errorText = nullptr; if (lua_gettop(m_L) > 0) { errorText = lua_tostring(m_L, -1); lua_pop(m_L, 1); } ss << (errorText ? errorText : "Unknown error") << " (code=" << m_code.message() << ")"; m_what = std::move(ss).str(); } static int panicHandlerCallback(lua_State* L) { #if LUABRIDGE_HAS_EXCEPTIONS throw LuaException(L, makeErrorCode(ErrorCode::LuaFunctionCallFailed), FromLua{}); #else unused(L); std::abort(); #endif } #if LUABRIDGE_HAS_EXCEPTIONS && LUABRIDGE_ON_LUAJIT static int luajitWrapperCallback(lua_State* L, lua_CFunction f) { try { return f(L); } catch (const std::exception& e) { lua_pushstring(L, e.what()); return lua_error_x(L); } } #endif lua_State* m_L = nullptr; std::error_code m_code; std::string m_what; }; inline void enableExceptions(lua_State* L) noexcept { #if LUABRIDGE_HAS_EXCEPTIONS LuaException::enableExceptions(L); #else unused(L); LUABRIDGE_ASSERT(false); #endif } } // End File: Source/LuaBridge/detail/LuaException.h // Begin File: Source/LuaBridge/detail/TypeTraits.h namespace luabridge { namespace detail { template