1use std::future::Future;
8use std::marker::PhantomData;
9use std::pin::Pin;
10
11use crate::body::BoxBody;
12use crate::extract::{FromRequest, FromRequestParts};
13use crate::response::IntoResponse;
14
15#[diagnostic::on_unimplemented(
21 message = "`{Self}` is not a valid handler for arguments `{Args}`",
22 label = "not a valid handler",
23 note = "handlers must be async functions whose arguments implement `FromRequestParts` or `FromRequest`"
24)]
25pub trait Handler<Args>: Clone + Send + Sync + 'static {
26 fn call(
28 self,
29 parts: http::request::Parts,
30 body: bytes::Bytes,
31 ) -> Pin<Box<dyn Future<Output = http::Response<BoxBody>> + Send>>;
32}
33
34impl<F, Fut, Res> Handler<()> for F
39where
40 F: FnOnce() -> Fut + Clone + Send + Sync + 'static,
41 Fut: Future<Output = Res> + Send,
42 Res: IntoResponse,
43{
44 fn call(
45 self,
46 _parts: http::request::Parts,
47 _body: bytes::Bytes,
48 ) -> Pin<Box<dyn Future<Output = http::Response<BoxBody>> + Send>> {
49 Box::pin(async move { self().await.into_response() })
50 }
51}
52
53macro_rules! impl_handler_from_parts {
58 ([$($T:ident),+], [$($t:ident),+]) => {
59 #[allow(non_snake_case)]
60 impl<F, Fut, Res, $($T,)+> Handler<($($T,)+)> for F
61 where
62 F: FnOnce($($T,)+) -> Fut + Clone + Send + Sync + 'static,
63 Fut: Future<Output = Res> + Send,
64 Res: IntoResponse,
65 $($T: FromRequestParts + 'static,)+
66 {
67 fn call(
68 self,
69 parts: http::request::Parts,
70 _body: bytes::Bytes,
71 ) -> Pin<Box<dyn Future<Output = http::Response<BoxBody>> + Send>> {
72 Box::pin(async move {
73 $(
74 let $t = match $T::from_request_parts(&parts) {
75 Ok(v) => v,
76 Err(e) => return e.into_response(),
77 };
78 )+
79 self($($t,)+).await.into_response()
80 })
81 }
82 }
83 };
84}
85
86impl_handler_from_parts!([T1], [t1]);
87impl_handler_from_parts!([T1, T2], [t1, t2]);
88impl_handler_from_parts!([T1, T2, T3], [t1, t2, t3]);
89impl_handler_from_parts!([T1, T2, T3, T4], [t1, t2, t3, t4]);
90impl_handler_from_parts!([T1, T2, T3, T4, T5], [t1, t2, t3, t4, t5]);
91impl_handler_from_parts!([T1, T2, T3, T4, T5, T6], [t1, t2, t3, t4, t5, t6]);
92impl_handler_from_parts!([T1, T2, T3, T4, T5, T6, T7], [t1, t2, t3, t4, t5, t6, t7]);
93impl_handler_from_parts!(
94 [T1, T2, T3, T4, T5, T6, T7, T8],
95 [t1, t2, t3, t4, t5, t6, t7, t8]
96);
97
98pub struct WithBody<Parts, Body>(PhantomData<(Parts, Body)>);
105
106macro_rules! impl_handler_with_body {
107 ([], []) => {
109 impl<F, Fut, Res, B> Handler<WithBody<(), B>> for F
110 where
111 F: FnOnce(B) -> Fut + Clone + Send + Sync + 'static,
112 Fut: Future<Output = Res> + Send,
113 Res: IntoResponse,
114 B: FromRequest + 'static,
115 {
116 fn call(
117 self,
118 parts: http::request::Parts,
119 body: bytes::Bytes,
120 ) -> Pin<Box<dyn Future<Output = http::Response<BoxBody>> + Send>> {
121 Box::pin(async move {
122 let b = match B::from_request(&parts, body).await {
123 Ok(v) => v,
124 Err(e) => return e.into_response(),
125 };
126 self(b).await.into_response()
127 })
128 }
129 }
130 };
131 ([$($T:ident),+], [$($t:ident),+]) => {
132 #[allow(non_snake_case)]
133 impl<F, Fut, Res, $($T,)+ B> Handler<WithBody<($($T,)+), B>> for F
134 where
135 F: FnOnce($($T,)+ B) -> Fut + Clone + Send + Sync + 'static,
136 Fut: Future<Output = Res> + Send,
137 Res: IntoResponse,
138 $($T: FromRequestParts + 'static,)+
139 B: FromRequest + 'static,
140 {
141 fn call(
142 self,
143 parts: http::request::Parts,
144 body: bytes::Bytes,
145 ) -> Pin<Box<dyn Future<Output = http::Response<BoxBody>> + Send>> {
146 Box::pin(async move {
147 $(
148 let $t = match $T::from_request_parts(&parts) {
149 Ok(v) => v,
150 Err(e) => return e.into_response(),
151 };
152 )+
153 let b = match B::from_request(&parts, body).await {
154 Ok(v) => v,
155 Err(e) => return e.into_response(),
156 };
157 self($($t,)+ b).await.into_response()
158 })
159 }
160 }
161 };
162}
163
164impl_handler_with_body!([], []);
165impl_handler_with_body!([T1], [t1]);
166impl_handler_with_body!([T1, T2], [t1, t2]);
167impl_handler_with_body!([T1, T2, T3], [t1, t2, t3]);
168impl_handler_with_body!([T1, T2, T3, T4], [t1, t2, t3, t4]);
169impl_handler_with_body!([T1, T2, T3, T4, T5], [t1, t2, t3, t4, t5]);
170impl_handler_with_body!([T1, T2, T3, T4, T5, T6], [t1, t2, t3, t4, t5, t6]);
171impl_handler_with_body!([T1, T2, T3, T4, T5, T6, T7], [t1, t2, t3, t4, t5, t6, t7]);
172
173pub type ResponseFuture = Pin<Box<dyn Future<Output = http::Response<BoxBody>> + Send>>;
179
180pub type BoxedHandler =
189 std::sync::Arc<dyn Fn(http::request::Parts, bytes::Bytes) -> ResponseFuture + Send + Sync>;
190
191pub fn into_boxed_handler<H, Args>(handler: H) -> BoxedHandler
193where
194 H: Handler<Args>,
195 Args: 'static,
196{
197 std::sync::Arc::new(move |parts, body| {
198 let h = handler.clone();
199 h.call(parts, body)
200 })
201}