// https://github.com/kunitoki/LuaBridge3 // Copyright 2026, kunitoki // 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 #include #include #include #include #include #include #include #include #include #include #if defined(__has_include) && __has_include() #include #endif #if defined(__has_include) && __has_include() && (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) #include #endif #if defined(__has_include) && __has_include() && (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) #include #endif #if defined(__has_include) && __has_include() && (__cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L)) #include #endif #if defined(__has_include) && __has_include() && (__cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L)) #include #endif #if defined(__has_include) && __has_include() && (__cplusplus >= 202302L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202302L)) #include #endif #if defined(__has_include) && __has_include() && (__cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)) #include #endif // Begin File: Source/LuaBridge/detail/Config.h #if __has_include() #endif #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 __cplusplus >= 202302L || (defined(_MSC_VER) && _HAS_CXX23) #define LUABRIDGE_CXX23_OR_GREATER 1 #elif __cplusplus >= 202002L || (defined(_MSC_VER) && _HAS_CXX20) #define LUABRIDGE_CXX20_OR_GREATER 1 #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(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(__clang__) || defined(__GNUC__) #define LUABRIDGE_NO_SANITIZE(x) __attribute__((no_sanitize(x))) #else #define LUABRIDGE_NO_SANITIZE(x) #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_STRICT_STACK_CONVERSIONS) #define LUABRIDGE_STRICT_STACK_CONVERSIONS 0 #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 #if !defined(LUABRIDGE_HAS_CXX17_FILESYSTEM) #if !defined(LUABRIDGE_DISABLE_CXX17_FILESYSTEM) && __has_include() && defined(__cpp_lib_filesystem) #define LUABRIDGE_HAS_CXX17_FILESYSTEM 1 #else #define LUABRIDGE_HAS_CXX17_FILESYSTEM 0 #endif #endif #if !defined(LUABRIDGE_HAS_CXX17_ANY) #if !defined(LUABRIDGE_DISABLE_CXX17_ANY) && __has_include() && defined(__cpp_lib_any) #define LUABRIDGE_HAS_CXX17_ANY 1 #else #define LUABRIDGE_HAS_CXX17_ANY 0 #endif #endif #if !defined(LUABRIDGE_HAS_CXX20_SPAN) #if !defined(LUABRIDGE_DISABLE_CXX20_SPAN) && LUABRIDGE_CXX20_OR_GREATER && __has_include() && defined(__cpp_lib_span) #define LUABRIDGE_HAS_CXX20_SPAN 1 #else #define LUABRIDGE_HAS_CXX20_SPAN 0 #endif #endif #if !defined(LUABRIDGE_HAS_CXX20_RANGES) #if !defined(LUABRIDGE_DISABLE_CXX20_RANGES) && LUABRIDGE_CXX20_OR_GREATER && defined(__cpp_lib_ranges) #define LUABRIDGE_HAS_CXX20_RANGES 1 #else #define LUABRIDGE_HAS_CXX20_RANGES 0 #endif #endif #if !defined(LUABRIDGE_HAS_CXX20_COROUTINES) #if !defined(LUABRIDGE_DISABLE_CXX20_COROUTINES) && LUABRIDGE_CXX20_OR_GREATER && !(LUABRIDGE_ON_LUAU || LUABRIDGE_ON_LUAJIT || LUABRIDGE_ON_RAVI || LUA_VERSION_NUM < 502) #define LUABRIDGE_HAS_CXX20_COROUTINES 1 #else #define LUABRIDGE_HAS_CXX20_COROUTINES 0 #endif #endif #if !defined(LUABRIDGE_HAS_CXX23_EXPECTED) #if !defined(LUABRIDGE_DISABLE_CXX23_EXPECTED) && LUABRIDGE_CXX23_OR_GREATER && __has_include() && defined(__cpp_lib_expected) #define LUABRIDGE_HAS_CXX23_EXPECTED 1 #else #define LUABRIDGE_HAS_CXX23_EXPECTED 0 #endif #endif #if !defined(LUABRIDGE_HAS_CXX23_FLAT_CONTAINERS) #if !defined(LUABRIDGE_DISABLE_CXX23_FLAT_CONTAINERS) && LUABRIDGE_CXX23_OR_GREATER && __has_include() && __has_include() && defined(__cpp_lib_flat_map) #define LUABRIDGE_HAS_CXX23_FLAT_CONTAINERS 1 #else #define LUABRIDGE_HAS_CXX23_FLAT_CONTAINERS 0 #endif #endif #if !defined(LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION) #if !defined(LUABRIDGE_DISABLE_CXX23_MOVE_ONLY_FUNCTION) && LUABRIDGE_CXX23_OR_GREATER && defined(__cpp_lib_move_only_function) #define LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION 1 #else #define LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION 0 #endif #endif // End File: Source/LuaBridge/detail/Config.h // Begin File: Source/LuaBridge/detail/FuncTraits.h namespace luabridge { namespace detail { [[noreturn]] inline void unreachable() { #if defined(__GNUC__) __builtin_unreachable(); #elif defined(_MSC_VER) __assume(false); #endif } template< class T > struct remove_cvref { typedef std::remove_cv_t> type; }; template using remove_cvref_t = typename remove_cvref::type; template struct function_traits_base { using result_type = R; using argument_types = std::tuple; static constexpr auto arity = sizeof...(Args); static constexpr auto is_member = IsMember; static constexpr auto is_const = IsConst; }; template struct function_traits_impl; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; #if defined(_MSC_VER) && defined(_M_IX86) inline static constexpr bool is_stdcall_default_calling_convention = std::is_same_v; inline static constexpr bool is_fastcall_default_calling_convention = std::is_same_v; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; template struct function_traits_impl : function_traits_base { }; #endif template struct has_call_operator : std::false_type { }; template struct has_call_operator> : std::true_type { }; template inline static constexpr bool has_call_operator_v = has_call_operator::value; template struct is_move_only_function : std::false_type {}; #if LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION template struct is_move_only_function> : std::true_type {}; template struct is_move_only_function> : std::true_type {}; template struct is_move_only_function> : std::true_type {}; template struct is_move_only_function> : std::true_type {}; #endif template inline static constexpr bool is_move_only_function_v = is_move_only_function::value; template struct functor_traits_impl { }; template struct functor_traits_impl>> : function_traits_impl { }; template struct functor_traits_impl && std::is_invocable_v && !is_move_only_function_v>> : function_traits_base> { }; #if LUABRIDGE_HAS_CXX23_MOVE_ONLY_FUNCTION template struct functor_traits_impl> : function_traits_base { }; template struct functor_traits_impl> : function_traits_base { }; template struct functor_traits_impl> : function_traits_base { }; template struct functor_traits_impl> : function_traits_base { }; #endif template struct function_traits : std::conditional_t, detail::functor_traits_impl, detail::function_traits_impl> { }; template , class = void> struct has_function_traits : std::false_type { }; template struct has_function_traits::result_type, typename function_traits::argument_types>> : std::true_type { }; template inline static constexpr bool has_function_traits_v = has_function_traits::value; template struct function_argument_or_void { using type = void; }; template struct function_argument_or_void::argument_types>>> { using type = std::tuple_element_t::argument_types>; }; template using function_argument_or_void_t = typename function_argument_or_void::type; template using function_result_t = typename function_traits::result_type; template using function_argument_t = std::tuple_element_t::argument_types>; template using function_arguments_t = typename function_traits::argument_types; template static constexpr std::size_t function_arity_v = function_traits::arity; template static constexpr bool function_is_member_v = function_traits::is_member; template static constexpr bool function_is_const_v = function_traits::is_const; template struct is_callable { static constexpr bool value = false; }; template struct is_callable> { static constexpr bool value = true; }; template struct is_callable && !has_call_operator_v && has_function_traits_v>> { static constexpr bool value = true; }; template struct is_callable && std::is_function_v>>> { static constexpr bool value = true; }; template struct is_callable>> { static constexpr bool value = true; }; template inline static constexpr bool is_callable_v = is_callable::value; template struct is_const_member_function_pointer { static constexpr bool value = false; }; template struct is_const_member_function_pointer { static constexpr bool value = false; }; template struct is_const_member_function_pointer { static constexpr bool value = true; }; template struct is_const_member_function_pointer { static constexpr bool value = false; }; template struct is_const_member_function_pointer { static constexpr bool value = true; }; template inline static constexpr bool is_const_member_function_pointer_v = is_const_member_function_pointer::value; template struct is_cfunction_pointer { static constexpr bool value = false; }; template <> struct is_cfunction_pointer { static constexpr bool value = true; }; template inline static constexpr bool is_cfunction_pointer_v = is_cfunction_pointer::value; template struct is_member_cfunction_pointer { static constexpr bool value = false; }; template struct is_member_cfunction_pointer { static constexpr bool value = true; }; template struct is_member_cfunction_pointer { static constexpr bool value = true; }; template inline static constexpr bool is_member_cfunction_pointer_v = is_member_cfunction_pointer::value; template struct is_const_member_cfunction_pointer { static constexpr bool value = false; }; template struct is_const_member_cfunction_pointer { static constexpr bool value = false; }; template struct is_const_member_cfunction_pointer { static constexpr bool value = true; }; template inline static constexpr bool is_const_member_cfunction_pointer_v = is_const_member_cfunction_pointer::value; template inline static constexpr bool is_any_cfunction_pointer_v = is_cfunction_pointer_v || is_member_cfunction_pointer_v; template inline static constexpr bool is_proxy_member_function_v = !std::is_member_function_pointer_v && std::is_same_v>>>; template inline static constexpr bool is_const_proxy_function_v = is_proxy_member_function_v && std::is_const_v>>>; template struct function_arity_excluding { }; template < class... Ts, class ExclusionType> struct function_arity_excluding, ExclusionType> : std::integral_constant, ExclusionType> ? 0 : 1))> { }; template inline static constexpr std::size_t function_arity_excluding_v = function_arity_excluding, ExclusionType>::value; template struct member_function_arity_excluding { }; template struct member_function_arity_excluding, ExclusionType, std::enable_if_t>> : std::integral_constant, ExclusionType> ? 0 : 1))> { }; template struct member_function_arity_excluding, ExclusionType, std::enable_if_t>> : std::integral_constant, ExclusionType> ? 0 : 1)) - 1> { }; template inline static constexpr std::size_t member_function_arity_excluding_v = member_function_arity_excluding, ExclusionType>::value; template static constexpr bool is_const_function = detail::is_const_member_function_pointer_v || (detail::function_arity_v > 0 && detail::is_const_proxy_function_v); template inline static constexpr std::size_t const_functions_count = (0 + ... + (is_const_function ? 1 : 0)); template inline static constexpr std::size_t non_const_functions_count = (0 + ... + (is_const_function ? 0 : 1)); template constexpr auto tupleize(Types&&... types) { return std::tuple(std::forward(types)...); } template struct remove_first_type { }; template struct remove_first_type> { using type = std::tuple; }; template using remove_first_type_t = typename remove_first_type::type; template struct tuple_drop_first { using type = typename tuple_drop_first>::type; }; template struct tuple_drop_first<0, Tuple> { using type = Tuple; }; template using tuple_drop_first_t = typename tuple_drop_first::type; template struct tuple_prepend; template struct tuple_prepend> { using type = std::tuple; }; template using tuple_prepend_t = typename tuple_prepend::type; template > struct tuple_take_first_impl { using type = Accum; }; template struct tuple_take_first_impl, std::tuple> { using type = typename tuple_take_first_impl, std::tuple>::type; }; template struct tuple_take_first_impl<0, std::tuple, std::tuple> { using type = std::tuple; }; template using tuple_take_first_t = typename tuple_take_first_impl::type; template struct member_function_class; template struct member_function_class { using type = C; }; template struct member_function_class { using type = const C; }; template struct member_function_class { using type = C; }; template struct member_function_class { using type = const C; }; template using member_function_class_t = typename member_function_class::type; template struct bind_back_leading_impl { using type = ExplicitRemaining; }; template struct bind_back_leading_impl { using type = tuple_prepend_t*, ExplicitRemaining>; }; template using bind_back_leading_t = typename bind_back_leading_impl>::type; template struct bind_front_wrapper; template struct bind_front_wrapper, Fn, BoundArgs...> { Fn fn_; std::tuple bound_; template bind_front_wrapper(F&& f, BA&&... ba) : fn_(std::forward(f)), bound_(std::forward(ba)...) { } R operator()(Remaining... args) const { return std::apply([&](const auto&... ba) { return std::invoke(fn_, ba..., args...); }, bound_); } }; } template auto bind_front(F&& f, BoundArgs&&... args) { using Fn = std::decay_t; using FnTraits = detail::function_traits; static constexpr std::size_t skip = std::is_member_function_pointer_v ? 1u : 0u; static constexpr std::size_t num_effective_bound = sizeof...(BoundArgs) - skip; using remaining = detail::tuple_drop_first_t; using R = typename FnTraits::result_type; return detail::bind_front_wrapper...>( std::forward(f), std::forward(args)...); } namespace detail { template struct bind_back_wrapper; template struct bind_back_wrapper, Fn, BoundArgs...> { Fn fn_; std::tuple bound_; template bind_back_wrapper(F&& f, BA&&... ba) : fn_(std::forward(f)), bound_(std::forward(ba)...) { } R operator()(Leading... args) const { return std::apply([&](const auto&... ba) { return std::invoke(fn_, args..., ba...); }, bound_); } }; } template auto bind_back(F&& f, BoundArgs&&... args) { using Fn = std::decay_t; using FnTraits = detail::function_traits; static constexpr std::size_t num_explicit = FnTraits::arity; static constexpr std::size_t num_bound = sizeof...(BoundArgs); static constexpr std::size_t num_remaining = num_explicit - num_bound; using explicit_remaining = detail::tuple_take_first_t; using leading = detail::bind_back_leading_t; using R = typename FnTraits::result_type; return detail::bind_back_wrapper...>( std::forward(f), std::forward(args)...); } } // End File: Source/LuaBridge/detail/FuncTraits.h // Begin File: Source/LuaBridge/detail/LuaHelpers.h namespace luabridge { template constexpr void unused(Args&&...) { } #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 #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) { return static_cast(lua_rawlen(L, idx)); } #endif #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); } [[noreturn]] inline void lua_error_x(lua_State* L) { lua_error(L); } 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); } inline int lua_rawgetp_x(lua_State* L, int idx, void* p) { return lua_rawgetp(L, idx, p); } inline void lua_rawsetp_x(lua_State* L, int idx, void* p) { lua_rawsetp(L, idx, p); } #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); } [[noreturn]] inline void lua_error_x(lua_State* L) { lua_error(L); detail::unreachable(); } 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); } inline int lua_rawgetp_x(lua_State* L, int idx, void* p) { #if LUA_VERSION_NUM < 503 idx = lua_absindex(L, idx); luaL_checkstack(L, 1, "not enough stack slots"); lua_pushlightuserdata(L, p); lua_rawget(L, idx); return lua_type(L, -1); #else return lua_rawgetp(L, idx, p); #endif } inline void lua_rawsetp_x(lua_State* L, int idx, void* p) { #if LUA_VERSION_NUM < 503 idx = lua_absindex(L, idx); luaL_checkstack(L, 1, "not enough stack slots"); lua_pushlightuserdata(L, p); lua_insert(L, -2); lua_rawset(L, idx); #else lua_rawsetp(L, idx, p); #endif } #endif #if LUA_VERSION_NUM < 505 inline lua_State* lua_newstate_x(lua_Alloc f, void* ud, [[maybe_unused]] unsigned seed) { return lua_newstate(f, ud); } #else inline lua_State* lua_newstate_x(lua_Alloc f, void* ud, unsigned seed) { return lua_newstate(f, ud, seed); } #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) { if (n < static_cast(std::numeric_limits::min()) || n >= -static_cast(std::numeric_limits::min())) { if (isnum) *isnum = 0; return 0; } 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 inline int lua_rawgetp_x(lua_State* L, int idx, const void* p) { return lua_rawgetp_x(L, idx, const_cast(p)); } inline void lua_rawsetp_x(lua_State* L, int idx, const void* p) { lua_rawsetp_x(L, idx, const_cast(p)); } #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; } [[noreturn]] inline void 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] == '[') 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); 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; } else if constexpr (std::is_unsigned_v) { return value <= static_cast((std::numeric_limits::max)()); } else { return value >= static_cast((std::numeric_limits::min)()) && static_cast(value) <= (std::numeric_limits::max)(); } } else if constexpr (sizeof(T) < sizeof(U)) { return static_cast(value) >= (std::numeric_limits::min)() && static_cast(value) <= (std::numeric_limits::max)(); } else if constexpr (std::is_unsigned_v) { return value <= static_cast((std::numeric_limits::max)()); } else { 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 bool is_floating_point_representable_by(T value) { if constexpr (sizeof(T) == sizeof(U)) { return true; } else if constexpr (sizeof(T) < sizeof(U)) { if (std::isnan(value) || std::isinf(value)) return true; return static_cast(value) >= -(std::numeric_limits::max)() && static_cast(value) <= (std::numeric_limits::max)(); } else { if (std::isnan(value) || std::isinf(value)) return true; 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; } inline int lua_resume_x(lua_State* L, lua_State* from, int nargs, int* nresults = nullptr) { #if LUABRIDGE_ON_LUAJIT || LUA_VERSION_NUM == 501 unused(from); int status = lua_resume(L, nargs); if (nresults) *nresults = lua_gettop(L); return status; #elif LUABRIDGE_ON_LUAU || LUABRIDGE_ON_RAVI || LUA_VERSION_NUM < 504 int status = lua_resume(L, from, nargs); if (nresults) *nresults = lua_gettop(L); return status; #else int nr = 0; int status = lua_resume(L, from, nargs, &nr); if (nresults) *nresults = nr; return status; #endif } inline bool lua_isyieldable_x(lua_State* L) { #if LUABRIDGE_ON_LUAJIT || LUA_VERSION_NUM == 501 || LUABRIDGE_ON_LUAU unused(L); return false; #elif LUA_VERSION_NUM < 503 unused(L); return true; #else return lua_isyieldable(L) != 0; #endif } } // 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, CoroutineYieldFromNonCoroutine, CoroutineAlreadyDone }; namespace detail { struct ErrorCategory : std::error_category { const char* name() const noexcept override { return "luabridge"; } std::string message(int ev) const override { return errorString(ev); } static const char* errorString(int ev) noexcept { 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"; case ErrorCode::CoroutineYieldFromNonCoroutine: return "Cannot yield from a non-coroutine Lua state"; case ErrorCode::CoroutineAlreadyDone: return "The Lua coroutine has already finished execution"; 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 namespace detail { template inline void throw_bad_expected_access_or_abort(E e) { #if LUABRIDGE_HAS_EXCEPTIONS throw BadExpectedAccess(std::move(e)); #else std::abort(); #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 (!hasValue()) detail::throw_bad_expected_access_or_abort(std::move(error())); return base_type::value(); } constexpr T& value() & LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { if (!hasValue()) detail::throw_bad_expected_access_or_abort(std::move(error())); return base_type::value(); } constexpr const T&& value() const&& LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { if (!hasValue()) detail::throw_bad_expected_access_or_abort(std::move(error())); return std::move(base_type::value()); } constexpr T&& value() && LUABRIDGE_IF_NO_EXCEPTIONS(noexcept) { if (!hasValue()) detail::throw_bad_expected_access_or_abort(std::move(error())); 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; } const char* error_cstr() const noexcept { return detail::ErrorCategory::errorString(m_ec.value()); } 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()); } T* operator->() { return &m_value.value(); } const T* operator->() const { return &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(); } const char* error_cstr() const noexcept { return detail::ErrorCategory::errorString(m_value.error().value()); } 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 <> struct TypeResult { TypeResult() noexcept = default; TypeResult(std::error_code ec) noexcept : m_ec(ec) { } TypeResult(const TypeResult&) noexcept = default; TypeResult(TypeResult&&) noexcept = default; TypeResult& operator=(const TypeResult&) noexcept = default; TypeResult& operator=(TypeResult&&) noexcept = default; explicit operator bool() const noexcept { return ! m_ec; } void value() const noexcept { } std::error_code error() const noexcept { return m_ec; } const char* error_cstr() const noexcept { return detail::ErrorCategory::errorString(m_ec.value()); } 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 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* getTypeIdentityKey() noexcept { return reinterpret_cast(0xc2c); } [[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* getCastTableKey() noexcept { return reinterpret_cast(0xca57); } [[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); } [[nodiscard]] inline const void* getConvertersKey() noexcept { return reinterpret_cast(0xc0de); } [[nodiscard]] inline const void* getStaticIndexFallbackKey() { return reinterpret_cast(0x81cc); } [[nodiscard]] inline const void* getStaticNewIndexFallbackKey() { return reinterpret_cast(0x8109); } 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()); 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