diff --git a/source/mijin/util/exception.hpp b/source/mijin/util/exception.hpp index 7ad87e3..1f0b776 100644 --- a/source/mijin/util/exception.hpp +++ b/source/mijin/util/exception.hpp @@ -4,8 +4,11 @@ #ifndef MIJIN_UTIL_EXCEPTION_HPP_INCLUDED #define MIJIN_UTIL_EXCEPTION_HPP_INCLUDED 1 +#include #include +#include +#include "../detect.hpp" #include "../debug/stacktrace.hpp" namespace mijin @@ -73,5 +76,76 @@ void walkExceptionCause(const std::exception_ptr& cause, TFunc func) } } } + +template +void walkException(const std::exception& exc, TFunc func) +{ + func(exc); +} + +template +void walkException(const mijin::Exception& exc, TFunc func) +{ + func(exc); + walkExceptionCause(exc.getCause(), func); +} } // namespace mijin + +template +struct std::formatter +{ + using char_t = TChar; + + template + constexpr TContext::iterator parse(TContext& ctx) + { + auto it = ctx.begin(); + auto end = ctx.end(); + + if (it != end && *it != MIJIN_SMART_QUOTE(char_t, '}')) + { + throw std::format_error("invalid format"); + } + + return it; + } + + template + TContext::iterator format(const mijin::Exception& exception, TContext& ctx) const + { + using namespace std::literals; + + auto it = ctx.out(); + bool first = true; + mijin::walkException(exception, [&](const T& exc) + { + if constexpr (!std::is_same_v) + { + if (!first) { + it = std::ranges::copy(MIJIN_SMART_QUOTE(char_t, "\nCaused by:\n"sv), it).out; + } + first = false; +#if MIJIN_RTTI + it = std::ranges::copy(std::basic_string_view(typeid(exc).name()), it).out; + it = std::ranges::copy(MIJIN_SMART_QUOTE(char_t, ": "sv), it).out; +#endif + it = std::ranges::copy(std::basic_string_view(exc.what()), it).out; + if constexpr (std::is_same_v) + { + if (const mijin::Result& trace = exc.getStacktrace(); trace.isSuccess()) + { + *it = MIJIN_SMART_QUOTE(char_t, '\n'); + ++it; + it = std::format_to(it, MIJIN_SMART_QUOTE(char_t, "{}"), trace.getValue()); + } + } + } + else + { + it = std::ranges::copy(MIJIN_SMART_QUOTE(char_t, ""sv), it).out; + } + }); + return it; + } +}; #endif // MIJIN_UTIL_EXCEPTION_HPP_INCLUDED