1use crate::logging::trace;
12use crate::{Error, HttpRequest, HttpResponse};
13use std::future::Future;
14use std::marker::PhantomData;
15use std::pin::Pin;
16use std::sync::Arc;
17
18pub trait Handler: Clone + Send + Sync + 'static {
34 type Future: Future<Output = Result<HttpResponse, Error>> + Send + 'static;
39
40 fn call(&self, req: HttpRequest) -> Self::Future;
45}
46
47pub trait IntoHandler<Args>: Clone + Send + Sync + 'static {
54 type Handler: Handler;
56
57 fn into_handler(self) -> Self::Handler;
59}
60
61#[derive(Clone)]
65pub struct FnHandler<F> {
66 f: F,
67}
68
69impl<F> FnHandler<F> {
70 #[inline(always)]
72 pub fn new(f: F) -> Self {
73 Self { f }
74 }
75}
76
77impl<F, Fut> Handler for FnHandler<F>
78where
79 F: Fn(HttpRequest) -> Fut + Clone + Send + Sync + 'static,
80 Fut: Future<Output = Result<HttpResponse, Error>> + Send + 'static,
81{
82 type Future = Fut;
83
84 #[inline(always)]
85 fn call(&self, req: HttpRequest) -> Self::Future {
86 (self.f)(req)
87 }
88}
89
90impl<F, Fut> IntoHandler<(HttpRequest,)> for F
92where
93 F: Fn(HttpRequest) -> Fut + Clone + Send + Sync + 'static,
94 Fut: Future<Output = Result<HttpResponse, Error>> + Send + 'static,
95{
96 type Handler = FnHandler<F>;
97
98 #[inline(always)]
99 fn into_handler(self) -> Self::Handler {
100 FnHandler::new(self)
101 }
102}
103
104pub struct BoxedHandler {
112 inner: Arc<dyn ErasedHandler>,
113}
114
115impl BoxedHandler {
116 #[inline]
120 pub fn new<H: Handler>(handler: H) -> Self {
121 Self {
122 inner: Arc::new(HandlerWrapper {
123 handler,
124 _marker: PhantomData,
125 }),
126 }
127 }
128
129 #[inline(always)]
134 pub fn call(
135 &self,
136 req: HttpRequest,
137 ) -> Pin<Box<dyn Future<Output = Result<HttpResponse, Error>> + Send>> {
138 trace!(path = %req.path, method = %req.method, "Handler dispatch");
139 self.inner.call(req)
140 }
141}
142
143impl Clone for BoxedHandler {
144 #[inline]
145 fn clone(&self) -> Self {
146 Self {
147 inner: self.inner.clone(),
148 }
149 }
150}
151
152trait ErasedHandler: Send + Sync {
157 fn call(
158 &self,
159 req: HttpRequest,
160 ) -> Pin<Box<dyn Future<Output = Result<HttpResponse, Error>> + Send>>;
161}
162
163struct HandlerWrapper<H: Handler> {
169 handler: H,
170 _marker: PhantomData<fn() -> H::Future>,
171}
172
173unsafe impl<H: Handler> Send for HandlerWrapper<H> {}
175unsafe impl<H: Handler> Sync for HandlerWrapper<H> {}
176
177impl<H: Handler> ErasedHandler for HandlerWrapper<H> {
178 #[inline(always)]
179 fn call(
180 &self,
181 req: HttpRequest,
182 ) -> Pin<Box<dyn Future<Output = Result<HttpResponse, Error>> + Send>> {
183 Box::pin(self.handler.call(req))
186 }
187}
188
189pub type OptimizedHandlerFn = BoxedHandler;
194
195#[inline]
209pub fn handler<H, Args>(h: H) -> BoxedHandler
210where
211 H: IntoHandler<Args>,
212{
213 BoxedHandler::new(h.into_handler())
214}
215
216#[allow(clippy::type_complexity)]
221pub type LegacyHandlerFn = Arc<
222 dyn Fn(HttpRequest) -> Pin<Box<dyn Future<Output = Result<HttpResponse, Error>> + Send>>
223 + Send
224 + Sync,
225>;
226
227#[inline]
232pub fn from_legacy_handler(f: LegacyHandlerFn) -> BoxedHandler {
233 BoxedHandler::new(LegacyHandler { f })
234}
235
236#[derive(Clone)]
238struct LegacyHandler {
239 f: LegacyHandlerFn,
240}
241
242impl Handler for LegacyHandler {
243 type Future = Pin<Box<dyn Future<Output = Result<HttpResponse, Error>> + Send>>;
244
245 #[inline(always)]
246 fn call(&self, req: HttpRequest) -> Self::Future {
247 (self.f)(req)
248 }
249}
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254
255 async fn test_handler(_req: HttpRequest) -> Result<HttpResponse, Error> {
256 Ok(HttpResponse::ok())
257 }
258
259 #[tokio::test]
260 async fn test_fn_handler() {
261 let handler = FnHandler::new(test_handler);
262 let req = HttpRequest::new("GET".to_string(), "/test".to_string());
263 let response = handler.call(req).await.unwrap();
264 assert_eq!(response.status, 200);
265 }
266
267 #[tokio::test]
268 async fn test_into_handler() {
269 let handler = test_handler.into_handler();
270 let req = HttpRequest::new("GET".to_string(), "/test".to_string());
271 let response = handler.call(req).await.unwrap();
272 assert_eq!(response.status, 200);
273 }
274
275 #[tokio::test]
276 async fn test_boxed_handler() {
277 let boxed = BoxedHandler::new(test_handler.into_handler());
278 let req = HttpRequest::new("GET".to_string(), "/test".to_string());
279 let response = boxed.call(req).await.unwrap();
280 assert_eq!(response.status, 200);
281 }
282
283 #[tokio::test]
284 async fn test_handler_fn() {
285 let h = handler(test_handler);
286 let req = HttpRequest::new("GET".to_string(), "/test".to_string());
287 let response = h.call(req).await.unwrap();
288 assert_eq!(response.status, 200);
289 }
290
291 #[tokio::test]
292 async fn test_clone_boxed_handler() {
293 let h1 = handler(test_handler);
294 let h2 = h1.clone();
295
296 let req1 = HttpRequest::new("GET".to_string(), "/test".to_string());
297 let req2 = HttpRequest::new("GET".to_string(), "/test".to_string());
298
299 let r1 = h1.call(req1).await.unwrap();
300 let r2 = h2.call(req2).await.unwrap();
301
302 assert_eq!(r1.status, 200);
303 assert_eq!(r2.status, 200);
304 }
305
306 #[test]
307 fn test_handler_is_send_sync() {
308 fn assert_send_sync<T: Send + Sync>() {}
309 assert_send_sync::<BoxedHandler>();
310 }
311}