fix: take handler for sol_lua_check as function reference (#6393)

* fix: take handler for `sol_lua_check` as function reference

* changelog

* fix: includes

* uintptr type

* fix: ub and eq
This commit is contained in:
nerix
2025-08-16 21:21:04 +02:00
committed by GitHub
parent d8aa2b2846
commit 0f11a9050a
6 changed files with 271 additions and 13 deletions
+8 -7
View File
@@ -40,7 +40,7 @@ void logError(Plugin *plugin, QStringView context, const QString &msg)
// NOLINTBEGIN(readability-named-parameter)
// QString
bool sol_lua_check(sol::types<QString>, lua_State *L, int index,
std::function<sol::check_handler_type> handler,
chatterino::FunctionRef<sol::check_handler_type> handler,
sol::stack::record &tracking)
{
return sol::stack::check<const char *>(L, index, handler, tracking);
@@ -60,7 +60,7 @@ int sol_lua_push(sol::types<QString>, lua_State *L, const QString &value)
// QStringList
bool sol_lua_check(sol::types<QStringList>, lua_State *L, int index,
std::function<sol::check_handler_type> handler,
chatterino::FunctionRef<sol::check_handler_type> handler,
sol::stack::record &tracking)
{
return sol::stack::check<sol::table>(L, index, handler, tracking);
@@ -92,7 +92,7 @@ int sol_lua_push(sol::types<QStringList>, lua_State *L,
// QByteArray
bool sol_lua_check(sol::types<QByteArray>, lua_State *L, int index,
std::function<sol::check_handler_type> handler,
chatterino::FunctionRef<sol::check_handler_type> handler,
sol::stack::record &tracking)
{
return sol::stack::check<const char *>(L, index, handler, tracking);
@@ -115,10 +115,11 @@ namespace chatterino::lua {
// ThisPluginState
bool sol_lua_check(sol::types<chatterino::lua::ThisPluginState>,
lua_State * /*L*/, int /* index*/,
std::function<sol::check_handler_type> /* handler*/,
sol::stack::record & /*tracking*/)
bool sol_lua_check(
sol::types<chatterino::lua::ThisPluginState>, lua_State * /*L*/,
int /* index*/,
chatterino::FunctionRef<sol::check_handler_type> /* handler*/,
sol::stack::record & /*tracking*/)
{
return true;
}
+8 -6
View File
@@ -1,5 +1,6 @@
#pragma once
#ifdef CHATTERINO_HAVE_PLUGINS
# include "util/FunctionRef.hpp"
# include "util/QMagicEnum.hpp"
# include "util/TypeName.hpp"
@@ -174,12 +175,13 @@ void loggedVoidCall(const auto &fn, QStringView context, Plugin *plugin,
}
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
# define SOL_STACK_FUNCTIONS(TYPE) \
bool sol_lua_check(sol::types<TYPE>, lua_State *L, int index, \
std::function<sol::check_handler_type> handler, \
sol::stack::record &tracking); \
TYPE sol_lua_get(sol::types<TYPE>, lua_State *L, int index, \
sol::stack::record &tracking); \
# define SOL_STACK_FUNCTIONS(TYPE) \
bool sol_lua_check( \
sol::types<TYPE>, lua_State *L, int index, \
chatterino::FunctionRef<sol::check_handler_type> handler, \
sol::stack::record &tracking); \
TYPE sol_lua_get(sol::types<TYPE>, lua_State *L, int index, \
sol::stack::record &tracking); \
int sol_lua_push(sol::types<TYPE>, lua_State *L, const TYPE &value);
SOL_STACK_FUNCTIONS(chatterino::lua::ThisPluginState)
+82
View File
@@ -0,0 +1,82 @@
#pragma once
#include <concepts>
#include <cstdint>
#include <type_traits>
#include <utility>
namespace chatterino {
/// A non-owning, type-erased reference to a callable. Callables can be lambdas,
/// functions, or std::functions.
///
/// It is intended to be used for functions taking a callback that is called
/// immediately (such as filter/map functions). Since this doesn't own the
/// callable, it's not safe to store.
///
/// This is based on llvm::function_ref (updated for C++ 20).
template <typename Fn>
class FunctionRef;
template <typename Ret, typename... Params>
class FunctionRef<Ret(Params...)>
{
public:
FunctionRef() = default;
FunctionRef(std::nullptr_t)
{
}
template <typename Callable>
FunctionRef(Callable &&callable) // NOLINT
requires
// This is not the copy-constructor.
(!std::same_as<std::remove_cvref_t<Callable>, FunctionRef>) &&
// Functor must be callable and return a suitable type.
(std::is_void_v<Ret> ||
std::convertible_to<
decltype(std::declval<Callable>()(std::declval<Params>()...)),
Ret>)
: callback(callTrampoline<std::remove_reference_t<Callable>>)
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
, callable(reinterpret_cast<uintptr_t>(&callable))
{
}
Ret operator()(Params... params) const
{
return this->callback(this->callable, std::forward<Params>(params)...);
}
explicit operator bool() const
{
return this->callback != nullptr;
}
bool operator==(const FunctionRef &other) const
{
return this->callback == other.callback &&
this->callable == other.callable;
}
bool operator!=(const FunctionRef &other) const = default;
private:
// same signature as callTrampoline
using Callback = Ret(uintptr_t, Params...);
/// Pointer to the call trampoline that, given the callable, calls the target function.
Callback *callback = nullptr;
/// Pointer to the actual function
uintptr_t callable = 0;
template <typename Callable>
static Ret callTrampoline(uintptr_t callable, Params... params)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return (*reinterpret_cast<Callable *>(callable))(
std::forward<Params>(params)...);
}
};
} // namespace chatterino