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