argan_core/response/
error.rs1use std::{
2 any::{Any, TypeId},
3 fmt::{self, Display, Formatter},
4};
5
6use http::StatusCode;
7
8use crate::{body::Body, marker, BoxedError, StdError, SCOPE_VALIDITY};
9
10use super::{BoxedErrorResponse, IntoResponse, Response};
11
12#[derive(Debug)]
21pub struct ResponseError {
22 status_code: StatusCode,
23 some_boxed_error: Option<BoxedError>,
24}
25
26impl ResponseError {
27 pub fn new<E>(status_code: StatusCode, error: E) -> Self
28 where
29 E: StdError + Send + Sync + 'static,
30 {
31 ResponseError {
32 status_code,
33 some_boxed_error: Some(error.into()),
34 }
35 }
36
37 pub fn from_error<E>(error: E) -> Self
38 where
39 E: StdError + Send + Sync + 'static,
40 {
41 ResponseError {
42 status_code: StatusCode::INTERNAL_SERVER_ERROR,
43 some_boxed_error: Some(error.into()),
44 }
45 }
46
47 pub fn status_code(&self) -> StatusCode {
48 self.status_code
49 }
50}
51
52impl From<StatusCode> for ResponseError {
53 fn from(status_code: StatusCode) -> Self {
54 ResponseError {
55 status_code,
56 some_boxed_error: None,
57 }
58 }
59}
60
61impl Display for ResponseError {
62 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
63 f.write_fmt(format_args!("[{}]", self.status_code))?;
64
65 if let Some(boxed_error) = self.some_boxed_error.as_ref() {
66 f.write_fmt(format_args!(" {}", boxed_error))?
67 }
68
69 Ok(())
70 }
71}
72
73impl StdError for ResponseError {
74 fn source(&self) -> Option<&(dyn StdError + 'static)> {
75 self
76 .some_boxed_error
77 .as_ref()
78 .map(|boxed_error| boxed_error.as_ref() as &(dyn StdError + 'static))
79 }
80}
81
82impl IntoResponse for ResponseError {
83 fn into_response(self) -> Response {
84 let mut response = self.status_code.into_response();
85
86 if let Some(boxed_error) = self.some_boxed_error {
87 *response.body_mut() = Body::new(boxed_error.to_string())
88 }
89
90 response
91 }
92}
93
94pub trait ErrorResponse: StdError + IntoResponse + 'static {
99 #[doc(hidden)]
100 fn concrete_type_id(&self, _: marker::Private) -> TypeId {
101 TypeId::of::<Self>()
102 }
103
104 #[doc(hidden)]
105 fn as_any_ref(&self, _: marker::Private) -> &dyn Any;
106
107 #[doc(hidden)]
108 fn as_any_mut(&mut self, _: marker::Private) -> &mut dyn Any;
109
110 #[doc(hidden)]
111 fn into_boxed_any(self: Box<Self>, _: marker::Private) -> Box<dyn Any>;
112
113 #[doc(hidden)]
114 fn concrete_into_response(self: Box<Self>, _: marker::Private) -> Response;
115
116 fn into_error_result(self) -> Result<Response, BoxedErrorResponse>
118 where
119 Self: Sized + Send + Sync,
120 {
121 Err(self.into())
122 }
123}
124
125impl dyn ErrorResponse + Send + Sync {
126 pub fn implementor_type_id(&self) -> TypeId {
128 ErrorResponse::concrete_type_id(self, marker::Private)
129 }
130
131 pub fn is<E: Any + 'static>(&self) -> bool {
133 let self_id = ErrorResponse::concrete_type_id(self, marker::Private);
134 let param_id = TypeId::of::<E>();
135
136 self_id == param_id
137 }
138
139 pub fn downcast_to<E: Any + 'static>(self: Box<Self>) -> Result<Box<E>, Box<Self>> {
141 if self.is::<E>() {
142 Ok(
143 self
144 .into_boxed_any(marker::Private)
145 .downcast()
146 .expect(SCOPE_VALIDITY),
147 )
148 } else {
149 Err(self)
150 }
151 }
152
153 pub fn downcast_to_ref<E: Any + 'static>(&self) -> Option<&E> {
155 self.as_any_ref(marker::Private).downcast_ref()
156 }
157
158 pub fn downcast_to_mut<E: Any + 'static>(&mut self) -> Option<&mut E> {
160 self.as_any_mut(marker::Private).downcast_mut()
161 }
162
163 pub fn into_response(self: Box<Self>) -> Response {
165 self.concrete_into_response(marker::Private)
166 }
167}
168
169impl<E> ErrorResponse for E
170where
171 E: StdError + IntoResponse + Send + Sync + 'static,
172{
173 #[doc(hidden)]
174 fn into_boxed_any(self: Box<Self>, _: marker::Private) -> Box<dyn Any> {
175 self
176 }
177
178 #[doc(hidden)]
179 fn as_any_ref(&self, _: marker::Private) -> &dyn Any {
180 self
181 }
182
183 #[doc(hidden)]
184 fn as_any_mut(&mut self, _: marker::Private) -> &mut dyn Any {
185 self
186 }
187
188 #[doc(hidden)]
189 fn concrete_into_response(self: Box<Self>, _: marker::Private) -> Response {
190 let e = (self as Box<dyn Any>)
191 .downcast::<E>()
192 .expect(SCOPE_VALIDITY);
193
194 (*e).into_response()
195 }
196}
197
198impl<E: ErrorResponse + Send + Sync> From<E> for BoxedErrorResponse {
199 fn from(error_response: E) -> Self {
200 Box::new(error_response)
201 }
202}
203
204#[cfg(test)]
207mod test {
208 use std::fmt::Display;
209
210 use crate::response::IntoResponseResult;
211
212 use super::*;
213
214 #[derive(Debug)]
218 struct Failure;
219
220 impl Display for Failure {
221 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
222 write!(f, "failure")
223 }
224 }
225
226 impl StdError for Failure {}
227
228 #[test]
231 fn response_error() {
232 let response_error = ResponseError::from(StatusCode::BAD_REQUEST);
233 println!("{}", response_error);
234 assert_eq!("[400 Bad Request]", response_error.to_string());
235
236 let response_error = ResponseError::new(StatusCode::UNAUTHORIZED, Failure);
237 println!("{}", response_error);
238 assert_eq!("[401 Unauthorized] failure", response_error.to_string());
239
240 let response_error = ResponseError::from_error(Failure);
241 println!("{}", response_error);
242 assert_eq!(
243 "[500 Internal Server Error] failure",
244 response_error.to_string()
245 );
246
247 let response_error = ResponseError::from_error(Failure);
248 assert!(response_error
249 .source()
250 .is_some_and(|error| error.is::<Failure>()));
251
252 let boxed_error_response = Box::new(response_error) as BoxedErrorResponse;
253 assert!(boxed_error_response
254 .source()
255 .is_some_and(|error| error.is::<Failure>()));
256
257 let response_error = ResponseError::from(StatusCode::INTERNAL_SERVER_ERROR);
260 let result = response_error.into_error_result();
261 assert!(result.is_err());
262 }
263
264 #[derive(Debug, PartialEq)]
267 struct E;
268
269 impl Display for E {
270 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271 write!(f, "E")
272 }
273 }
274
275 impl StdError for E {}
276
277 impl IntoResponse for E {
278 fn into_response(self) -> Response {
279 ().into_response()
280 }
281 }
282
283 #[derive(Debug, PartialEq)]
286 struct A;
287
288 impl Display for A {
289 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 write!(f, "A")
291 }
292 }
293
294 impl StdError for A {}
295
296 impl IntoResponse for A {
297 fn into_response(self) -> Response {
298 ().into_response()
299 }
300 }
301
302 #[test]
305 fn error_response() {
306 let mut error = Box::new(E) as BoxedErrorResponse;
307 assert_eq!(TypeId::of::<E>(), error.implementor_type_id());
308 assert!(error.is::<E>());
309 assert_eq!(Some(&mut E), error.downcast_to_mut::<E>());
310 assert_eq!(Some(&E), error.downcast_to_ref::<E>());
311 assert_eq!(E, error.downcast_to::<E>().map(|boxed| *boxed).unwrap());
312
313 let mut error = Box::new(A) as BoxedErrorResponse;
316 assert_eq!(
317 TypeId::of::<A>(),
318 <dyn ErrorResponse + Send + Sync>::implementor_type_id(error.as_ref())
319 );
320 assert!(error.is::<A>());
321 assert!(!error.is::<E>());
322 assert_eq!(Some(&mut A), error.downcast_to_mut::<A>());
323 assert_eq!(Some(&A), error.downcast_to_ref::<A>());
324 assert_eq!(None, error.downcast_to_mut::<E>());
325 assert_eq!(None, error.downcast_to_ref::<E>());
326
327 let result = error.downcast_to::<E>();
328 assert!(result.is_err());
329 assert_eq!(
330 A,
331 result
332 .unwrap_err()
333 .downcast_to::<A>()
334 .map(|boxed| *boxed)
335 .unwrap()
336 );
337
338 let error = Box::new(A) as BoxedErrorResponse;
341 assert_eq!(
342 A,
343 error
344 .downcast_to::<E>()
345 .unwrap_err()
346 .downcast_to::<A>()
347 .map(|boxed| *boxed)
348 .unwrap()
349 );
350
351 let response_result = E.into_error_result();
354 assert!(response_result.is_err());
355
356 let response_result = E.into_response_result();
357 assert!(response_result.is_ok());
358 }
359}
360
361