tackt/
func.rs

1use std::future::Future;
2use std::marker::PhantomData;
3
4use tower_service::Service;
5
6use crate::error::Error;
7use crate::future::Maybe;
8use crate::param::Param;
9use crate::route::Route;
10
11/// Wrap a function into a route.
12///
13/// Note that application code cannot construct this struct directly. This is
14/// exported for type annotation only.
15pub struct Func<F, P> {
16    inner: F,
17
18    param: PhantomData<P>,
19}
20
21impl<F, P> std::fmt::Debug for Func<F, P> {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        f.debug_struct("Func").finish()
24    }
25}
26
27impl<F, P> Func<F, P> {
28    #[inline]
29    pub(crate) fn new<T, U, E, Fut>(inner: F) -> Func<F, P>
30    where
31        F: FnMut(T, P) -> Fut,
32        P: Param<T>,
33        E: From<Error>,
34        Fut: Future<Output = Result<U, E>>,
35    {
36        Func {
37            inner,
38            param: PhantomData,
39        }
40    }
41}
42
43impl<F: Copy, P> Copy for Func<F, P> {}
44
45impl<F: Clone, P> Clone for Func<F, P> {
46    fn clone(&self) -> Self {
47        Func {
48            inner: self.inner.clone(),
49            param: self.param,
50        }
51    }
52}
53
54impl<F, T, P, U, E, Fut> Service<T> for Func<F, P>
55where
56    F: FnMut(T, P) -> Fut,
57    P: Param<T>,
58    E: From<Error>,
59    Fut: Future<Output = Result<U, E>>,
60{
61    type Response = U;
62
63    type Error = E;
64
65    type Future = Maybe<Fut, Result<U, E>>;
66
67    #[inline]
68    fn poll_ready(
69        &mut self,
70        _: &mut std::task::Context<'_>,
71    ) -> std::task::Poll<Result<(), Self::Error>> {
72        std::task::Poll::Ready(Ok(()))
73    }
74
75    #[inline]
76    fn call(&mut self, req: T) -> Self::Future {
77        match self.param(&req) {
78            Ok(param) => self.call_with_param(req, param),
79            Err(err) => Maybe::ready(Err(err.into())),
80        }
81    }
82}
83
84impl<F, T, P, U, E, Fut> Route<T> for Func<F, P>
85where
86    F: FnMut(T, P) -> Fut,
87    P: Param<T>,
88    E: From<Error>,
89    Fut: Future<Output = Result<U, E>>,
90{
91    type Param = P;
92
93    #[inline]
94    fn call_with_param(&mut self, req: T, param: Self::Param) -> Self::Future {
95        Maybe::Future((self.inner)(req, param))
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::Error;
102    use super::Func;
103
104    #[test]
105    fn test() {
106        #[derive(Debug)]
107        struct Param;
108
109        impl crate::param::Param<&'static str> for Param {
110            fn from_request(req: &&'static str) -> Result<Self, Error> {
111                if *req != "/" {
112                    return Err(Error::Path);
113                }
114                Ok(Param)
115            }
116        }
117
118        let func = Func::new(|_: &'static str, param: Param| async { Ok::<_, Error>(param) });
119        let res = crate::exec::run(func, "/");
120        assert!(matches!(res, Ok(Param)));
121        let res = crate::exec::run(func, "/somewhere");
122        assert!(matches!(res, Err(Error::Path)));
123    }
124}