From cfe55c1e960c857bc86e38f8e32ebd609475c718 Mon Sep 17 00:00:00 2001 From: dominic Date: Wed, 31 Jan 2024 12:52:57 +0100 Subject: [PATCH] added formatter for std::expected --- include/fmt/std.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++ test/std-test.cc | 20 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/include/fmt/std.h b/include/fmt/std.h index 5cb1ca48d874..33993f7f1038 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -36,6 +36,9 @@ # if FMT_HAS_INCLUDE() # include # endif +# if FMT_HAS_INCLUDE() +# include +# endif #endif #if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE() @@ -242,6 +245,52 @@ struct formatter, Char, FMT_END_NAMESPACE #endif // __cpp_lib_optional +#ifdef __cpp_lib_expected +FMT_BEGIN_NAMESPACE +namespace detail { + +template +auto write_expected_alternative(OutputIt out, const T& v) -> OutputIt { + if constexpr (has_to_string_view::value) + return write_escaped_string(out, detail::to_string_view(v)); + else if constexpr (std::is_same_v) + return write_escaped_char(out, v); + else + return write(out, v); +} + +} // namespace detail + +FMT_EXPORT +template +struct formatter< + std::expected, Char, + std::enable_if_t, is_formattable>>> { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + auto format(const std::expected& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + + if(value.has_value()) { + out = detail::write(out, "expected("); + out = detail::write_expected_alternative(out, value.value()); + } else { + out = detail::write(out, "unexpected("); + out = detail::write_expected_alternative(out, value.error()); + } + *out++ = ')'; + return out; + } +}; +FMT_END_NAMESPACE +#endif // __cpp_lib_expected + #ifdef __cpp_lib_source_location FMT_BEGIN_NAMESPACE FMT_EXPORT diff --git a/test/std-test.cc b/test/std-test.cc index f5566848e023..0cdd3abbd6f7 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -102,6 +102,26 @@ TEST(std_test, optional) { #endif } +TEST(std_test, expected) { +#ifdef __cpp_lib_expected + EXPECT_EQ(fmt::format("{}", std::expected{1}), "expected(1)"); + EXPECT_EQ(fmt::format("{}", std::expected{std::unexpected(1)}), "unexpected(1)"); + EXPECT_EQ(fmt::format("{}", std::expected{"test"}), "expected(\"test\")"); + EXPECT_EQ(fmt::format("{}", std::expected{std::unexpected("test")}), "unexpected(\"test\")"); + EXPECT_EQ(fmt::format("{}", std::expected{'a'}), "expected('a')"); + EXPECT_EQ(fmt::format("{}", std::expected{std::unexpected('a')}), "unexpected('a')"); + + struct unformattable1 {}; + struct unformattable2 {}; + EXPECT_FALSE((fmt::is_formattable::value)); + EXPECT_FALSE((fmt::is_formattable::value)); + EXPECT_FALSE((fmt::is_formattable>::value)); + EXPECT_FALSE((fmt::is_formattable>::value)); + EXPECT_FALSE((fmt::is_formattable>::value)); + EXPECT_TRUE((fmt::is_formattable>::value)); +#endif +} + namespace my_nso { enum class my_number { one,