grid_sdk/error/internal.rs
1// Copyright 2018-2020 Cargill Incorporated
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Module containing InternalError implementation.
16
17use std::error;
18use std::fmt;
19
20struct Source {
21 prefix: Option<String>,
22 source: Box<dyn error::Error>,
23}
24
25/// An error which is returned for reasons internal to the function.
26///
27/// This error is produced when a failure occurred within the function but the failure is due to an
28/// internal implementation detail of the function. This generally means that there is no specific
29/// information which can be returned that would help the caller of the function recover or
30/// otherwise take action.
31pub struct InternalError {
32 message: Option<String>,
33 source: Option<Source>,
34}
35
36impl InternalError {
37 /// Constructs a new `InternalError` from a specified source error.
38 ///
39 /// The implementation of `std::fmt::Display` for this error will simply pass through the
40 /// display of the source message unmodified.
41 ///
42 /// # Examples
43 ///
44 /// ```
45 /// use grid_sdk::error::InternalError;
46 ///
47 /// let io_err = std::io::Error::new(std::io::ErrorKind::Other, "io error");
48 /// let internal_error = InternalError::from_source(Box::new(io_err));
49 /// assert_eq!(format!("{}", internal_error), "io error");
50 /// ```
51 pub fn from_source(source: Box<dyn error::Error>) -> Self {
52 Self {
53 message: None,
54 source: Some(Source {
55 prefix: None,
56 source,
57 }),
58 }
59 }
60
61 /// Constructs a new `InternalError` from a specified source error and message string.
62 ///
63 /// The implementation of `std::fmt::Display` for this error will be the message string
64 /// provided.
65 ///
66 /// # Examples
67 ///
68 /// ```
69 /// use grid_sdk::error::InternalError;
70 ///
71 /// let io_err = std::io::Error::new(std::io::ErrorKind::Other, "io error");
72 /// let internal_error = InternalError::from_source_with_message(Box::new(io_err), "oops".to_string());
73 /// assert_eq!(format!("{}", internal_error), "oops");
74 /// ```
75 pub fn from_source_with_message(source: Box<dyn error::Error>, message: String) -> Self {
76 Self {
77 message: Some(message),
78 source: Some(Source {
79 prefix: None,
80 source,
81 }),
82 }
83 }
84
85 /// Constructs a new `InternalError` from a specified source error and prefix string.
86 ///
87 /// The implementation of `std::fmt::Display` for this error will be constructed from the
88 /// prefix and source message's display following the format of `format!("{}: {}", prefix,
89 /// source)`.
90 ///
91 /// # Examples
92 ///
93 /// ```
94 /// use grid_sdk::error::InternalError;
95 ///
96 /// let io_err = std::io::Error::new(std::io::ErrorKind::Other, "io error");
97 /// let internal_error = InternalError::from_source_with_prefix(Box::new(io_err), "Could not open file".to_string());
98 /// assert_eq!(format!("{}", internal_error), "Could not open file: io error");
99 /// ```
100 pub fn from_source_with_prefix(source: Box<dyn error::Error>, prefix: String) -> Self {
101 Self {
102 message: None,
103 source: Some(Source {
104 prefix: Some(prefix),
105 source,
106 }),
107 }
108 }
109
110 /// Constructs a new `InternalError` with a specified message string.
111 ///
112 /// The implementation of `std::fmt::Display` for this error will be the message string
113 /// provided.
114 ///
115 /// # Examples
116 ///
117 /// ```
118 /// use grid_sdk::error::InternalError;
119 ///
120 /// let internal_error = InternalError::with_message("oops".to_string());
121 /// assert_eq!(format!("{}", internal_error), "oops");
122 /// ```
123 pub fn with_message(message: String) -> Self {
124 Self {
125 message: Some(message),
126 source: None,
127 }
128 }
129}
130
131#[cfg(feature = "client-reqwest")]
132impl From<reqwest::Error> for InternalError {
133 fn from(err: reqwest::Error) -> Self {
134 InternalError::with_message(format!("{}", err))
135 }
136}
137
138impl error::Error for InternalError {
139 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
140 self.source.as_ref().map(|s| s.source.as_ref())
141 }
142}
143
144impl fmt::Display for InternalError {
145 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146 match &self.message {
147 Some(m) => write!(f, "{}", m),
148 None => match &self.source {
149 Some(s) => match &s.prefix {
150 Some(p) => write!(f, "{}: {}", p, s.source),
151 None => write!(f, "{}", s.source),
152 },
153 None => write!(f, "{}", std::any::type_name::<InternalError>()),
154 },
155 }
156 }
157}
158
159impl fmt::Debug for InternalError {
160 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161 const TYPE_NAME: &str = "InternalError";
162
163 match &self.message {
164 Some(m) => match &self.source {
165 Some(s) => write!(
166 f,
167 "{} {{ message: {:?}, source: {:?} }}",
168 TYPE_NAME, m, s.source
169 ),
170 None => write!(f, "{} {{ message: {:?} }}", TYPE_NAME, m),
171 },
172 None => match &self.source {
173 Some(s) => match &s.prefix {
174 Some(p) => write!(
175 f,
176 "{} {{ prefix: {:?}, source: {:?} }}",
177 TYPE_NAME, p, s.source
178 ),
179 None => write!(f, "{} {{ source: {:?} }}", TYPE_NAME, s.source),
180 },
181 None => write!(f, "{}", TYPE_NAME),
182 },
183 }
184 }
185}
186
187#[cfg(test)]
188pub mod tests {
189 use super::*;
190
191 /// Tests that errors constructed with `InternalError::from_source` return a debug string of
192 /// the form `format!("InternalError { {:?} }", source)`.
193 #[test]
194 fn test_debug_from_source() {
195 let msg = "test message";
196 let debug = "InternalError { source: InternalError { message: \"test message\" } }";
197 let err =
198 InternalError::from_source(Box::new(InternalError::with_message(msg.to_string())));
199 assert_eq!(format!("{:?}", err), debug);
200 }
201
202 /// Tests that errors constructed with `InternalError::from_source_with_message` return a debug
203 /// string of the form `format!("InternalError { message: {:?}, source: {:?} }", message,
204 /// source)`.
205 #[test]
206 fn test_debug_from_source_with_message() {
207 let msg = "test message";
208 let debug = "InternalError { message: \"test message\", source: InternalError { message: \"unused\" } }";
209 let err = InternalError::from_source_with_message(
210 Box::new(InternalError::with_message("unused".to_string())),
211 msg.to_string(),
212 );
213 assert_eq!(format!("{:?}", err), debug);
214 }
215
216 /// Tests that errors constructed with `InternalError::from_source_with_prefix` return a debug
217 /// string of the form `format!("InternalError { prefix: {:?}, source: {:?} }", prefix,
218 /// source)`.
219 #[test]
220 fn test_debug_from_source_with_prefix() {
221 let prefix = "test prefix";
222 let msg = "test message";
223 let debug = "InternalError { prefix: \"test prefix\", source: InternalError { message: \"test message\" } }";
224 let err = InternalError::from_source_with_prefix(
225 Box::new(InternalError::with_message(msg.to_string())),
226 prefix.to_string(),
227 );
228 assert_eq!(format!("{:?}", err), debug);
229 }
230
231 /// Tests that errors constructed with `InternalError::with_message` return a debug
232 /// string of the form `format!("InternalError { message: {:?} }", message)`.
233 #[test]
234 fn test_debug_with_message() {
235 let msg = "test message";
236 let debug = "InternalError { message: \"test message\" }";
237 let err = InternalError::with_message(msg.to_string());
238 assert_eq!(format!("{:?}", err), debug);
239 }
240
241 /// Tests that error constructed with `InternalError::from_source` return a display
242 /// string which is the same as the source's display string.
243 #[test]
244 fn test_display_from_source() {
245 let msg = "test message";
246 let err =
247 InternalError::from_source(Box::new(InternalError::with_message(msg.to_string())));
248 assert_eq!(format!("{}", err), msg);
249 }
250
251 /// Tests that error constructed with `InternalError::from_source_with_message` return
252 /// message as the display string.
253 #[test]
254 fn test_display_from_source_with_message() {
255 let msg = "test message";
256 let err = InternalError::from_source_with_message(
257 Box::new(InternalError::with_message("unused".to_string())),
258 msg.to_string(),
259 );
260 assert_eq!(format!("{}", err), msg);
261 }
262
263 /// Tests that error constructed with `InternalError::from_source_with_message` return
264 /// a display string of the form `format!("{}: {}", prefix, source)`.
265 #[test]
266 fn test_display_from_source_with_prefix() {
267 let prefix = "test prefix";
268 let msg = "test message";
269 let err = InternalError::from_source_with_prefix(
270 Box::new(InternalError::with_message(msg.to_string())),
271 prefix.to_string(),
272 );
273 assert_eq!(format!("{}", err), format!("{}: {}", prefix, msg));
274 }
275
276 /// Tests that error constructed with `InternalError::with_message` return message as the
277 /// display string.
278 #[test]
279 fn test_display_with_message() {
280 let msg = "test message";
281 let err = InternalError::with_message(msg.to_string());
282 assert_eq!(format!("{}", err), msg);
283 }
284}