tackt/
router.rs

1use std::future::Future;
2
3use tower_service::Service;
4
5use crate::error::Error;
6use crate::func::Func;
7use crate::mount::Mount;
8use crate::or::Or;
9use crate::param::Param;
10use crate::request::PathReq;
11use crate::request::RemovePrefix;
12use crate::route::Route;
13use crate::void::Void;
14use crate::with::With;
15
16/// The router instance.
17///
18/// Note that a router does not implement Route. It only implement service.
19#[derive(Clone, Copy, Debug)]
20pub struct Router<R> {
21    inner: R,
22}
23
24impl<R, T> Service<T> for Router<R>
25where
26    R: Service<T>,
27{
28    type Response = R::Response;
29
30    type Error = R::Error;
31
32    type Future = R::Future;
33
34    fn poll_ready(
35        &mut self,
36        _: &mut std::task::Context<'_>,
37    ) -> std::task::Poll<Result<(), Self::Error>> {
38        std::task::Poll::Ready(Ok(()))
39    }
40
41    fn call(&mut self, req: T) -> Self::Future {
42        self.inner.call(req)
43    }
44}
45
46impl<T, U> Router<Void<T, U>> {
47    /// Create a router that does not match any request.
48    pub const fn void() -> Router<Void<T, U>> {
49        Router { inner: Void::new() }
50    }
51}
52
53impl<F, P> Router<Func<F, P>> {
54    /// Create a new router with the route.
55    #[inline]
56    pub fn new<T, U, E, Fut>(route: F) -> Router<Func<F, P>>
57    where
58        F: FnMut(T, P) -> Fut,
59        P: Param<T>,
60        E: From<Error>,
61        Fut: Future<Output = Result<U, E>>,
62    {
63        Router {
64            inner: Func::new(route),
65        }
66    }
67}
68
69impl<R> Router<R> {
70    /// Add new route to this router.
71    #[inline]
72    pub fn route<F, T, P, U, E, Fut>(self, route: F) -> Router<Or<R, Func<F, P>>>
73    where
74        R: Route<T, Response = U, Error = E>,
75        F: FnMut(T, P) -> Fut,
76        P: Param<T>,
77        E: From<Error>,
78        Fut: Future<Output = Result<U, E>>,
79    {
80        Router {
81            inner: Or::new(self.inner, Func::new(route)),
82        }
83    }
84
85    /// Mount a service at prefix.
86    ///
87    /// Any request to prefix will be delegated to the service with the prefix
88    /// stripped.
89    ///
90    /// *NOTE*: `prefix` will be stripped from any trailing slash.
91    ///
92    /// # Panic
93    ///
94    /// Panic if one of these conditions is met:
95    ///
96    /// 1. Prefix contains `?`.
97    /// 2. Prefix contains `#`.
98    /// 3. Prefix is empty.
99    /// 4. Prefix is `/`.
100    /// 5. Prefix does not start with `/`.
101    #[inline]
102    pub fn mount<S, T, U, E>(self, prefix: &'static str, service: S) -> Router<Or<R, Mount<S>>>
103    where
104        R: Route<T, Response = U, Error = E>,
105        S: Service<T, Response = U, Error = E>,
106        T: PathReq + RemovePrefix,
107        E: From<Error>,
108    {
109        let prefix = prefix.trim_end_matches('/');
110        assert!(!prefix.contains('?'), "Prefix cannot contains '?'");
111        assert!(!prefix.contains('#'), "Prefix cannot contains '#'");
112        assert!(!prefix.is_empty(), "Prefix cannot be empty");
113        assert!(prefix != "/", "Prefix cannot be '/'");
114        assert!(prefix.starts_with('/'), "Prefix must be starts with '/'");
115        Router {
116            inner: Or::new(self.inner, Mount::new(service, prefix)),
117        }
118    }
119
120    /// Add middleware to the router.
121    #[inline]
122    pub fn with<F, T, Fut>(self, func: F) -> Router<With<R, F>>
123    where
124        R: Clone + Service<T>,
125        F: FnMut(T) -> Fut,
126        Fut: Future<Output = Result<T, R::Error>>,
127    {
128        Router {
129            inner: With::new(self.inner, func),
130        }
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use std::convert::Infallible;
137    use std::net::SocketAddr;
138
139    use http::Request;
140    use http::Response;
141    use hyper::service::make_service_fn;
142    use hyper::Body;
143
144    use crate::error::Error;
145    use crate::param::Param;
146    use crate::Router;
147
148    #[derive(Clone, Copy, Debug)]
149    struct Home;
150
151    impl Param<Request<Body>> for Home {
152        fn from_request(req: &Request<Body>) -> Result<Self, Error> {
153            match req.uri().path() {
154                "/" => Ok(Home),
155                _ => Err(Error::Path),
156            }
157        }
158    }
159
160    async fn home(req: Request<Body>, param: Home) -> Result<Response<Body>, Error> {
161        Ok(Response::new(Body::from(format!(
162            "{:?} @ {}",
163            param,
164            req.uri().path()
165        ))))
166    }
167
168    #[derive(Clone, Copy, Debug)]
169    struct About;
170
171    impl Param<Request<Body>> for About {
172        fn from_request(req: &Request<Body>) -> Result<Self, Error> {
173            match req.uri().path() {
174                "/about" => Ok(About),
175                _ => Err(Error::Path),
176            }
177        }
178    }
179
180    async fn about(req: Request<Body>, param: About) -> Result<Response<Body>, Error> {
181        Ok(Response::new(Body::from(format!(
182            "{:?} @ {}",
183            param,
184            req.uri().path()
185        ))))
186    }
187
188    #[test]
189    #[allow(dead_code)]
190    fn compile() {
191        let subrouter = Router::new(home).route(about);
192        let router = Router::new(home).route(about).mount("/sub", subrouter);
193
194        let _ = |addr: SocketAddr| async move {
195            let _ = hyper::server::Server::bind(&addr)
196                .serve(make_service_fn(
197                    |_| async move { Ok::<_, Infallible>(router) },
198                ))
199                .await;
200        };
201    }
202}