use std::future::Future;
use tower_service::Service;
use crate::error::Error;
use crate::func::Func;
use crate::mount::Mount;
use crate::or::Or;
use crate::param::Param;
use crate::request::PathReq;
use crate::request::RemovePrefix;
use crate::route::Route;
use crate::void::Void;
use crate::with::With;
#[derive(Clone, Copy, Debug)]
pub struct Router<R> {
inner: R,
}
impl<R, T> Service<T> for Router<R>
where
R: Service<T>,
{
type Response = R::Response;
type Error = R::Error;
type Future = R::Future;
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 {
self.inner.call(req)
}
}
impl<T, U> Router<Void<T, U>> {
pub const fn void() -> Router<Void<T, U>> {
Router { inner: Void::new() }
}
}
impl<F, P> Router<Func<F, P>> {
#[inline]
pub fn new<T, U, E, Fut>(route: F) -> Router<Func<F, P>>
where
F: FnMut(T, P) -> Fut,
P: Param<T>,
E: From<Error>,
Fut: Future<Output = Result<U, E>>,
{
Router {
inner: Func::new(route),
}
}
}
impl<R> Router<R> {
#[inline]
pub fn route<F, T, P, U, E, Fut>(self, route: F) -> Router<Or<R, Func<F, P>>>
where
R: Route<T, Response = U, Error = E>,
F: FnMut(T, P) -> Fut,
P: Param<T>,
E: From<Error>,
Fut: Future<Output = Result<U, E>>,
{
Router {
inner: Or::new(self.inner, Func::new(route)),
}
}
#[inline]
pub fn mount<S, T, U, E>(self, prefix: &'static str, service: S) -> Router<Or<R, Mount<S>>>
where
R: Route<T, Response = U, Error = E>,
S: Service<T, Response = U, Error = E>,
T: PathReq + RemovePrefix,
E: From<Error>,
{
let prefix = prefix.trim_end_matches('/');
assert!(!prefix.contains('?'), "Prefix cannot contains '?'");
assert!(!prefix.contains('#'), "Prefix cannot contains '#'");
assert!(!prefix.is_empty(), "Prefix cannot be empty");
assert!(prefix != "/", "Prefix cannot be '/'");
assert!(prefix.starts_with('/'), "Prefix must be starts with '/'");
Router {
inner: Or::new(self.inner, Mount::new(service, prefix)),
}
}
#[inline]
pub fn with<F, T, Fut>(self, func: F) -> Router<With<R, F>>
where
R: Clone + Service<T>,
F: FnMut(T) -> Fut,
Fut: Future<Output = Result<T, R::Error>>,
{
Router {
inner: With::new(self.inner, func),
}
}
}
#[cfg(test)]
mod tests {
use std::convert::Infallible;
use std::net::SocketAddr;
use http::Request;
use http::Response;
use hyper::service::make_service_fn;
use hyper::Body;
use crate::error::Error;
use crate::param::Param;
use crate::Router;
#[derive(Clone, Copy, Debug)]
struct Home;
impl Param<Request<Body>> for Home {
fn from_request(req: &Request<Body>) -> Result<Self, Error> {
match req.uri().path() {
"/" => Ok(Home),
_ => Err(Error::Path),
}
}
}
async fn home(req: Request<Body>, param: Home) -> Result<Response<Body>, Error> {
Ok(Response::new(Body::from(format!(
"{:?} @ {}",
param,
req.uri().path()
))))
}
#[derive(Clone, Copy, Debug)]
struct About;
impl Param<Request<Body>> for About {
fn from_request(req: &Request<Body>) -> Result<Self, Error> {
match req.uri().path() {
"/about" => Ok(About),
_ => Err(Error::Path),
}
}
}
async fn about(req: Request<Body>, param: About) -> Result<Response<Body>, Error> {
Ok(Response::new(Body::from(format!(
"{:?} @ {}",
param,
req.uri().path()
))))
}
#[test]
#[allow(dead_code)]
fn compile() {
let subrouter = Router::new(home).route(about);
let router = Router::new(home).route(about).mount("/sub", subrouter);
let _ = |addr: SocketAddr| async move {
let _ = hyper::server::Server::bind(&addr)
.serve(make_service_fn(
|_| async move { Ok::<_, Infallible>(router) },
))
.await;
};
}
}