error_stack/
macros.rs

1pub mod __private {
2    #![doc(hidden)]
3    //! Implementation detail for macros.
4    //!
5    //! ⚠️ **Functionality in this module is considered unstable and is subject to change at any
6    //! time without a major version bump!** ⚠️
7    mod specialization {
8        #![allow(clippy::unused_self)]
9        //! [Autoref-Based Stable Specialization](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md)
10        //! for macros.
11        //!
12        //! This is a stable implementation for specialization (only possible within macros, as
13        //! there is no trait bound for these things).
14        //!
15        //! The different tags [`ReportTag`] and [`ContextTag`] have a blanket implementation
16        //! returning a concrete type. This type is then used to create a [`Report`].
17        //!
18        //! [`ContextTag`] is implemented for `T: `[`Context`]s while [`ReportTag`] is implement for
19        //! [`Report`]s. Calling `my_report.__kind()` will always return a [`Reporter`] while
20        //! `my_context.__kind()` will return a [`ContextReporter`] so a [`Report`] has the highest
21        //! precedence when calling `.__kind()`. This will use an identity function when creating a
22        //! [`Report`] to ensure that no information will be lost.
23        //!
24        //! Note: The methods on the tags are called `__kind` instead of `kind` to avoid misleading
25        //! suggestions from the Rust compiler, when calling `kind`. It would suggest implementing a
26        //! tag for the type which cannot and should not be implemented.
27
28        pub trait ReportTag {
29            #[inline]
30            fn __kind(&self) -> Reporter {
31                Reporter
32            }
33        }
34        impl<T> ReportTag for Report<T> {}
35
36        pub trait ContextTag {
37            #[inline]
38            fn __kind(&self) -> ContextReporter {
39                ContextReporter
40            }
41        }
42        impl<T> ContextTag for &T where T: ?Sized + Context {}
43        use crate::{Context, Report};
44
45        pub struct Reporter;
46        impl Reporter {
47            #[inline]
48            pub const fn report<T>(self, report: Report<T>) -> Report<T> {
49                report
50            }
51        }
52
53        pub struct ContextReporter;
54        impl ContextReporter {
55            #[inline]
56            #[track_caller]
57            pub fn report<C: Context>(self, context: C) -> Report<C> {
58                Report::new(context)
59            }
60        }
61    }
62
63    // Import anonymously to allow calling `__kind` but forbid implementing the tag-traits.
64    pub use self::specialization::{ContextTag as _, ReportTag as _};
65}
66
67/// Creates a [`Report`] from the given parameters.
68///
69/// The parameters may either be [`Context`] or a [`Report`]. The returned [`Report`] will use the
70/// the provided type as context.
71///
72/// [`Report`]: crate::Report
73/// [`Context`]: crate::Context
74/// [`Error`]: core::error::Error
75///
76/// # Examples
77///
78/// Create a [`Report`] from [`Error`]:
79///
80/// ```rust
81/// use std::fs;
82///
83/// use error_stack::report;
84///
85/// # fn wrapper() -> error_stack::Result<(), impl core::fmt::Debug> {
86/// match fs::read_to_string("/path/to/file") {
87///     Ok(content) => println!("file contents: {content}"),
88///     Err(err) => return Err(report!(err)),
89/// }
90/// # Ok(()) }
91/// # assert!(wrapper().unwrap_err().contains::<std::io::Error>());
92/// ```
93///
94/// Create a [`Report`] from [`Context`]:
95///
96/// ```rust
97/// # fn has_permission(_: &u32, _: &u32) -> bool { true }
98/// # type User = u32;
99/// # let user = 0;
100/// # type Resource = u32;
101/// # let resource = 0;
102/// use core::fmt;
103///
104/// use error_stack::{report, Context};
105///
106/// #[derive(Debug)]
107/// # #[allow(dead_code)]
108/// struct PermissionDenied(User, Resource);
109///
110/// impl fmt::Display for PermissionDenied {
111///     # #[allow(unused_variables)]
112///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
113///         # const _: &str = stringify! {
114///         ...
115///         # }; Ok(())}
116/// }
117///
118/// impl Context for PermissionDenied {}
119///
120/// if !has_permission(&user, &resource) {
121///     return Err(report!(PermissionDenied(user, resource)));
122/// }
123/// # Ok(())
124/// ```
125#[macro_export]
126macro_rules! report {
127    ($err:expr $(,)?) => {{
128        use $crate::__private::*;
129        let error = $err;
130        (&error).__kind().report(error)
131    }};
132}
133
134/// Creates a [`Report`] and returns it as [`Result`].
135///
136/// Shorthand for `return `Err`(`[`report!(...)`]`)`
137///
138/// [`Report`]: crate::Report
139/// [`report!(...)`]: report
140///
141/// # Examples
142///
143/// Create a [`Report`] from [`Error`]:
144///
145/// [`Error`]: core::error::Error
146///
147/// ```
148/// use std::fs;
149///
150/// use error_stack::bail;
151/// # fn wrapper() -> error_stack::Result<(), impl core::fmt::Debug> {
152/// match fs::read_to_string("/path/to/file") {
153///     Ok(content) => println!("file contents: {content}"),
154///     Err(err) => bail!(err),
155/// }
156/// # Ok(()) }
157/// # assert!(wrapper().unwrap_err().contains::<std::io::Error>());
158/// ```
159///
160/// Create a [`Report`] from [`Context`]:
161///
162/// [`Context`]: crate::Context
163///
164/// ```rust
165/// # fn has_permission(_: &u32, _: &u32) -> bool { true }
166/// # type User = u32;
167/// # let user = 0;
168/// # type Resource = u32;
169/// # let resource = 0;
170/// use core::fmt;
171///
172/// use error_stack::{bail, Context};
173///
174/// #[derive(Debug)]
175/// # #[allow(dead_code)]
176/// struct PermissionDenied(User, Resource);
177///
178/// impl fmt::Display for PermissionDenied {
179///     # #[allow(unused_variables)]
180///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
181///         # const _: &str = stringify! {
182///         ...
183///         # }; Ok(())}
184/// }
185///
186/// impl Context for PermissionDenied {}
187///
188/// if !has_permission(&user, &resource) {
189///     bail!(PermissionDenied(user, resource));
190/// }
191/// # Ok(())
192/// ```
193#[macro_export]
194macro_rules! bail {
195    ($err:expr $(,)?) => {{
196        return $crate::Result::Err($crate::report!($err));
197    }};
198}
199
200/// Ensures `$cond` is met, otherwise return an error.
201///
202/// Shorthand for `if !$cond { `[`bail!(...)`]`) }`
203///
204/// [`Report`]: crate::Report
205/// [`bail!(...)`]: bail
206///
207/// # Examples
208///
209/// Create a [`Report`] from [`Context`]:
210///
211/// [`Report`]: crate::Report
212/// [`Context`]: crate::Context
213///
214/// ```rust
215/// # fn has_permission(_: &u32, _: &u32) -> bool { true }
216/// # type User = u32;
217/// # let user = 0;
218/// # type Resource = u32;
219/// # let resource = 0;
220/// # use core::fmt;
221///
222/// use error_stack::{ensure, Context};
223///
224/// #[derive(Debug)]
225/// # #[allow(dead_code)]
226/// struct PermissionDenied(User, Resource);
227///
228/// impl fmt::Display for PermissionDenied {
229///     # #[allow(unused_variables)]
230///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
231///         const _: &str = stringify! {
232///         ...
233///          };
234///         Ok(())
235///     }
236/// }
237///
238/// impl Context for PermissionDenied {}
239///
240/// ensure!(
241///     has_permission(&user, &resource),
242///     PermissionDenied(user, resource)
243/// );
244/// # Ok(())
245/// ```
246#[macro_export]
247macro_rules! ensure {
248    ($cond:expr, $err:expr $(,)?) => {{
249        if !bool::from($cond) {
250            $crate::bail!($err)
251        }
252    }};
253}