Skip to main content

lazy_errors/
or_wrap_with.rs

1use core::fmt::Display;
2
3use crate::Error;
4
5/// Adds the [`or_wrap_with`](Self::or_wrap_with) method on `Result<_, E>`,
6/// if `E` implements [`Into<I>`](crate::Error#inner-error-type-i).
7///
8/// Do not implement this trait.
9/// Importing the trait is sufficient due to blanket implementations.
10/// The trait is implemented on `Result<_, E>` if `E` implements `Into<I>`,
11/// where `I` is the [_inner error type_](crate::Error#inner-error-type-i),
12/// typically [`prelude::Stashable`].
13#[cfg_attr(
14    any(feature = "rust-v1.81", feature = "std"),
15    doc = r##"
16
17[`prelude::Stashable`]: crate::prelude::Stashable
18"##
19)]
20#[cfg_attr(
21    not(any(feature = "rust-v1.81", feature = "std")),
22    doc = r##"
23
24[`prelude::Stashable`]: crate::surrogate_error_trait::prelude::Stashable
25"##
26)]
27pub trait OrWrapWith<F, M, T, E>
28where
29    F: FnOnce() -> M,
30    M: Display,
31{
32    /// If `self` is `Result::Ok(value)`, returns `Result::Ok(value)`;
33    /// if `self` is `Result::Err(e1)`, returns `Result::Err(e2)`
34    /// where `e2` is an [`Error`] containing a [`WrappedError`]
35    /// that will hold the original `e1` value
36    /// and annotates it with the message provided by the user.
37    ///
38    /// This method behaves identically to [`or_wrap`]
39    /// except that you can pass some information
40    /// about the context of the error.
41    ///
42    /// ```
43    /// # use lazy_errors::doctest_line_num_helper as replace_line_numbers;
44    /// #[cfg(any(feature = "rust-v1.81", feature = "std"))]
45    /// use lazy_errors::prelude::*;
46    ///
47    /// #[cfg(not(any(feature = "rust-v1.81", feature = "std")))]
48    /// use lazy_errors::surrogate_error_trait::prelude::*;
49    ///
50    /// fn run(tokens: &[&str]) -> Result<(), Error> {
51    ///     all_ascii(tokens).or_wrap_with(|| "Input is not ASCII")
52    /// }
53    ///
54    /// fn all_ascii(tokens: &[&str]) -> Result<(), String> {
55    ///     match tokens.iter().find(|s| !s.is_ascii()) {
56    ///         None => Ok(()),
57    ///         Some(not_ascii) => Err(not_ascii.to_string()),
58    ///     }
59    /// }
60    ///
61    /// fn main() {
62    ///     assert!(run(&["foo", "bar"]).is_ok());
63    ///
64    ///     let err = run(&["foo", "❌", "bar"]).unwrap_err();
65    ///     let printed = format!("{err:#}");
66    ///     let printed = replace_line_numbers(&printed);
67    ///     assert_eq!(printed, indoc::indoc! {"
68    ///         Input is not ASCII: ❌
69    ///         at src/or_wrap_with.rs:1234:56"});
70    /// }
71    /// ```
72    ///
73    /// Please take a look at [`or_wrap`] if you do not want to supply
74    /// the informative message.
75    ///
76    /// [`WrappedError`]: crate::WrappedError
77    /// [`or_wrap`]: crate::OrWrap::or_wrap
78    fn or_wrap_with<I>(self, f: F) -> Result<T, Error<I>>
79    where
80        E: Into<I>;
81}
82
83impl<F, M, T, E> OrWrapWith<F, M, T, E> for Result<T, E>
84where
85    F: FnOnce() -> M,
86    M: Display,
87{
88    #[track_caller]
89    fn or_wrap_with<I>(self, f: F) -> Result<T, Error<I>>
90    where
91        E: Into<I>,
92    {
93        match self {
94            Ok(t) => Ok(t),
95            Err(inner) => Err(Error::wrap_with(inner, f())),
96        }
97    }
98}