xitca_http/util/service/
handler.rs

1//! high level async function service with "variadic generic" ish.
2
3#![allow(non_snake_case)]
4
5use core::{convert::Infallible, marker::PhantomData, net::SocketAddr};
6
7use xitca_service::{Service, pipeline::PipelineE};
8
9use crate::http::{BorrowReq, Extensions, HeaderMap, Method, Request, RequestExt, Uri};
10
11/// A service factory shortcut offering given async function ability to use [FromRequest] to destruct and transform `Service<Req>`'s
12/// `Req` type and receive them as function argument.
13///
14/// Given async function's return type must impl [Responder] trait for transforming arbitrary return type to `Service::Future`'s
15/// output type.
16pub fn handler_service<F, T>(func: F) -> HandlerService<F, T, marker::BuilderMark>
17where
18    F: AsyncFn2<T> + Clone,
19{
20    HandlerService::new(func)
21}
22
23pub struct HandlerService<F, T, M> {
24    func: F,
25    _p: PhantomData<fn(T, M)>,
26}
27
28// marker for specialized trait implement on HandlerService
29mod marker {
30    pub struct BuilderMark;
31    pub struct ServiceMark;
32}
33
34impl<F, T, M> HandlerService<F, T, M> {
35    pub const fn new(func: F) -> Self {
36        Self { func, _p: PhantomData }
37    }
38}
39
40impl<F, T, M> Clone for HandlerService<F, T, M>
41where
42    F: Clone,
43{
44    fn clone(&self) -> Self {
45        Self::new(self.func.clone())
46    }
47}
48
49impl<F, T> Service for HandlerService<F, T, marker::BuilderMark>
50where
51    F: Clone,
52{
53    type Response = HandlerService<F, T, marker::ServiceMark>;
54    type Error = Infallible;
55
56    async fn call(&self, _: ()) -> Result<Self::Response, Self::Error> {
57        Ok(HandlerService::new(self.func.clone()))
58    }
59}
60
61impl<F, Req, T, O> Service<Req> for HandlerService<F, T, marker::ServiceMark>
62where
63    // for borrowed extractors, `T` is the `'static` version of the extractors
64    T: FromRequest<'static, Req>,
65    // just to assist type inference to pinpoint `T`
66    F: AsyncFn2<T>,
67    F: for<'a> AsyncFn2<T::Type<'a>, Output = O>,
68    O: Responder<Req>,
69    T::Error: From<O::Error>,
70{
71    type Response = O::Response;
72    type Error = T::Error;
73
74    #[inline]
75    async fn call(&self, req: Req) -> Result<Self::Response, Self::Error> {
76        let extract = T::Type::<'_>::from_request(&req).await?;
77        let res = self.func.call(extract).await;
78        res.respond(req).await.map_err(Into::into)
79    }
80}
81
82/// Extract type from Req asynchronously and receive them with function passed to [handler_service].
83///
84/// `'a` is the lifetime of the extracted type.
85///
86/// When `Req` is also a borrowed type, the lifetimes of `Req` type and of the extracted type should
87/// be kept separate. See example below of extracting &str from &String:
88///
89/// # Examples
90/// ```
91/// # use std::future::Future;
92/// # use xitca_http::util::service::handler::FromRequest;
93///
94/// // new type for implementing FromRequest trait to &str.
95/// struct Str<'a>(&'a str);
96///
97/// // borrowed Req type has a named lifetime of it self while trait implementor has the same lifetime
98/// // from FromRequest's lifetime param.
99/// impl<'a, 'r> FromRequest<'a, &'r String> for Str<'a> {
100///     type Type<'b> = Str<'b>; // use GAT lifetime to output a named lifetime instance of implementor.
101///     type Error = ();
102///
103///     async fn from_request(req: &'a &'r String) -> Result<Self, Self::Error> {
104///         Ok(Str(req))
105///     }
106/// }
107///
108/// # async fn extract() {
109/// let input = &String::from("996");
110/// let extract = Str::from_request(&input).await.unwrap();
111/// assert_eq!(extract.0, input.as_str());
112/// # }
113/// ```
114#[diagnostic::on_unimplemented(
115    message = "`{Self}` does not impl FromRequest trait",
116    label = "handler function arguments must impl FromRequest trait",
117    note = "consider add `impl FromRequest<_> for {Self}`"
118)]
119pub trait FromRequest<'a, Req>: Sized {
120    // Used to construct the type for any lifetime 'b.
121    type Type<'b>: FromRequest<'b, Req, Error = Self::Error>;
122    type Error;
123
124    fn from_request(req: &'a Req) -> impl Future<Output = Result<Self, Self::Error>>;
125}
126
127macro_rules! from_req_impl {
128    ($req0: ident, $($req: ident,)*) => {
129        impl<'a, Req, $req0, $($req,)*> FromRequest<'a, Req> for ($req0, $($req,)*)
130        where
131            $req0: FromRequest<'a, Req>,
132            $(
133                $req: FromRequest<'a, Req>,
134                $req0::Error: From<$req::Error>,
135            )*
136        {
137            type Type<'r> = ($req0::Type<'r>, $($req::Type<'r>,)*);
138            type Error = $req0::Error;
139
140            #[inline]
141            async fn from_request(req: &'a Req) -> Result<Self, Self::Error> {
142                Ok((
143                    $req0::from_request(req).await?,
144                    $($req::from_request(req).await?,)*
145                ))
146            }
147        }
148    }
149}
150
151from_req_impl! { A, }
152from_req_impl! { A, B, }
153from_req_impl! { A, B, C, }
154from_req_impl! { A, B, C, D, }
155from_req_impl! { A, B, C, D, E, }
156from_req_impl! { A, B, C, D, E, F, }
157from_req_impl! { A, B, C, D, E, F, G, }
158from_req_impl! { A, B, C, D, E, F, G, H, }
159from_req_impl! { A, B, C, D, E, F, G, H, I, }
160
161/// Make Response with ownership of Req.
162/// The Output type is what returns from [handler_service] function.
163#[diagnostic::on_unimplemented(
164    message = "`{Self}` does not impl Responder trait",
165    label = "handler function return type must impl Responder trait",
166    note = "consider add `impl Responder<_> for {Self}`"
167)]
168pub trait Responder<Req> {
169    type Response;
170    type Error;
171
172    /// generate response from given request.
173    fn respond(self, req: Req) -> impl Future<Output = Result<Self::Response, Self::Error>>;
174
175    /// map response type and mutate it's state.
176    /// default to pass through without any modification.
177    fn map(self, res: Self::Response) -> Result<Self::Response, Self::Error>
178    where
179        Self: Sized,
180    {
181        Ok(res)
182    }
183}
184
185macro_rules! responder_impl {
186    ($res0: ident, $($res: ident,)*) => {
187        #[allow(non_snake_case)]
188        impl<Req, $res0, $($res,)*> Responder<Req> for ($res0, $($res,)*)
189        where
190            $res0: Responder<Req>,
191            $(
192                $res: Responder<Req, Response = $res0::Response>,
193                $res0::Error: From<$res::Error>,
194            )*
195        {
196            type Response = $res0::Response;
197            type Error = $res0::Error;
198
199            async fn respond(self, req: Req) -> Result<Self::Response, Self::Error> {
200                let ($res0, $($res,)*) = self;
201
202                let res = $res0.respond(req).await?;
203                $(
204                    let res = $res.map(res)?;
205                )*
206
207                Ok(res)
208            }
209
210            fn map(self, mut res: Self::Response) -> Result<Self::Response, Self::Error> {
211                let ($res0, $($res,)*) = self;
212
213                res = $res0.map(res)?;
214                $(
215                    res = $res.map(res)?;
216                )*
217
218                Ok(res)
219            }
220        }
221    }
222}
223
224responder_impl! { A, }
225responder_impl! { A, B, }
226responder_impl! { A, B, C, }
227responder_impl! { A, B, C, D, }
228responder_impl! { A, B, C, D, E, }
229responder_impl! { A, B, C, D, E, F, }
230
231impl<R, F, S> Responder<R> for PipelineE<F, S>
232where
233    F: Responder<R>,
234    S: Responder<R, Response = F::Response>,
235    F::Error: From<S::Error>,
236{
237    type Response = F::Response;
238    type Error = F::Error;
239
240    #[inline]
241    async fn respond(self, req: R) -> Result<Self::Response, Self::Error> {
242        match self {
243            Self::First(f) => f.respond(req).await,
244            Self::Second(s) => s.respond(req).await.map_err(From::from),
245        }
246    }
247
248    #[inline]
249    fn map(self, res: Self::Response) -> Result<Self::Response, Self::Error>
250    where
251        Self: Sized,
252    {
253        match self {
254            Self::First(f) => f.map(res),
255            Self::Second(s) => s.map(res).map_err(From::from),
256        }
257    }
258}
259
260macro_rules! borrow_req_impl {
261    ($tt: tt) => {
262        impl<'a, Ext> FromRequest<'a, Request<Ext>> for &'a $tt {
263            type Type<'b> = &'b $tt;
264            type Error = Infallible;
265
266            #[inline]
267            async fn from_request(req: &'a Request<Ext>) -> Result<Self, Self::Error> {
268                Ok(req.borrow())
269            }
270        }
271    };
272}
273
274borrow_req_impl!(Method);
275borrow_req_impl!(Uri);
276borrow_req_impl!(HeaderMap);
277borrow_req_impl!(Extensions);
278
279impl<'a, Ext> FromRequest<'a, Request<Ext>> for &'a Request<Ext>
280where
281    Ext: 'static,
282{
283    type Type<'b> = &'b Request<Ext>;
284    type Error = Infallible;
285
286    #[inline]
287    async fn from_request(req: &'a Request<Ext>) -> Result<Self, Self::Error> {
288        Ok(req)
289    }
290}
291
292impl<'a, B> FromRequest<'a, Request<RequestExt<B>>> for &'a SocketAddr {
293    type Type<'b> = &'b SocketAddr;
294    type Error = Infallible;
295
296    #[inline]
297    async fn from_request(req: &'a Request<RequestExt<B>>) -> Result<Self, Self::Error> {
298        Ok(req.borrow())
299    }
300}
301
302/// helper trait flatting tuple of arguments.
303///
304/// [`FromRequest`] trait extract a tuple of (type1, type2, type3, ..) from request type. this trait would destruct the tuple
305/// handling over it to an async function use them as arguments.
306pub trait AsyncFn2<Arg> {
307    type Output;
308    type Future: Future<Output = Self::Output>;
309
310    fn call(&self, arg: Arg) -> Self::Future;
311}
312
313macro_rules! async_fn_impl {
314    ($($arg: ident),*) => {
315        impl<Func, Fut, $($arg,)*> AsyncFn2<($($arg,)*)> for Func
316        where
317            Func: Fn($($arg),*) -> Fut,
318            Fut: Future,
319        {
320            type Output = Fut::Output;
321            type Future = Fut;
322
323            #[inline]
324            fn call(&self, ($($arg,)*): ($($arg,)*)) -> Self::Future {
325                self($($arg,)*)
326            }
327        }
328    }
329}
330
331async_fn_impl! {}
332async_fn_impl! { A }
333async_fn_impl! { A, B }
334async_fn_impl! { A, B, C }
335async_fn_impl! { A, B, C, D }
336async_fn_impl! { A, B, C, D, E }
337async_fn_impl! { A, B, C, D, E, F }
338async_fn_impl! { A, B, C, D, E, F, G }
339async_fn_impl! { A, B, C, D, E, F, G, H }
340async_fn_impl! { A, B, C, D, E, F, G, H, I }
341
342#[cfg(test)]
343mod test {
344    use xitca_service::ServiceExt;
345    use xitca_unsafe_collection::futures::NowOrPanic;
346
347    use crate::{
348        http::{Response, StatusCode},
349        unspecified_socket_addr,
350    };
351
352    use super::*;
353
354    async fn handler(
355        method: &Method,
356        addr: &SocketAddr,
357        uri: &Uri,
358        headers: &HeaderMap,
359        (_, ext): (&Request<RequestExt<()>>, &Extensions),
360    ) -> StatusCode {
361        assert_eq!(method, Method::GET);
362        assert_eq!(*addr, unspecified_socket_addr());
363        assert_eq!(uri.path(), "/");
364        assert!(headers.is_empty());
365        assert!(ext.is_empty());
366
367        StatusCode::MULTI_STATUS
368    }
369
370    impl Responder<Request<RequestExt<()>>> for StatusCode {
371        type Response = Response<()>;
372        type Error = Infallible;
373
374        async fn respond(self, _: Request<RequestExt<()>>) -> Result<Self::Response, Self::Error> {
375            let mut res = Response::new(());
376            *res.status_mut() = self;
377            Ok(res)
378        }
379    }
380
381    #[test]
382    fn concurrent_extract_with_enclosed_fn() {
383        async fn enclosed<S, Req>(service: &S, req: Req) -> Result<S::Response, S::Error>
384        where
385            S: Service<Req>,
386        {
387            service.call(req).await
388        }
389
390        let res = handler_service(handler)
391            .enclosed_fn(enclosed)
392            .call(())
393            .now_or_panic()
394            .unwrap()
395            .call(Request::default())
396            .now_or_panic()
397            .unwrap();
398
399        assert_eq!(res.status(), StatusCode::MULTI_STATUS);
400    }
401
402    #[cfg(feature = "router")]
403    #[test]
404    fn handler_in_router() {
405        use crate::util::service::{Router, route::get};
406
407        let res = Router::new()
408            .insert("/", get(handler_service(handler)))
409            .call(())
410            .now_or_panic()
411            .unwrap()
412            .call(Request::default())
413            .now_or_panic()
414            .unwrap();
415
416        assert_eq!(res.status(), StatusCode::MULTI_STATUS);
417    }
418}