use tower_service::Service;
use crate::error::Error;
use crate::future::Maybe;
use crate::request::PathReq;
use crate::request::RemovePrefix;
use crate::route::Route;
#[derive(Clone, Copy, Debug)]
pub struct Mount<S> {
inner: S,
prefix: &'static str,
}
impl<S> Mount<S> {
#[inline]
pub(crate) fn new<T>(inner: S, prefix: &'static str) -> Mount<S>
where
S: Service<T>,
T: PathReq + RemovePrefix,
S::Error: From<Error>,
{
Mount { inner, prefix }
}
}
impl<S, T> Service<T> for Mount<S>
where
S: Service<T>,
T: PathReq + RemovePrefix,
S::Error: From<Error>,
{
type Response = S::Response;
type Error = S::Error;
type Future = Maybe<S::Future, Result<Self::Response, Self::Error>>;
#[inline]
fn poll_ready(
&mut self,
_: &mut std::task::Context<'_>,
) -> std::task::Poll<Result<(), Self::Error>> {
std::task::Poll::Ready(Ok(()))
}
fn call(&mut self, req: T) -> Self::Future {
match req.remove_prefix(self.prefix) {
Err(err) => Maybe::ready(Err(err.into())),
Ok(req) => Maybe::Future(self.inner.call(req)),
}
}
}
impl<S, T> Route<T> for Mount<S>
where
S: Service<T>,
T: PathReq + RemovePrefix,
S::Error: From<Error>,
{
type Param = Param;
fn call_with_param(&mut self, req: T, _: Self::Param) -> Self::Future {
self.call(req)
}
fn param(&self, req: &T) -> Result<Self::Param, Error> {
match req.path().starts_with(self.prefix) {
true => Ok(Param),
false => Err(Error::Path),
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Param;
impl<T> crate::param::Param<T> for Param {
fn from_request(_: &T) -> Result<Self, Error> {
Ok(Param)
}
}
#[cfg(test)]
mod tests {
use http::Request;
use crate::error::Error;
use crate::exec::run;
use crate::macros::param;
use crate::router::Router;
param!(Root, GET, "/");
param!(Route1, GET, "/route1");
param!(Route2, GET, "/route2");
param!(Other, GET, "/other");
async fn root(_: Request<()>, _: Root) -> Result<&'static str, Error> {
Ok("root")
}
async fn route1(_: Request<()>, _: Route1) -> Result<&'static str, Error> {
Ok("route1")
}
async fn route2(_: Request<()>, _: Route2) -> Result<&'static str, Error> {
Ok("route2")
}
async fn other(_: Request<()>, _: Other) -> Result<&'static str, Error> {
Ok("other")
}
fn req(path: &'static str) -> Request<()> {
Request::builder()
.method(http::Method::GET)
.uri(http::Uri::from_static(path))
.body(())
.unwrap()
}
#[test]
fn test() {
let root = Router::new(root).route(other);
let r1 = Router::new(route1);
let r2 = Router::new(route2);
let router = root.mount("/r1", r1).mount("/r2", r2);
let res = run(router, req("/"));
assert_eq!(res, Ok("root"));
let res = run(router, req("/other"));
assert_eq!(res, Ok("other"));
let res = run(router, req("/r1/route1"));
assert_eq!(res, Ok("route1"));
let res = run(router, req("/r2/route2"));
assert_eq!(res, Ok("route2"));
}
}