Skip to main content

error_stack/
macros.rs

1/// Creates a [`Report`] and returns it as [`Result`].
2///
3/// Shorthand for `return Err(report!(..))`.
4///
5/// [`Report`]: crate::Report
6/// [`report!(...)`]: report
7///
8/// # Examples
9///
10/// Create a [`Report`] from [`Error`]:
11///
12/// [`Error`]: core::error::Error
13///
14/// ```
15/// use std::fs;
16///
17/// use error_stack::bail;
18/// # fn wrapper() -> error_stack::Result<(), impl core::fmt::Debug> {
19/// match fs::read_to_string("/path/to/file") {
20///     Ok(content) => println!("file contents: {content}"),
21///     Err(err) => bail!(err),
22/// }
23/// # Ok(()) }
24/// # assert!(wrapper().unwrap_err().contains::<std::io::Error>());
25/// ```
26///
27/// Create a [`Report`] from [`Context`]:
28///
29/// [`Context`]: crate::Context
30///
31/// ```rust
32/// # fn has_permission(_: &u32, _: &u32) -> bool { true }
33/// # type User = u32;
34/// # let user = 0;
35/// # type Resource = u32;
36/// # let resource = 0;
37/// use core::fmt;
38///
39/// use error_stack::{bail, Context};
40///
41/// #[derive(Debug)]
42/// # #[allow(dead_code)]
43/// struct PermissionDenied(User, Resource);
44///
45/// impl fmt::Display for PermissionDenied {
46///     # #[allow(unused_variables)]
47///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
48///         # const _: &str = stringify! {
49///         ...
50///         # }; Ok(())}
51/// }
52///
53/// impl Context for PermissionDenied {}
54///
55/// if !has_permission(&user, &resource) {
56///     bail!(PermissionDenied(user, resource));
57/// }
58/// # Ok(())
59/// ```
60#[cfg(not(feature = "unstable"))]
61#[macro_export]
62macro_rules! bail {
63    ($err:expr $(,)?) => {{
64        return ::core::result::Result::Err($crate::IntoReport::into_report($err));
65    }};
66
67    [$($err:expr),+ $(,)?] => {{
68        compile_error!("enable the `unstable` feature flag to use `bail` to create multiple errors")
69    }};
70}
71
72/// Creates a [`Report`] and returns it as [`Result`].
73///
74/// [`Report`]: crate::Report
75///
76/// # `unstable`
77///
78/// The match arm: `[$($err:expr),+ $(,)?]` is considered unstable and can be used to construct a
79/// `Report<[C]>`.
80///
81/// # Examples
82///
83/// Create a [`Report`] from [`Error`]:
84///
85/// [`Error`]: core::error::Error
86///
87/// ```
88/// use std::fs;
89///
90/// use error_stack::bail;
91/// # fn wrapper() -> Result<(), error_stack::Report<impl core::fmt::Debug>> {
92/// match fs::read_to_string("/path/to/file") {
93///     Ok(content) => println!("file contents: {content}"),
94///     Err(err) => bail!(err),
95/// }
96/// # Ok(()) }
97/// # assert!(wrapper().unwrap_err().contains::<std::io::Error>());
98/// ```
99///
100/// Create a `Report<[C]>` from multiple errors (**unstable only**):
101///
102/// ```rust
103/// # fn has_permission(_: &u32, _: &u32) -> bool { true }
104/// # type User = u32;
105/// # let user = 0;
106/// # type Resource = u32;
107/// # let create_user = 0;
108/// # let create_resource = 0;
109/// use error_stack::bail;
110///
111/// #[derive(Debug)]
112/// # #[allow(dead_code)]
113/// struct PermissionDenied(User, Resource);
114///
115/// impl core::fmt::Display for PermissionDenied {
116///    # #[allow(unused_variables)]
117///     fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118///         # const _: &str = stringify! {
119///         ...
120///         # }; Ok(())
121///     }
122/// }
123///
124/// impl core::error::Error for PermissionDenied {}
125///
126/// // You might want to look into `ReportSink` for a more incremental approach.
127/// if !has_permission(&user, &create_user) && !has_permission(&user, &create_resource) {
128///     bail![
129///         PermissionDenied(user, create_user),
130///         PermissionDenied(user, create_resource)
131///     ];
132/// }
133/// # Ok(())
134/// ```
135#[cfg(feature = "unstable")]
136#[cfg_attr(doc, doc(cfg(all())))]
137#[macro_export]
138macro_rules! bail {
139    ($err:expr $(,)?) => {{
140        return ::core::result::Result::Err($crate::IntoReport::into_report($err));
141    }};
142
143    [$($err:expr),+ $(,)?] => {{
144        let mut sink = $crate::ReportSink::new();
145
146        $(
147            sink.capture($err);
148        )+
149
150        let error = match sink.finish() {
151            Ok(()) => unreachable!(),
152            Err(error) => error,
153        };
154
155        return ::core::result::Result::Err(error);
156    }};
157}
158
159/// Ensures `$cond` is met, otherwise return an error.
160///
161/// Shorthand for <code>if !$cond { [bail!(..)]) }</code>
162///
163/// [`Report`]: crate::Report
164/// [bail!(..)]: bail
165///
166/// # Examples
167///
168/// Create a [`Report`] from an [`Error`]:
169///
170/// [`Error`]: core::error::Error
171///
172/// ```rust
173/// # fn has_permission(_: &u32, _: &u32) -> bool { true }
174/// # type User = u32;
175/// # let user = 0;
176/// # type Resource = u32;
177/// # let resource = 0;
178/// use core::error::Error;
179/// use core::fmt;
180///
181/// use error_stack::ensure;
182///
183/// #[derive(Debug)]
184/// # #[allow(dead_code)]
185/// struct PermissionDenied(User, Resource);
186///
187/// impl fmt::Display for PermissionDenied {
188///     # #[allow(unused_variables)]
189///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
190///         # const _: &str = stringify! {
191///         ...
192///         # };
193///         Ok(())
194///     }
195/// }
196///
197/// impl Error for PermissionDenied {}
198///
199/// ensure!(
200///     has_permission(&user, &resource),
201///     PermissionDenied(user, resource)
202/// );
203/// # Ok(())
204/// ```
205#[macro_export]
206macro_rules! ensure {
207    ($cond:expr, $err:expr $(,)?) => {{
208        if !bool::from($cond) {
209            $crate::bail!($err)
210        }
211    }};
212}