From 7ee008e150bc5bcf76082d726f719ee0fdfda982 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Wed, 11 Feb 2026 02:37:39 -0600 Subject: Fluorine Manager: full Linux port of Mod Organizer 2 Complete native Linux port with FUSE-based virtual filesystem, Proton/umu-run integration, and Flatpak packaging. Key features: - FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak) - Proton/GE-Proton/umu-run launcher with env var forwarding - Flatpak support (sandbox-aware VFS, NXM handler, umu-run) - Wine prefix management UI - Case-insensitive path resolution for Linux filesystems - QSettings-safe INI handling (avoids Bethesda INI corruption) - Portable instance support with auto-generated launcher scripts Co-Authored-By: Claude Opus 4.6 --- .../include/pybind11_utils/functional.h | 155 +++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 libs/plugin_python/src/pybind11-utils/include/pybind11_utils/functional.h (limited to 'libs/plugin_python/src/pybind11-utils/include/pybind11_utils/functional.h') diff --git a/libs/plugin_python/src/pybind11-utils/include/pybind11_utils/functional.h b/libs/plugin_python/src/pybind11-utils/include/pybind11_utils/functional.h new file mode 100644 index 0000000..8662d82 --- /dev/null +++ b/libs/plugin_python/src/pybind11-utils/include/pybind11_utils/functional.h @@ -0,0 +1,155 @@ +#ifndef PYTHON_PYBIND11_FUNCTIONAL_H +#define PYTHON_PYBIND11_FUNCTIONAL_H + +#include + +namespace mo2::python::detail { + + // check if the given function is valid for a C++ function with the + // given arity + // + bool has_compatible_arity(pybind11::function handle, std::size_t arity); + +} // namespace mo2::python::detail + +namespace pybind11::detail { + + // custom type_caster for std::function<> + // + // most of this is from pybind11 except that we also check arity of the function to + // allow overloaded function based on arity of argument + // + template + struct type_caster> { + using type = std::function; + using retval_type = + conditional_t::value, void_type, Return>; + using function_type = Return (*)(Args...); + + public: + bool load(handle src, bool convert) + { + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert + // mode): + if (!convert) { + return false; + } + return true; + } + + if (!isinstance(src)) { + return false; + } + + auto func = reinterpret_borrow(src); + + /* + When passing a C++ function as an argument to another C++ + function via Python, every function call would normally involve + a full C++ -> Python -> C++ roundtrip, which can be prohibitive. + Here, we try to at least detect the case where the function is + stateless (i.e. function pointer or lambda function without + captured variables), in which case the roundtrip can be avoided. + */ + if (auto cfunc = func.cpp_function()) { + auto* cfunc_self = PyCFunction_GET_SELF(cfunc.ptr()); + if (isinstance(cfunc_self)) { + auto c = reinterpret_borrow(cfunc_self); + auto* rec = (function_record*)c; + + while (rec != nullptr) { + if (rec->is_stateless && + same_type(typeid(function_type), + *reinterpret_cast( + rec->data[1]))) { + struct capture { + function_type f; + }; + value = ((capture*)&rec->data)->f; + return true; + } + rec = rec->next; + } + } + // PYPY segfaults here when passing builtin function like sum. + // Raising an fail exception here works to prevent the segfault, but + // only on gcc. See PR #1413 for full details + } + + // !MO2! - check arity + + if (!mo2::python::detail::has_compatible_arity(func, sizeof...(Args))) { + return false; + } + + // !MO2! - everything below is copy/paste from pybind11 + + // ensure GIL is held during functor destruction + struct func_handle { + function f; +#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17)) + // This triggers a syntax error under very special conditions (very + // weird indeed). + explicit +#endif + func_handle(function&& f_) noexcept + : f(std::move(f_)) + { + } + func_handle(const func_handle& f_) { operator=(f_); } + func_handle& operator=(const func_handle& f_) + { + gil_scoped_acquire acq; + f = f_.f; + return *this; + } + ~func_handle() + { + gil_scoped_acquire acq; + function kill_f(std::move(f)); + } + }; + + // to emulate 'move initialization capture' in C++11 + struct func_wrapper { + func_handle hfunc; + explicit func_wrapper(func_handle&& hf) noexcept : hfunc(std::move(hf)) + { + } + Return operator()(Args... args) const + { + gil_scoped_acquire acq; + object retval(hfunc.f(std::forward(args)...)); + return retval.template cast(); + } + }; + + value = func_wrapper(func_handle(std::move(func))); + return true; + } + + template + static handle cast(Func&& f_, return_value_policy policy, handle /* parent */) + { + if (!f_) { + return none().inc_ref(); + } + + auto result = f_.template target(); + if (result) { + return cpp_function(*result, policy).release(); + } + return cpp_function(std::forward(f_), policy).release(); + } + + PYBIND11_TYPE_CASTER(type, const_name("Callable[[") + + concat(make_caster::name...) + + const_name("], ") + + make_caster::name + + const_name("]")); + }; + +} // namespace pybind11::detail + +#endif -- cgit v1.3.1