human_errors/
result.rs

1use std::borrow::Cow;
2
3use super::*;
4
5/// Extension trait for `Result` to convert errors into user-friendly or
6/// system-friendly `Error` types.
7///
8/// # Examples
9/// ```
10/// use human_errors::ResultExt;
11///
12/// // Converts any error into a user-caused error with the provided advice.
13/// "0.not a number".parse::<i32>()
14///     .map_err_as_user(&["Please provide a valid integer input."]);
15///
16/// // Converts any error into a system-caused error with the provided advice.
17/// "0.not a number".parse::<i32>()
18///     .map_err_as_system(&["Please check your system configuration."]);
19///
20/// // Wraps any error into a user-caused error with a custom message and advice.
21/// "0.not a number".parse::<i32>()
22///     .wrap_err_as_user(
23///         "Failed to parse the provided input as an integer.",
24///         &["Please provide a valid integer input."],
25///     );
26///
27/// // Wraps any error into a system-caused error with a custom message and advice.
28/// "0.not a number".parse::<i32>()
29///     .wrap_err_as_system(
30///         "Failed to parse the provided input as an integer.",
31///         &["Please check your system configuration."],
32///     );
33/// ```
34pub trait ResultExt<T> {
35    /// Converts a `Result<T, E>` into a `Result<T, Error>`, wrapping any
36    /// error in a user-facing error with the provided advice.
37    ///
38    /// # Examples
39    /// ```
40    /// use human_errors::ResultExt;
41    ///
42    /// "0.not a number".parse::<i32>()
43    ///     .or_user_err(&["Please provide a valid integer input."]);
44    /// ```
45    fn or_user_err(self, advice: &'static [&'static str]) -> Result<T, Error>;
46
47    /// Converts a `Result<T, E>` into a `Result<T, Error>`, wrapping any
48    /// error in a user-facing error with the provided description and advice.
49    ///
50    /// # Examples
51    /// ```
52    /// use human_errors::ResultExt;
53    ///
54    /// "0.not a number".parse::<i32>()
55    ///     .wrap_user_err(
56    ///         "Failed to parse the provided input as an integer.",
57    ///         &["Please provide a valid integer input."],
58    ///     );
59    /// ```
60    fn wrap_user_err<S: Into<Cow<'static, str>> + 'static>(
61        self,
62        message: S,
63        advice: &'static [&'static str],
64    ) -> Result<T, Error>;
65
66    /// Converts a `Result<T, E>` into a `Result<T, Error>`, wrapping any
67    /// error in a system-facing error with the provided advice.
68    /// 
69    /// # Examples
70    /// ```
71    /// use human_errors::ResultExt;
72    /// 
73    /// "0.not a number".parse::<i32>()
74    ///    .or_system_err(&["Please report this issue to the dev team."]);
75    /// ```
76    fn or_system_err(self, advice: &'static [&'static str]) -> Result<T, Error>;
77
78    /// Converts a `Result<T, E>` into a `Result<T, Error>`, wrapping any
79    /// error in a system-facing error with the provided description and advice.
80    /// 
81    /// # Examples
82    /// ```
83    /// use human_errors::ResultExt;
84    ///
85    /// "0.not a number".parse::<i32>()
86    ///     .wrap_system_err(
87    ///         "Failed to parse the provided input as an integer.",
88    ///         &["Please report this issue to the dev team."],
89    ///     );
90    /// ```
91    fn wrap_system_err<S: Into<Cow<'static, str>> + 'static>(
92        self,
93        message: S,
94        advice: &'static [&'static str],
95    ) -> Result<T, Error>;
96
97    /// Converts a `Result<T, E>` into a `Result<T, Error>`, wrapping any
98    /// error in a user-facing error with the provided advice.
99    ///
100    /// # Examples
101    /// ```
102    /// use human_errors::ResultExt;
103    ///
104    /// "0.not a number".parse::<i32>()
105    ///     .map_err_as_user(&["Please provide a valid integer input."]);
106    /// ```
107    #[deprecated(
108        since = "0.2.3",
109        note = "We are updating the interface to match the Rust stdlib style. Please use `or_user_err` method instead."
110    )]
111    fn map_err_as_user(self, advice: &'static [&'static str]) -> Result<T, Error>;
112
113    /// Converts a `Result<T, E>` into a `Result<T, Error>`, wrapping any
114    /// error in a user-facing error with the provided description and advice.
115    ///
116    /// # Examples
117    /// ```
118    /// use human_errors::ResultExt;
119    ///
120    /// "0.not a number".parse::<i32>()
121    ///     .wrap_err_as_user(
122    ///         "Failed to parse the provided input as an integer.",
123    ///         &["Please provide a valid integer input."],
124    ///     );
125    /// ```
126    #[deprecated(
127        since = "0.2.3",
128        note = "We are updating the interface to match the Rust stdlib style. Please use `wrap_user_err` method instead."
129    )]
130    fn wrap_err_as_user<S: Into<Cow<'static, str>> + 'static>(
131        self,
132        message: S,
133        advice: &'static [&'static str],
134    ) -> Result<T, Error>;
135
136    /// Converts a `Result<T, E>` into a `Result<T, Error>`, wrapping any
137    /// error in a system-facing error with the provided advice.
138    ///
139    /// # Examples
140    /// ```
141    /// use human_errors::ResultExt;
142    ///
143    /// "0.not a number".parse::<i32>()
144    ///     .map_err_as_system(&["Please report this issue to the dev team."]);
145    /// ```
146    #[deprecated(
147        since = "0.2.3",
148        note = "We are updating the interface to match the Rust stdlib style. Please use `or_system_err` method instead."
149    )]
150    fn map_err_as_system(self, advice: &'static [&'static str]) -> Result<T, Error>;
151
152    /// Converts a `Result<T, E>` into a `Result<T, Error>`, wrapping any
153    /// error in a system-facing error with the provided description and advice.
154    /// 
155    /// # Examples
156    /// ```
157    /// use human_errors::ResultExt;
158    ///
159    /// "0.not a number".parse::<i32>()
160    ///     .wrap_err_as_system(
161    ///         "Failed to parse the provided input as an integer.",
162    ///         &["Please report this issue to the dev team."],
163    ///     );
164    /// ```
165    #[deprecated(
166        since = "0.2.3",
167        note = "We are updating the interface to match the Rust stdlib style. Please use `wrap_system_err` method instead."
168    )]
169    fn wrap_err_as_system<S: Into<Cow<'static, str>> + 'static>(
170        self,
171        message: S,
172        advice: &'static [&'static str],
173    ) -> Result<T, Error>;
174}
175
176impl<T, E> ResultExt<T> for Result<T, E>
177where
178    E: Into<Box<dyn std::error::Error + Send + Sync>> + 'static,
179{
180    fn or_user_err(self, advice: &'static [&'static str]) -> Result<T, Error> {
181        self.map_err(|e| user(e, advice))
182    }
183
184    fn wrap_user_err<S: Into<Cow<'static, str>> + 'static>(
185        self,
186        message: S,
187        advice: &'static [&'static str],
188    ) -> Result<T, Error> {
189        self.map_err(|e| wrap_user(e, message, advice))
190    }
191
192    fn or_system_err(self, advice: &'static [&'static str]) -> Result<T, Error> {
193        self.map_err(|e| system(e, advice))
194    }
195
196    fn wrap_system_err<S: Into<Cow<'static, str>> + 'static>(
197            self,
198            message: S,
199            advice: &'static [&'static str],
200        ) -> Result<T, Error> {
201        self.map_err(|e| wrap_system(e, message, advice))
202    }
203
204    fn map_err_as_user(self, advice: &'static [&'static str]) -> Result<T, Error> {
205        self.map_err(|e| user(e, advice))
206    }
207
208    fn wrap_err_as_user<S: Into<Cow<'static, str>> + 'static>(
209        self,
210        message: S,
211        advice: &'static [&'static str],
212    ) -> Result<T, Error> {
213        self.map_err(|e| user(wrap_user(e, message, advice), advice))
214    }
215
216    fn map_err_as_system(self, advice: &'static [&'static str]) -> Result<T, Error> {
217        self.map_err(|e| system(e, advice))
218    }
219
220    fn wrap_err_as_system<S: Into<Cow<'static, str>> + 'static>(
221        self,
222        message: S,
223        advice: &'static [&'static str],
224    ) -> Result<T, Error> {
225        self.map_err(|e| system(wrap_system(e, message, advice), advice))
226    }
227}
228
229#[cfg(test)]
230mod tests {
231    use super::*;
232
233    #[test]
234    fn test_or_user_error() {
235        let result: Result<i32, std::io::Error> = Err(std::io::Error::other("underlying error"));
236
237        let user_error = result
238            .or_user_err(&["Please check your input and try again."])
239            .err()
240            .unwrap();
241
242        assert!(user_error.is(Kind::User));
243    }
244
245    #[test]
246    fn test_wrap_user_error() {
247        let result: Result<i32, std::io::Error> = Err(std::io::Error::other("underlying error"));
248
249        let user_error = result
250            .wrap_user_err(
251                "Failed to process the input.",
252                &["Please check your input and try again."],
253            )
254            .err()
255            .unwrap();
256
257        assert!(user_error.is(Kind::User));
258        assert_eq!(user_error.message(), "Failed to process the input.");
259    }
260
261    #[test]
262    fn test_or_system_error() {
263        let result: Result<i32, std::io::Error> = Err(std::io::Error::other("underlying error"));
264
265        let system_error = result
266            .or_system_err(&["Please check your input and try again."])
267            .err()
268            .unwrap();
269
270        assert!(system_error.is(Kind::System));
271    }
272
273    #[test]
274    fn test_wrap_system_error() {
275        let result: Result<i32, std::io::Error> = Err(std::io::Error::other("underlying error"));
276        let system_error = result
277            .wrap_system_err(
278                "Failed to process the input.",
279                &["Please check your input and try again."],
280            )
281            .err()
282            .unwrap();
283        assert!(system_error.is(Kind::System));
284        assert_eq!(system_error.message(), "Failed to process the input.");
285    }
286}