n0_error/macros.rs
1/// Constructs an error enum/struct value while automatically filling `meta: Meta`.
2///
3/// - `e!(MyError::Variant)` constructs `MyError::Variant { meta: Meta::default() }`.
4/// - `e!(MyError::Variant, source)` constructs `MyError::Variant { source, meta: Meta::default() }`.
5/// - `e!(MyError::Variant { field: value, other })` constructs `MyError::Variant { field: value, other, meta: Meta::default() }`
6#[macro_export]
7macro_rules! e {
8 // No source, no fields
9 ($($err:tt)::+) => {
10 $($err)::+ { meta: $crate::Meta::default() }
11 };
12
13 // Source, no fields
14 ($($err:tt)::+ , $source:expr) => {
15 $($err)::+ { source: $source, meta: $crate::Meta::default() }
16 };
17
18 // Fields and values plus source
19 ($($err:tt)::+ { $($body:tt)* }, $source:expr) => {
20 $($err)::+ { meta: $crate::Meta::default(), source: $source, $($body)* }
21 };
22
23 // Fields and values
24 ($($err:tt)::+ { $($body:tt)* }) => {
25 $($err)::+ { meta: $crate::Meta::default(), $($body)* }
26 };
27}
28
29/// Reexport `spez` for use in the [`anyerr`] macro.
30#[doc(hidden)]
31pub use spez as __spez;
32
33/// Converts a value into [`AnyError`].
34///
35/// - `anyerr!("msg")` creates an error with just a message.
36/// - `anyerr!("this failed at {a} with {}", b)` creates an error with a formatted message
37/// - `anyerr!(value)` converts any [`impl StackError`], `impl std::error::Error`, or `impl Display` into [`AnyError`].
38/// - `anyerr!(value, "context")` works as above and then adds context via [`AnyError::context`].
39/// - `anyerr!(value, "context {}", foo)` works as above, but with a formatted string as context
40///
41/// The forms that take `value` use *autoref specialization* to keep the most details possible:
42/// if given a [`StackError`] it uses [`AnyError::from_stack`], if given a std error, uses [`AnyError::from_std`],
43/// if given a value that impls `Display` it uses [`AnyError::from_display`] - in this order.
44///
45/// [`AnyError::context`]: crate::AnyError::context
46/// [`AnyError::from_display`]: crate::AnyError::from_display
47/// [`AnyError::from_stack`]: crate::AnyError::from_stack
48/// [`AnyError::from_std`]: crate::AnyError::from_std
49/// [`AnyError`]: crate::AnyError
50/// [`StackError`]: crate::StackError
51/// [`impl StackError`]: crate::StackError
52#[macro_export]
53macro_rules! anyerr {
54 ($fmt:literal$(, $($arg:expr),* $(,)?)?) => {
55 $crate::anyerr!(::std::format!($fmt$(, $($arg),*)*))
56 };
57
58 ($err:expr, $fmt:literal$(, $($arg:expr),* $(,)?)?) => {
59 $crate::anyerr!($err).context(format!($fmt$(, $($arg),*)*))
60 };
61
62 ($err:expr) => {
63 $crate::__spez::spez! {
64 for err = $err;
65 match $crate::AnyError -> $crate::AnyError {
66 err
67 }
68 match<T: $crate::StackError + 'static> T -> $crate::AnyError {
69 $crate::AnyError::from_stack(err)
70 }
71 match<T: ::std::error::Error + Send + Sync + 'static> T -> $crate::AnyError {
72 $crate::AnyError::from_std(err)
73 }
74 match <T: ::std::fmt::Display> T -> $crate::AnyError {
75 $crate::AnyError::from_display(err)
76 }
77 }
78 };
79}
80
81/// Ensures a condition, otherwise returns the error constructed with [`e`] from the remaining args.
82///
83/// This macro takes an expression as its first argument. If the expression evaluates
84/// to `false`, the macro expands to returning an error result.
85///
86/// The error will be constructed by passing all remaining arguments to [`e`].
87/// See its docs for details on accepted forms.
88#[macro_export]
89macro_rules! ensure {
90 ($predicate:expr, $($tt:tt)*) => {
91 if !$predicate {
92 $crate::bail!($($tt)*)
93 }
94 };
95}
96
97/// Ensures a condition, otherwise returns an [`AnyError`].
98///
99/// This macro takes an expression as its first argument. If the expression evaluates
100/// to `false`, the macro expands to returning an error result. The error will be constructed
101/// by passing the remaining arguments after the expression to [`anyerr`]. See its docs for
102/// supported forms.
103///
104/// [`AnyError`]: crate::AnyError
105/// [`anyerr`]: crate::anyerr
106#[macro_export]
107macro_rules! ensure_any {
108 ($cond:expr, $($tt:tt)*) => {
109 if !$cond {
110 $crate::bail_any!($($tt)*)
111 }
112 };
113}
114
115/// Returns an error result by constructing a `StackError` with [`e`].
116///
117/// This macro accepts the same forms as [`e`], but wraps the error into `Err` and
118/// expands to returning the result from the current function.
119#[macro_export]
120macro_rules! bail {
121 ($($tt:tt)*) => {
122 return ::core::result::Result::Err($crate::e!($($tt)*).into())
123 }
124}
125
126/// Returns an error result by constructing an [`AnyError`] with [`anyerr`].
127///
128/// This macro accepts the same forms as [`anyerr`], but wraps the error into `Err` and
129/// expands to returning the result from the current function.
130///
131/// [`AnyError`]: crate::AnyError
132/// [`anyerr`]: crate::anyerr
133#[macro_export]
134macro_rules! bail_any {
135 ($($tt:tt)*) => {
136 return ::core::result::Result::Err($crate::anyerr!($($tt)*).into())
137 }
138}
139
140/// Unwraps a result, returning in the error case while converting the error.
141///
142/// If the result is the error variant, this will construct a new error with [`e`]
143/// that takes the result's error as its source.
144#[macro_export]
145macro_rules! try_or {
146 ($result:expr, $($tt:tt)*) => {
147 match $result {
148 ::core::result::Result::Ok(v) => v,
149 ::core::result::Result::Err(e) => {
150 return ::core::result::Result::Err($crate::e!($($tt)*, e));
151 }
152 }
153 };
154}
155
156/// Unwraps a result, returning in the error case while adding context to the error.
157///
158/// If the result is the error variant, this will construct a new error with [`anyerr`]
159/// from the result's error while providing additional context.
160///
161/// [`anyerr`]: crate::anyerr
162#[macro_export]
163macro_rules! try_or_any {
164 ($result:expr, $($context:tt)*) => {
165 match $result {
166 ::core::result::Result::Ok(v) => v,
167 ::core::result::Result::Err(e) => {
168 return ::core::result::Result::Err($crate::anyerr!(e, $($context)*));
169 }
170 }
171 };
172}