#ifndef GINVOKE_HPP #define GINVOKE_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "overload.hpp" #include "make_array.hpp" #include "hexify.hpp" namespace glib { namespace impl { using static_c_str = const char *; using varstring_t = std::variant; struct varstring : varstring_t { const char* c_str() const && = delete; const char* c_str() const & { return std::visit(overload{ [](const std::string &s){ return s.c_str(); }, [](const static_c_str s){ return s; } }, static_cast(*this)); } }; struct hresult { std::int32_t code; varstring message; }; std::optional get_if_hresult_error(std::exception_ptr) noexcept; } template inline auto &describe_argument(OStream &s, const T &a) { return s << a; } template inline auto &describe_argument(OStream &s, std::string_view const a) { return s << std::quoted(a); } template inline auto &describe_argument(OStream &s, const std::string & a) { return s << std::quoted(a); } template inline auto &describe_argument(OStream &s, const char * const a) { return s << std::quoted(a); } // TODO: overload for const GString * template inline auto &describe_argument(OStream &s, std::wstring_view const a) { return s << std::quoted(a); } template inline auto &describe_argument(OStream &s, const std::wstring & a) { return s << std::quoted(a); } template inline auto &describe_argument(OStream &s, const wchar_t * const a) = delete; // not implemented // TODO: handle wide strings maybe template inline impl::varstring describe_arguments(const Arg &...a) noexcept try { std::ostringstream ss; ((describe_argument(ss,a)<<','), ...); auto s = std::move(ss).str(); s.pop_back(); return {s}; } catch (...) { return {""}; } #define FORMAT "%s(%s) failed: %s" template inline void log_invocation_failure(const char *e, const char *func_name, const Arg &...a) noexcept { const auto args = describe_arguments(a...); g_warning(FORMAT, func_name, args.c_str(), e); } template inline void log_invocation_failure_desc(const char* e, const char* e_desc, const char* func_name, const Arg&... a) noexcept { const auto args = describe_arguments(a...); g_warning(FORMAT": %s", func_name, args.c_str(), e, e_desc); } #undef FORMAT template inline gboolean try_invoke(const char *func_name, Invokable &&i, const Arg &...a) noexcept try { return std::invoke(std::forward(i), a...); } catch (const std::exception &e) { log_invocation_failure(e.what(), func_name, a...); return FALSE; } catch (...) { if (const auto e = impl::get_if_hresult_error(std::current_exception())) { auto hr = make_array("hresult 0x01234567\0"); hexify32(static_cast(e->code), std::end(hr)-1); log_invocation_failure_desc(std::begin(hr), e->message.c_str(), func_name, a...); } else log_invocation_failure("unknown error", func_name, a...); return FALSE; } } // namespace glib #define g_try_invoke(invokable, ...) glib::try_invoke(#invokable, invokable, __VA_ARGS__) #endif