Aria 2.0.0
C++23 MVVM framework (C++20 minimum) — reactive, coroutine-first, ABI-layered
Loading...
Searching...
No Matches
error.hpp
Go to the documentation of this file.
1#pragma once
2
3// ============================================================================
4// aria/error.hpp
5// ----------------------------------------------------------------------------
6// Unified error model for the Aria framework. Per docs/error-model.md,
7// every observable error face in Aria reports through `aria::Error`:
8//
9// - reactive graph cycles -> ErrorKind::GraphCycle
10// - validator rule failures -> ErrorKind::Validation + ValidationKey
11// - async command body failure -> ErrorKind::AsyncFailure
12// - async cancellation -> ErrorKind::Cancellation
13// - async with_timeout -> ErrorKind::Timeout
14// - view binding setter failed -> ErrorKind::BindingFailure
15// - bad user argument -> ErrorKind::UserError
16// - internal contract broken -> ErrorKind::InvariantViolation
17//
18// Properties of the type:
19//
20// * Value-typed: copyable, equality-comparable. Designed to be the
21// `T` of `Property<std::optional<Error>>`.
22//
23// * Embedded ValidationKey: a ValidationError no longer needs its
24// own struct -- it is just an `Error` with `kind = Validation`
25// and a populated `key`. This keeps a single observable surface
26// (`vector<Error>`) instead of fragmenting per error family.
27//
28// * Optional `source` string: a stable, free-form locator for "who
29// produced this" (e.g. "AsyncCommand", "AsyncResource", "Validator",
30// "BindingEngine"). Renderers can group / filter on it.
31//
32// * Optional `inner` exception_ptr: an escape hatch for callers that
33// want full stack-trace context. Most consumers never touch it;
34// `message` carries the human-facing text already.
35//
36// * `Error::from_exception(...)`: canonical mapping from a thrown
37// exception_ptr to a typed Error. Framework-specific sentinels are
38// classified at their owning subsystem's error boundary first.
39//
40// Per docs/api-style.md S-1 the type lives in `aria::` and never
41// forces the caller to qualify into an implementation namespace.
42// ============================================================================
43
45
46#include <cstdint>
47#include <exception>
48#include <optional>
49#include <ostream>
50#include <stdexcept>
51#include <string>
52#include <string_view>
53#include <utility>
54
55namespace aria {
56
57// ---------------------------------------------------------------------------
58// ErrorKind
59// ---------------------------------------------------------------------------
60
65enum class ErrorKind : std::uint8_t {
70
75
80
84 Cancellation = 3,
85
88
93
97
102};
103
104[[nodiscard]] inline std::string_view to_string(ErrorKind k) noexcept {
105 switch (k) {
106 case ErrorKind::UserError: return "UserError";
107 case ErrorKind::Validation: return "Validation";
108 case ErrorKind::AsyncFailure: return "AsyncFailure";
109 case ErrorKind::Cancellation: return "Cancellation";
110 case ErrorKind::Timeout: return "Timeout";
111 case ErrorKind::BindingFailure: return "BindingFailure";
112 case ErrorKind::GraphCycle: return "GraphCycle";
113 case ErrorKind::InvariantViolation: return "InvariantViolation";
114 }
115 return "ErrorKind?";
116}
117
118[[nodiscard]] inline std::string_view to_string(Severity s) noexcept {
119 return s == Severity::Error ? "Error" : "Warning";
120}
121
122// ---------------------------------------------------------------------------
123// Error
124// ---------------------------------------------------------------------------
125
129struct Error {
132 std::string message;
136 std::string source;
145 std::exception_ptr inner;
146
147 [[nodiscard]] bool is_error() const noexcept { return severity == Severity::Error; }
148 [[nodiscard]] bool is_warning() const noexcept { return severity == Severity::Warning; }
149
150 [[nodiscard]] bool is_cancellation() const noexcept {
152 }
153
156 [[nodiscard]] std::string to_string() const {
157 std::string out;
158 out.append(::aria::to_string(kind));
159 if (!source.empty()) { out.push_back(':'); out.append(source); }
160 if (!key.empty()) { out.push_back(':'); out.append(key.to_string()); }
161 out.append(": ");
162 out.append(message);
163 return out;
164 }
165
166 // ── Factories ─────────────────────────────────────────────────────
167
170 [[nodiscard]] static Error validation(ValidationKey k, std::string msg) {
172 std::move(msg), "Validator", std::move(k), {}};
173 }
174
176 [[nodiscard]] static Error validation_warning(ValidationKey k, std::string msg) {
178 std::move(msg), "Validator", std::move(k), {}};
179 }
180
182 [[nodiscard]] static Error async_failure(std::string msg,
183 std::string source_tag = "AsyncCommand",
184 std::exception_ptr inner = {}) {
186 std::move(msg), std::move(source_tag), {}, std::move(inner)};
187 }
188
192 [[nodiscard]] static Error cancellation(std::string source_tag = "AsyncCommand") {
194 "operation cancelled", std::move(source_tag), {}, {}};
195 }
196
198 [[nodiscard]] static Error timeout(std::string source_tag = "AsyncCommand") {
200 "operation timed out", std::move(source_tag), {}, {}};
201 }
202
205 [[nodiscard]] static Error user_error(std::string msg, std::string source_tag = {}) {
207 std::move(msg), std::move(source_tag), {}, {}};
208 }
209
211 [[nodiscard]] static Error graph_cycle(std::string msg,
212 std::exception_ptr inner = {}) {
214 std::move(msg), "Graph", {}, std::move(inner)};
215 }
216
237 [[nodiscard]] static Error from_exception(std::exception_ptr ex,
238 std::string source_tag) {
239 if (!ex) {
240 return Error::async_failure("unknown error",
241 std::move(source_tag), {});
242 }
243 try {
244 std::rethrow_exception(ex);
245 } catch (const std::invalid_argument& e) {
247 std::move(source_tag), {}, ex};
248 } catch (const std::out_of_range& e) {
250 std::move(source_tag), {}, ex};
251 } catch (const std::exception& e) {
252 return Error::async_failure(e.what(), std::move(source_tag), ex);
253 } catch (...) {
254 return Error::async_failure("unknown error",
255 std::move(source_tag), ex);
256 }
257 }
258};
259
260// Equality intentionally ignores `inner` (exception_ptr identity is
261// not a useful equivalence) so that re-emitting the same logical
262// failure does NOT trigger Property::on_changed when wrapped in
263// `Property<std::optional<Error>>`.
264inline bool operator==(const Error& a, const Error& b) noexcept {
265 return a.kind == b.kind
266 && a.severity == b.severity
267 && a.message == b.message
268 && a.source == b.source
269 && a.key == b.key;
270}
271inline bool operator!=(const Error& a, const Error& b) noexcept {
272 return !(a == b);
273}
274
275inline std::ostream& operator<<(std::ostream& os, const Error& e) {
276 return os << e.to_string();
277}
278
279} // namespace aria
Definition signal.hpp:12
ErrorKind
Coarse classification of every error Aria can surface.
Definition error.hpp:65
@ Validation
A validator rule failed.
Definition error.hpp:74
@ Cancellation
An OperationCancelled propagated through the async pipeline.
Definition error.hpp:84
@ UserError
Caller passed something the API explicitly forbids (null view model, out-of-range index,...
Definition error.hpp:69
@ BindingFailure
View / adapter side-effect failed (e.g.
Definition error.hpp:92
@ GraphCycle
A reactive dependency cycle or non-converging flush was detected.
Definition error.hpp:96
@ Timeout
A with_timeout deadline elapsed (either Race or Fail mode).
Definition error.hpp:87
@ InvariantViolation
A documented framework invariant was violated at runtime (reserved for stress / fuzz reporting; never...
Definition error.hpp:101
@ AsyncFailure
An asynchronous body threw a non-cancellation, non-timeout exception.
Definition error.hpp:79
std::ostream & operator<<(std::ostream &os, const Error &e)
Definition error.hpp:275
@ Validation
Validator / FormValidator rule runs.
Definition diagnostics.hpp:71
bool operator!=(const Error &a, const Error &b) noexcept
Definition error.hpp:271
bool operator==(const Error &a, const Error &b) noexcept
Definition error.hpp:264
std::string_view to_string(TraceCategory c) noexcept
Definition diagnostics.hpp:75
Severity
Severity of a single error / warning.
Definition validation_key.hpp:42
@ Warning
Definition validation_key.hpp:44
@ Error
Definition validation_key.hpp:43
One uniform error record.
Definition error.hpp:129
static Error from_exception(std::exception_ptr ex, std::string source_tag)
Catch-all converter from a thrown exception_ptr to a typed Error.
Definition error.hpp:237
bool is_cancellation() const noexcept
Definition error.hpp:150
std::string message
Definition error.hpp:132
static Error validation(ValidationKey k, std::string msg)
Hard validation error.
Definition error.hpp:170
std::string to_string() const
Stable single-line render: <kind>:<source>:<key>: <message>.
Definition error.hpp:156
static Error cancellation(std::string source_tag="AsyncCommand")
Cancellation.
Definition error.hpp:192
std::string source
Free-form locator: which subsystem produced this.
Definition error.hpp:136
Severity severity
Definition error.hpp:131
ValidationKey key
For kind == Validation: the (field_path, rule_id) locator.
Definition error.hpp:140
ErrorKind kind
Definition error.hpp:130
static Error timeout(std::string source_tag="AsyncCommand")
with_timeout deadline expired.
Definition error.hpp:198
std::exception_ptr inner
Optional original exception.
Definition error.hpp:145
bool is_warning() const noexcept
Definition error.hpp:148
bool is_error() const noexcept
Definition error.hpp:147
static Error user_error(std::string msg, std::string source_tag={})
Bad caller argument (mirrors std::invalid_argument / std::out_of_range).
Definition error.hpp:205
static Error graph_cycle(std::string msg, std::exception_ptr inner={})
Reactive graph cycle (mirrors CircularDependencyError).
Definition error.hpp:211
static Error async_failure(std::string msg, std::string source_tag="AsyncCommand", std::exception_ptr inner={})
Async failure with optional inner exception_ptr preserved.
Definition error.hpp:182
static Error validation_warning(ValidationKey k, std::string msg)
Soft validation advisory (severity = Warning).
Definition error.hpp:176
(field_path, rule_id) locator for a validation message.
Definition validation_key.hpp:52
bool empty() const noexcept
Definition validation_key.hpp:56
std::string to_string() const
Stable string view of the form "<field_path>#<rule_id>".
Definition validation_key.hpp:61