154 lines
5.2 KiB
C++
154 lines
5.2 KiB
C++
//-----------------------------------------------------------------------------
|
|
// ___ __ _ _
|
|
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
|
|
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
|
|
// / ___/ (_| | | \__ \ __/ /__| | | | | <
|
|
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
// 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 <magic_enum.hpp>
|
|
|
|
#include <tl/expected.hpp>
|
|
|
|
// Simple wrapper for error strings to be formatted like any other string_view.
|
|
template <>
|
|
struct fmt::formatter<parselink::logging::error_str>
|
|
: fmt::formatter<std::string_view> {
|
|
template <typename FormatContext>
|
|
constexpr auto format(auto const& v, FormatContext& ctx) const {
|
|
return fmt::formatter<std::string_view>::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 <typename E>
|
|
requires std::is_enum_v<E>
|
|
struct fmt::formatter<E> : fmt::formatter<std::string_view> {
|
|
template <typename FormatContext>
|
|
auto format(E const v, FormatContext& ctx) const {
|
|
auto str = [v] {
|
|
return fmt::format("{}::{}", magic_enum::enum_type_name<E>(),
|
|
magic_enum::enum_name(v));
|
|
}();
|
|
return fmt::formatter<std::string_view>::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 <typename E>
|
|
requires std::is_enum_v<E>
|
|
struct fmt::formatter<parselink::logging::enum_name_only<E>>
|
|
: fmt::formatter<std::string_view> {
|
|
using enum_name_only = parselink::logging::enum_name_only<E>;
|
|
|
|
template <typename FormatContext>
|
|
auto format(enum_name_only const v, FormatContext& ctx) const {
|
|
return fmt::formatter<std::string_view>::format(
|
|
magic_enum::enum_name(v.v), ctx);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct fmt::formatter<std::error_code> : fmt::formatter<std::string_view> {
|
|
template <typename FormatContext>
|
|
auto format(auto const& v, FormatContext& ctx) const {
|
|
return fmt::formatter<std::string_view>::format(v.message(), ctx);
|
|
}
|
|
};
|
|
|
|
// Support conversion of typical standard error codes into a human-readable
|
|
// string.
|
|
template <>
|
|
struct fmt::formatter<std::errc> : fmt::formatter<std::error_code> {
|
|
template <typename FormatContext>
|
|
auto format(std::errc const& v, FormatContext& ctx) const {
|
|
return fmt::formatter<std::error_code>::format(
|
|
std::make_error_code(v), ctx);
|
|
}
|
|
};
|
|
|
|
// Support printing bytes as their hex representation.
|
|
template <>
|
|
struct fmt::formatter<std::byte> {
|
|
template <typename ParseContext>
|
|
constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
|
return ctx.begin();
|
|
}
|
|
|
|
template <typename FormatContext>
|
|
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 <parselink::logging::detail::printable_pointer T>
|
|
struct fmt::formatter<T> : fmt::formatter<void const*> {
|
|
template <typename FormatContext>
|
|
auto format(T const& v, FormatContext& ctx) const {
|
|
return fmt::formatter<void const*>::format(fmt::ptr(v), ctx);
|
|
}
|
|
};
|
|
|
|
template <typename T, typename Err>
|
|
struct fmt::formatter<tl::expected<T, Err>> {
|
|
template <typename ParseContext>
|
|
constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
|
return ctx.begin();
|
|
}
|
|
|
|
template <typename FormatContext>
|
|
auto format(tl::expected<T, Err> const& v, FormatContext& ctx) const {
|
|
if (v) {
|
|
return fmt::format_to(ctx.out(), "{}",
|
|
parselink::logging::format_arg<T>{v.value()});
|
|
} else {
|
|
return fmt::format_to(ctx.out(), "{}",
|
|
parselink::logging::format_arg<Err>{v.error()});
|
|
}
|
|
}
|
|
};
|
|
|
|
// Support format_arg wrappers, which will be used to colorize output.
|
|
template <typename T>
|
|
struct fmt::formatter<parselink::logging::format_arg<T>>
|
|
: fmt::formatter<typename parselink::logging::format_arg<T>::type> {
|
|
using format_arg_type = parselink::logging::format_arg<T>;
|
|
using resolved_type = typename format_arg_type::type;
|
|
|
|
template <typename FormatContext>
|
|
auto format(format_arg_type const& v, FormatContext& ctx) const {
|
|
return fmt::formatter<resolved_type>::format(v.v, ctx);
|
|
}
|
|
};
|
|
|
|
#endif // logging_formatters_d22a64b1645a8134
|