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 /// .map_err_as_user(&["Please provide a valid integer input."]);
44 /// ```
45 fn map_err_as_user(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_err_as_user(
56 /// "Failed to parse the provided input as an integer.",
57 /// &["Please provide a valid integer input."],
58 /// );
59 /// ```
60 fn wrap_err_as_user<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 /// .map_err_as_system(&["Please report this issue to the dev team."]);
75 /// ```
76 fn map_err_as_system(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 /// # Examples
81 /// ```
82 /// use human_errors::ResultExt;
83 ///
84 /// "0.not a number".parse::<i32>()
85 /// .wrap_err_as_system(
86 /// "Failed to parse the provided input as an integer.",
87 /// &["Please report this issue to the dev team."],
88 /// );
89 /// ```
90 fn wrap_err_as_system<S: Into<Cow<'static, str>> + 'static>(
91 self,
92 message: S,
93 advice: &'static [&'static str],
94 ) -> Result<T, Error>;
95}
96
97impl<T, E> ResultExt<T> for Result<T, E>
98where
99 E: Into<Box<dyn std::error::Error + Send + Sync>> + 'static,
100{
101 fn map_err_as_user(self, advice: &'static [&'static str]) -> Result<T, Error> {
102 self.map_err(|e| user(e, advice))
103 }
104
105 fn wrap_err_as_user<S: Into<Cow<'static, str>> + 'static>(
106 self,
107 message: S,
108 advice: &'static [&'static str],
109 ) -> Result<T, Error> {
110 self.map_err(|e| user(wrap_user(e, message, advice), advice))
111 }
112
113 fn map_err_as_system(self, advice: &'static [&'static str]) -> Result<T, Error> {
114 self.map_err(|e| system(e, advice))
115 }
116
117 fn wrap_err_as_system<S: Into<Cow<'static, str>> + 'static>(
118 self,
119 message: S,
120 advice: &'static [&'static str],
121 ) -> Result<T, Error> {
122 self.map_err(|e| system(wrap_system(e, message, advice), advice))
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn test_into_user_error() {
132 let result: Result<i32, std::io::Error> = Err(std::io::Error::other("underlying error"));
133
134 let user_error = result
135 .map_err_as_user(&["Please check your input and try again."])
136 .err()
137 .unwrap();
138
139 assert!(user_error.is(Kind::User));
140 }
141
142 #[test]
143 fn test_into_system_error() {
144 let result: Result<i32, std::io::Error> = Err(std::io::Error::other("underlying error"));
145
146 let system_error = result
147 .map_err_as_system(&["Please check your input and try again."])
148 .err()
149 .unwrap();
150
151 assert!(system_error.is(Kind::System));
152 }
153}