wren
Vulkan-based game engine
Loading...
Searching...
No Matches
result.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <boost/describe.hpp>
4#include <boost/preprocessor.hpp>
5#include <expected>
6#include <optional>
7#include <system_error>
8
9#include "enums.hpp" // IWYU pragma: export
10#include "macros.hpp"
11
12namespace wren {
13
14class Err {
15 public:
16 template <typename T>
17 requires std::is_error_code_enum_v<T>
18 Err(T error, std::source_location loc = std::source_location::current())
19 : error_code_(make_error_code(error)), loc_(loc) {}
20 Err(const std::error_code& ec,
21 std::source_location loc = std::source_location::current())
22 : error_code_(ec), loc_(loc) {}
23 Err(int32_t ec, const std::error_category& e_cat,
24 std::source_location loc = std::source_location::current())
25 : error_code_(ec, e_cat), loc_(loc) {}
26
27 [[nodiscard]] auto error() const { return error_code_; }
28
29 [[nodiscard]] auto message() const { return error_code_.message(); }
30
31 [[nodiscard]] auto extra_msg() const { return extra_message_; }
32
33 [[nodiscard]] auto location() const { return loc_; }
34
35 private:
36 std::error_code error_code_;
37 std::optional<std::string> extra_message_;
38
39 std::source_location loc_;
40};
41
42template <typename T>
43using expected = std::expected<T, Err>;
44
45} // namespace wren
46
47template <>
48struct std::formatter<wren::Err, char> {
49 constexpr auto parse(std::format_parse_context& ctx) {
50 auto it = ctx.begin(), end = ctx.end();
51
52 if (it != end && *it != '}') {
53 throw std::runtime_error("invalid format");
54 }
55
56 return it;
57 }
58
59 auto format(const wren::Err& e, std::format_context& ctx) const {
60 auto out = ctx.out();
61 out = std::format_to(out, "Error: {} {}", e.error().category().name(),
62 e.error().message());
63
64 if (e.extra_msg().has_value())
65 out = std::format_to(out, "({})", e.extra_msg().value());
66
67 out = std::format_to(out, "\n{} {}:{}:{}", e.location().function_name(),
68 e.location().file_name(), e.location().line(),
69 e.location().column());
70
71 return out;
72 }
73};
74
77#define DEFINE_ERROR_IMPL(CAT_NAME, ERROR_ENUM) \
78 class ERROR_ENUM##_category_t : public std::error_category { \
79 public: \
80 [[nodiscard]] auto name() const noexcept -> const char* final { \
81 return CAT_NAME; \
82 } \
83 [[nodiscard]] auto message(int32_t c) const -> std::string final { \
84 auto e = static_cast<ERROR_ENUM>(c); \
85 using namespace boost::describe; \
86 return std::string{wren::utils::enum_to_string(e)}; \
87 } \
88 }; \
89 inline auto ERROR_ENUM##_category() -> const ERROR_ENUM##_category_t& { \
90 static const ERROR_ENUM##_category_t kC; \
91 return kC; \
92 } \
93 inline auto make_error_code(ERROR_ENUM ec) noexcept -> std::error_code { \
94 return {static_cast<int32_t>(ec), ERROR_ENUM##_category()}; \
95 }
96
97/* @brief This macro defines an enum with BOOST_DEFINE_ENUM_CLASS and
98 * hooks into the std::error_code system The NAMSPACE arg can be
99 * skipped if the enum is in the global namespace.
100 * @param cat_name The name to use for the Error's category, should
101 * be something similar to the current namespace
102 * @param name the error enum name
103 * @param ... The enum variants to define
104 */
105#define DEFINE_ERROR(cat_name, name, ...) \
106 BOOST_DEFINE_ENUM_CLASS(name, __VA_ARGS__); \
107 DEFINE_ERROR_IMPL(cat_name, name)
108
109#define RESULT_UNIQUE_NAME() BOOST_PP_CAT(__result_tmp, __COUNTER__)
110
111#define TRY_RESULT_IMPL(unique, expr) \
112 auto unique = (expr); \
113 if (!(unique).has_value()) return std::unexpected(unique.error());
114
115#define TRY_RESULT_1(unique, expr) TRY_RESULT_IMPL(unique, expr)
116#define TRY_RESULT_2(unique, out, expr) \
117 TRY_RESULT_IMPL(unique, expr) \
118 out = (unique).value();
119
120#define TRY_RESULT(...) \
121 BOOST_PP_OVERLOAD(TRY_RESULT_, __VA_ARGS__) \
122 (RESULT_UNIQUE_NAME(), __VA_ARGS__)
123
124#define TRY_RESULT_VOID_IMPL(unique, expr) \
125 auto unique = (expr); \
126 if (!(unique).has_value()) return;
127
128#define TRY_RESULT_VOID_1(unique, expr) TRY_RESULT_VOID_IMPL(unique, expr)
129#define TRY_RESULT_VOID_2(unique, out, expr) \
130 TRY_RESULT_VOID_IMPL(unique, expr) \
131 out = (unique).value();
132#define TRY_RESULT_VOID(...) \
133 BOOST_PP_OVERLOAD(TRY_RESULT_VOID_, __VA_ARGS__) \
134 (RESULT_UNIQUE_NAME(), __VA_ARGS__)
135
145// NOLINTNEXTLINE
146#define ERR_VAL_OR(out, err, on_err) \
147 const auto LINEIZE(res, __LINE__) = err; \
148 if (!LINEIZE(res, __LINE__).has_value()) { \
149 on_err \
150 } \
151 out = LINEIZE(res, __LINE__).value();
152
159// NOLINTNEXTLINE
160#define ERR_VOID_OR(err, on_err) \
161 const auto LINEIZE(res, __LINE__) = err; \
162 if (!LINEIZE(res, __LINE__).has_value()) { \
163 on_err \
164 }
Definition result.hpp:14
Err(int32_t ec, const std::error_category &e_cat, std::source_location loc=std::source_location::current())
Definition result.hpp:23
auto location() const
Definition result.hpp:33
auto extra_msg() const
Definition result.hpp:31
auto error() const
Definition result.hpp:27
Err(T error, std::source_location loc=std::source_location::current())
Definition result.hpp:18
auto message() const
Definition result.hpp:29
Err(const std::error_code &ec, std::source_location loc=std::source_location::current())
Definition result.hpp:20
std::error_code error_code_
Definition result.hpp:36
std::optional< std::string > extra_message_
Definition result.hpp:37
std::source_location loc_
Definition result.hpp:39
Definition editor_scene.hpp:5
std::expected< T, Err > expected
Definition result.hpp:43
constexpr auto parse(std::format_parse_context &ctx)
Definition result.hpp:49
auto format(const wren::Err &e, std::format_context &ctx) const
Definition result.hpp:59