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
11pub 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}