#pragma once #include "tl/detail/prologue.h" #include "tl/detail/outcome.hpp" #include "string.h" #include "enum.h" #include "format.h" namespace tl { using namespace OUTCOME_V2_NAMESPACE; template struct error { using code_t = CODE; code_t code; string what; }; template E make_error(typename E::code_t code, std::format_string format_str, Args&&... args) noexcept { return E{code, tl::format(format_str, std::forward(args)...)}; } template E make_error(typename E::code_t code) noexcept { return E{code}; } struct generic_error { string what; }; template generic_error make_generic_error(std::format_string format_str, Args&&... args) noexcept { return generic_error{tl::format(format_str, std::forward(args)...)}; } template using result = OUTCOME_V2_NAMESPACE::result; template auto check(basic_result&& r) noexcept -> basic_result&& { TL_ASSERT(r.has_value(), "Result failed: {}", r.error()); return std::forward>(r); } template auto ignore(basic_result&& r) noexcept -> basic_result&& { [[maybe_unused]] bool has = r.has_value(); return std::forward>(r); } } template struct std::formatter> { constexpr auto parse(format_parse_context& ctx) noexcept { return ctx.begin(); } auto format(const tl::error& e, std::format_context& ctx) const { if constexpr (std::is_enum_v) return format_to(ctx.out(), "code {}: {}", tl::enum_name(e.code), e.what); else return format_to(ctx.out(), "code {}: {}", e.code, e.what); } }; template <> struct std::formatter { constexpr auto parse(format_parse_context& ctx) noexcept { return ctx.begin(); } auto format(const tl::generic_error& e, std::format_context& ctx) const { return format_to(ctx.out(), "{}", e.what); } };