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}