xitca_http/util/middleware/
catch_unwind.rs1use core::any::Any;
4
5use xitca_service::{Service, pipeline::PipelineE};
6
7pub struct CatchUnwind;
9
10impl<S, E> Service<Result<S, E>> for CatchUnwind {
11 type Response = service::CatchUnwindService<S>;
12 type Error = E;
13
14 async fn call(&self, arg: Result<S, E>) -> Result<Self::Response, Self::Error> {
15 arg.map(service::CatchUnwindService)
16 }
17}
18
19pub type CatchUnwindError<E> = PipelineE<Box<dyn Any + Send>, E>;
22
23mod service {
24 use core::panic::AssertUnwindSafe;
25
26 use xitca_service::ready::ReadyService;
27 use xitca_unsafe_collection::futures::CatchUnwind;
28
29 use super::*;
30
31 pub struct CatchUnwindService<S>(pub(super) S);
32
33 impl<S, Req> Service<Req> for CatchUnwindService<S>
34 where
35 S: Service<Req>,
36 {
37 type Response = S::Response;
38 type Error = CatchUnwindError<S::Error>;
39
40 async fn call(&self, req: Req) -> Result<Self::Response, Self::Error> {
41 CatchUnwind::new(AssertUnwindSafe(self.0.call(req)))
42 .await
43 .map_err(CatchUnwindError::First)?
44 .map_err(CatchUnwindError::Second)
45 }
46 }
47
48 impl<S> ReadyService for CatchUnwindService<S>
49 where
50 S: ReadyService,
51 {
52 type Ready = S::Ready;
53
54 #[inline]
55 async fn ready(&self) -> Self::Ready {
56 self.0.ready().await
57 }
58 }
59}