//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // //----------------------------------------------------------------------------- // Author: Kurt Sassenrath // Module: Logging // // {fmt} formatters for various types that are used throughout the codebase. // Some are specific, while others depend on traits. // // Copyright (c) 2023 Kurt Sassenrath. // // License TBD. //----------------------------------------------------------------------------- #ifndef logging_formatters_d22a64b1645a8134 #define logging_formatters_d22a64b1645a8134 #include "theme.h" #include "traits.h" #include #include // Simple wrapper for error strings to be formatted like any other string_view. template <> struct fmt::formatter : fmt::formatter { template constexpr auto format(auto const& v, FormatContext& ctx) const { return fmt::formatter::format(v.v, ctx); } }; // Support enums. By default, enums print the enum type name as well as the // enum name for the given value. E.g. // // enum Color { Red, Green, Blue }; // auto const color = Color::Green; // // Logging `color` will yield "Color::Green" template requires std::is_enum_v struct fmt::formatter : fmt::formatter { template auto format(E const v, FormatContext& ctx) const { auto str = [v] { return fmt::format("{}::{}", magic_enum::enum_type_name(), magic_enum::enum_name(v)); }(); return fmt::formatter::format(str, ctx); } }; // Support enums that _only_ print the string "name" of the enum value. Using // the same example above: // // enum Color { Red, Green, Blue }; // auto const color = Color::Green; // // Logging `enum_name_only{color}` will yield "Green" template requires std::is_enum_v struct fmt::formatter> : fmt::formatter { using enum_name_only = parselink::logging::enum_name_only; template auto format(enum_name_only const v, FormatContext& ctx) const { return fmt::formatter::format( magic_enum::enum_name(v.v), ctx); } }; template <> struct fmt::formatter : fmt::formatter { template auto format(auto const& v, FormatContext& ctx) const { return fmt::formatter::format(v.message(), ctx); } }; // Support conversion of typical standard error codes into a human-readable // string. template <> struct fmt::formatter : fmt::formatter { template auto format(std::errc const& v, FormatContext& ctx) const { return fmt::formatter::format( std::make_error_code(v), ctx); } }; // Support printing bytes as their hex representation. template <> struct fmt::formatter { template constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } template auto format(std::byte const v, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "0x{:0x}", std::uint8_t(v)); } }; // Support printing raw/smart pointers without needing to wrap them in fmt::ptr template struct fmt::formatter : fmt::formatter { template auto format(T const& v, FormatContext& ctx) const { return fmt::formatter::format(fmt::ptr(v), ctx); } }; // TODO(ksassenrath): Re-enable when expected has been integrated template struct fmt::formatter> { template constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } template auto format(tl::expected const& v, FormatContext& ctx) const { if (v) { return fmt::format_to(ctx.out(), "{}", parselink::logging::format_arg{v.value()}); } else { return fmt::format_to(ctx.out(), "{}", parselink::logging::format_arg{v.error()}); } } }; // Support format_arg wrappers, which will be used to colorize output. template struct fmt::formatter> : fmt::formatter::type> { using format_arg_type = parselink::logging::format_arg; using resolved_type = typename format_arg_type::type; template auto format(format_arg_type const& v, FormatContext& ctx) const { return fmt::formatter::format(v.v, ctx); } }; #endif // logging_formatters_d22a64b1645a8134