diff --git a/include/log/fmt/logger.hpp b/include/log/fmt/logger.hpp index f57cc204..a33652e9 100644 --- a/include/log/fmt/logger.hpp +++ b/include/log/fmt/logger.hpp @@ -24,6 +24,14 @@ namespace fmt_detail { using namespace std::string_view_literals; constexpr std::array level_text{"MAX"sv, "FATAL"sv, "ERROR"sv, "WARN"sv, "INFO"sv, "USER1"sv, "USER2"sv, "TRACE"sv}; + +template auto decay_enum_value(T const &t) -> decltype(auto) { + if constexpr (requires { format_as(t); } or not std::is_enum_v) { + return (t); + } else { + return stdx::to_underlying(t); + } +} } // namespace fmt_detail template @@ -55,7 +63,8 @@ template struct log_handler { constexpr auto fmtstr = std::string_view{decltype(fr.str)::value}; fr.args.apply([&](auto const &...args) { - ::fmt::format_to(out, fmtstr, args...); + ::fmt::format_to(out, fmtstr, + fmt_detail::decay_enum_value(args)...); }); *out = '\n'; }, diff --git a/test/log/fmt_logger.cpp b/test/log/fmt_logger.cpp index eae43256..e3a6bcdf 100644 --- a/test/log/fmt_logger.cpp +++ b/test/log/fmt_logger.cpp @@ -53,13 +53,35 @@ TEST_CASE("logging doesn't use dynamic memory", "[fmt_logger]") { } TEST_CASE("logging behavior can be properly overridden", "[fmt_logger]") { - buffer.reserve(100); buffer.clear(); log_test_override(); CAPTURE(buffer); CHECK(buffer.substr(buffer.size() - std::size("Hello")) == "Hello\n"); } +namespace detail { +enum struct E1 { A, B, C }; +enum struct E2 { A, B, C }; +[[maybe_unused]] static auto format_as(E2) { return 42; } +} // namespace detail + +TEST_CASE("fmt logger can deal with runtime enum values", "[fmt_logger]") { + buffer.clear(); + auto x = detail::E1::A; + CIB_INFO("Hello {}", x); + CAPTURE(buffer); + CHECK(buffer.substr(buffer.size() - std::size("Hello 0")) == "Hello 0\n"); +} + +TEST_CASE("fmt logger can deal with formattable runtime enum values", + "[fmt_logger]") { + buffer.clear(); + auto x = detail::E2::A; + CIB_INFO("Hello {}", x); + CAPTURE(buffer); + CHECK(buffer.substr(buffer.size() - std::size("Hello 42")) == "Hello 42\n"); +} + TEST_CASE("log levels are properly represented", "[fmt_logger]") { { std::string level{};