Skip to main content

router_service/unsync/
service.rs

1use std::{
2    collections::HashMap,
3    future::Future,
4    pin::Pin,
5    task::{Context, Poll},
6};
7
8use futures_util::{future::LocalBoxFuture, FutureExt};
9use http::{Request, Response, StatusCode};
10use tower::Service;
11
12use crate::unsync::{RouteContext, Router};
13
14impl<Body, Data, Error> Service<Request<Body>> for Router<Body, Data, Error>
15where
16    Body: Default,
17    Data: Clone,
18{
19    type Response = Response<Body>;
20
21    type Error = Error;
22
23    type Future = ResponseFuture<Body, Error>;
24
25    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
26        Poll::Ready(Ok(()))
27    }
28
29    fn call(&mut self, req: Request<Body>) -> Self::Future {
30        let uri = req.uri();
31
32        let inner = self.inner.read().unwrap();
33
34        if let Ok(node) = inner.at(uri.path()) {
35            let route = node.value;
36            let ctx = RouteContext {
37                params: {
38                    let mut params = HashMap::with_capacity(node.params.len());
39                    for (name, value) in node.params.iter() {
40                        params.insert(name.into(), value.into());
41                    }
42                    params
43                },
44                data: self.data.clone(),
45            };
46
47            if let Some(handler) = route.handlers.get(req.method()) {
48                return ResponseFuture((handler.0)(req, ctx));
49            }
50
51            if let Some(handler) = &route.catchall {
52                return ResponseFuture((handler.0)(req, ctx));
53            }
54        }
55
56        ResponseFuture(Box::pin(async move {
57            Ok(Response::builder()
58                .status(StatusCode::NOT_FOUND)
59                .body(Body::default())
60                .unwrap())
61        }))
62    }
63}
64
65/// A [`Future`] that resolves to a [`Response`](http::Response).
66pub struct ResponseFuture<Body, Error>(LocalBoxFuture<'static, Result<Response<Body>, Error>>);
67
68impl<Body, Error> Future for ResponseFuture<Body, Error> {
69    type Output = Result<Response<Body>, Error>;
70
71    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
72        self.0.poll_unpin(cx)
73    }
74}