error_stack/
result.rs

1use core::fmt;
2
3use crate::{Context, Report};
4
5/// [`Result`](std::result::Result)`<T, `[`Report<C>`](Report)`>`
6///
7/// A reasonable return type to use throughout an application.
8///
9/// The `Result` type can be used with one or two parameters, where the first parameter represents
10/// the [`Ok`] arm and the second parameter `Context` is used as in [`Report<C>`].
11///
12/// # Examples
13///
14/// `Result` can also be used in `fn main()`:
15///
16/// ```rust
17/// # fn has_permission(_: (), _: ()) -> bool { true }
18/// # fn get_user() -> Result<(), AccessError> { Ok(()) }
19/// # fn get_resource() -> Result<(), AccessError> { Ok(()) }
20/// # #[derive(Debug)] enum AccessError { PermissionDenied((), ()) }
21/// # impl core::fmt::Display for AccessError {
22/// #    fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Ok(()) }
23/// # }
24/// # impl error_stack::Context for AccessError {}
25/// use error_stack::{ensure, Result};
26///
27/// fn main() -> Result<(), AccessError> {
28///     let user = get_user()?;
29///     let resource = get_resource()?;
30///
31///     ensure!(
32///         has_permission(user, resource),
33///         AccessError::PermissionDenied(user, resource)
34///     );
35///
36///     # const _: &str = stringify! {
37///     ...
38///     # }; Ok(())
39/// }
40/// ```
41pub type Result<T, C> = core::result::Result<T, Report<C>>;
42
43/// Extension trait for [`Result`][core::result::Result] to provide context information on
44/// [`Report`]s.
45pub trait ResultExt {
46    /// The [`Context`] type of the [`Result`].
47    type Context: Context;
48
49    /// Type of the [`Ok`] value in the [`Result`]
50    type Ok;
51
52    /// Adds a new attachment to the [`Report`] inside the [`Result`].
53    ///
54    /// Applies [`Report::attach`] on the [`Err`] variant, refer to it for more information.
55    fn attach<A>(self, attachment: A) -> core::result::Result<Self::Ok, Report<Self::Context>>
56    where
57        A: Send + Sync + 'static;
58
59    /// Lazily adds a new attachment to the [`Report`] inside the [`Result`].
60    ///
61    /// Applies [`Report::attach`] on the [`Err`] variant, refer to it for more information.
62    fn attach_lazy<A, F>(
63        self,
64        attachment: F,
65    ) -> core::result::Result<Self::Ok, Report<Self::Context>>
66    where
67        A: Send + Sync + 'static,
68        F: FnOnce() -> A;
69
70    /// Adds a new printable attachment to the [`Report`] inside the [`Result`].
71    ///
72    /// Applies [`Report::attach_printable`] on the [`Err`] variant, refer to it for more
73    /// information.
74    fn attach_printable<A>(
75        self,
76        attachment: A,
77    ) -> core::result::Result<Self::Ok, Report<Self::Context>>
78    where
79        A: fmt::Display + fmt::Debug + Send + Sync + 'static;
80
81    /// Lazily adds a new printable attachment to the [`Report`] inside the [`Result`].
82    ///
83    /// Applies [`Report::attach_printable`] on the [`Err`] variant, refer to it for more
84    /// information.
85    fn attach_printable_lazy<A, F>(
86        self,
87        attachment: F,
88    ) -> core::result::Result<Self::Ok, Report<Self::Context>>
89    where
90        A: fmt::Display + fmt::Debug + Send + Sync + 'static,
91        F: FnOnce() -> A;
92
93    /// Changes the context of the [`Report`] inside the [`Result`].
94    ///
95    /// Applies [`Report::change_context`] on the [`Err`] variant, refer to it for more information.
96    fn change_context<C>(self, context: C) -> core::result::Result<Self::Ok, Report<C>>
97    where
98        C: Context;
99
100    /// Lazily changes the context of the [`Report`] inside the [`Result`].
101    ///
102    /// Applies [`Report::change_context`] on the [`Err`] variant, refer to it for more information.
103    fn change_context_lazy<C, F>(self, context: F) -> core::result::Result<Self::Ok, Report<C>>
104    where
105        C: Context,
106        F: FnOnce() -> C;
107}
108
109impl<T, C> ResultExt for core::result::Result<T, C>
110where
111    C: Context,
112{
113    type Context = C;
114    type Ok = T;
115
116    #[track_caller]
117    fn attach<A>(self, attachment: A) -> Result<T, C>
118    where
119        A: Send + Sync + 'static,
120    {
121        match self {
122            Ok(value) => Ok(value),
123            Err(error) => Err(Report::new(error).attach(attachment)),
124        }
125    }
126
127    #[track_caller]
128    fn attach_lazy<A, F>(self, attachment: F) -> Result<T, C>
129    where
130        A: Send + Sync + 'static,
131        F: FnOnce() -> A,
132    {
133        match self {
134            Ok(value) => Ok(value),
135            Err(error) => Err(Report::new(error).attach(attachment())),
136        }
137    }
138
139    #[track_caller]
140    fn attach_printable<A>(self, attachment: A) -> Result<T, C>
141    where
142        A: fmt::Display + fmt::Debug + Send + Sync + 'static,
143    {
144        match self {
145            Ok(value) => Ok(value),
146            Err(error) => Err(Report::new(error).attach_printable(attachment)),
147        }
148    }
149
150    #[track_caller]
151    fn attach_printable_lazy<A, F>(self, attachment: F) -> Result<T, C>
152    where
153        A: fmt::Display + fmt::Debug + Send + Sync + 'static,
154        F: FnOnce() -> A,
155    {
156        match self {
157            Ok(value) => Ok(value),
158            Err(error) => Err(Report::new(error).attach_printable(attachment())),
159        }
160    }
161
162    #[track_caller]
163    fn change_context<C2>(self, context: C2) -> Result<T, C2>
164    where
165        C2: Context,
166    {
167        match self {
168            Ok(value) => Ok(value),
169            Err(error) => Err(Report::new(error).change_context(context)),
170        }
171    }
172
173    #[track_caller]
174    fn change_context_lazy<C2, F>(self, context: F) -> Result<T, C2>
175    where
176        C2: Context,
177        F: FnOnce() -> C2,
178    {
179        match self {
180            Ok(value) => Ok(value),
181            Err(error) => Err(Report::new(error).change_context(context())),
182        }
183    }
184}
185
186impl<T, C> ResultExt for Result<T, C>
187where
188    C: Context,
189{
190    type Context = C;
191    type Ok = T;
192
193    #[track_caller]
194    fn attach<A>(self, attachment: A) -> Self
195    where
196        A: Send + Sync + 'static,
197    {
198        // Can't use `map_err` as `#[track_caller]` is unstable on closures
199        match self {
200            Ok(ok) => Ok(ok),
201            Err(report) => Err(report.attach(attachment)),
202        }
203    }
204
205    #[track_caller]
206    fn attach_lazy<A, F>(self, attachment: F) -> Self
207    where
208        A: Send + Sync + 'static,
209        F: FnOnce() -> A,
210    {
211        // Can't use `map_err` as `#[track_caller]` is unstable on closures
212        match self {
213            Ok(ok) => Ok(ok),
214            Err(report) => Err(report.attach(attachment())),
215        }
216    }
217
218    #[track_caller]
219    fn attach_printable<A>(self, attachment: A) -> Self
220    where
221        A: fmt::Display + fmt::Debug + Send + Sync + 'static,
222    {
223        // Can't use `map_err` as `#[track_caller]` is unstable on closures
224        match self {
225            Ok(ok) => Ok(ok),
226            Err(report) => Err(report.attach_printable(attachment)),
227        }
228    }
229
230    #[track_caller]
231    fn attach_printable_lazy<A, F>(self, attachment: F) -> Self
232    where
233        A: fmt::Display + fmt::Debug + Send + Sync + 'static,
234        F: FnOnce() -> A,
235    {
236        // Can't use `map_err` as `#[track_caller]` is unstable on closures
237        match self {
238            Ok(ok) => Ok(ok),
239            Err(report) => Err(report.attach_printable(attachment())),
240        }
241    }
242
243    #[track_caller]
244    fn change_context<C2>(self, context: C2) -> Result<T, C2>
245    where
246        C2: Context,
247    {
248        // Can't use `map_err` as `#[track_caller]` is unstable on closures
249        match self {
250            Ok(ok) => Ok(ok),
251            Err(report) => Err(report.change_context(context)),
252        }
253    }
254
255    #[track_caller]
256    fn change_context_lazy<C2, F>(self, context: F) -> Result<T, C2>
257    where
258        C2: Context,
259        F: FnOnce() -> C2,
260    {
261        // Can't use `map_err` as `#[track_caller]` is unstable on closures
262        match self {
263            Ok(ok) => Ok(ok),
264            Err(report) => Err(report.change_context(context())),
265        }
266    }
267}