pub mod ext;
pub mod prelude;
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use hyper::service::Service;
use hyper::{Body, Method, Request, Response};
use route_recognizer::Router as InnerRouter;
pub struct Router<E, State> {
inner: HashMap<Method, InnerRouter<Box<dyn Handler<E>>>>,
not_found: Option<Box<dyn Handler<E>>>,
state: State,
}
impl<E> Default for Router<E, ()>
where
E: Into<Box<dyn Error + Send + Sync>> + 'static,
{
fn default() -> Self {
Self::new()
}
}
impl<E> Router<E, ()>
where
E: Into<Box<dyn Error + Send + Sync>> + 'static,
{
pub fn new() -> Self {
Router::with_state(())
}
}
impl<E, State> Router<E, State>
where
E: Into<Box<dyn Error + Send + Sync>> + 'static,
State: Clone + Send + Sync + 'static,
{
pub fn with_state(state: State) -> Self {
Self {
inner: HashMap::new(),
not_found: None,
state,
}
}
pub fn get<H, R>(&mut self, path: &str, handler: H)
where
H: Fn(Request<Body>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Body>, E>> + Send + Sync + 'static,
E: Into<Box<dyn Error + Send + Sync>> + 'static,
{
let h = move |req| Box::pin(handler(req));
let entry = self
.inner
.entry(Method::GET)
.or_insert_with(InnerRouter::new);
entry.add(path, Box::new(h));
}
pub fn post<H, R>(&mut self, path: &str, handler: H)
where
H: Fn(Request<Body>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Body>, E>> + Send + Sync + 'static,
E: Into<Box<dyn Error + Send + Sync>> + 'static,
{
let h = move |req| Box::pin(handler(req));
let entry = self
.inner
.entry(Method::POST)
.or_insert_with(InnerRouter::new);
entry.add(path, Box::new(h));
}
pub fn put<H, R>(&mut self, path: &str, handler: H)
where
H: Fn(Request<Body>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Body>, E>> + Send + Sync + 'static,
E: Into<Box<dyn Error + Send + Sync>> + 'static,
{
let h = move |req| Box::pin(handler(req));
let entry = self
.inner
.entry(Method::PUT)
.or_insert_with(InnerRouter::new);
entry.add(path, Box::new(h));
}
pub fn delete<H, R>(&mut self, path: &str, handler: H)
where
H: Fn(Request<Body>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Body>, E>> + Send + Sync + 'static,
E: Into<Box<dyn Error + Send + Sync>> + 'static,
{
let h = move |req| Box::pin(handler(req));
let entry = self
.inner
.entry(Method::DELETE)
.or_insert_with(InnerRouter::new);
entry.add(path, Box::new(h));
}
pub fn patch<H, R>(&mut self, path: &str, handler: H)
where
H: Fn(Request<Body>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Body>, E>> + Send + Sync + 'static,
E: Into<Box<dyn Error + Send + Sync>> + 'static,
{
let h = move |req| Box::pin(handler(req));
let entry = self
.inner
.entry(Method::PATCH)
.or_insert_with(InnerRouter::new);
entry.add(path, Box::new(h));
}
pub fn not_found<H, R>(&mut self, handler: H)
where
H: Fn(Request<Body>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Body>, E>> + Send + Sync + 'static,
E: Into<Box<dyn Error + Send + Sync>> + 'static,
{
self.not_found = Some(Box::new(handler));
}
pub fn serve(
&self,
mut req: Request<Body>,
) -> Pin<Box<dyn Future<Output = Result<Response<Body>, E>> + Send + Sync>>
where
E: Into<Box<dyn Error + Send + Sync>> + 'static,
{
match self.inner.get(req.method()) {
Some(inner_router) => match inner_router.recognize(req.uri().path()) {
Ok(matcher) => {
let handler = matcher.handler();
let params = matcher.params().clone();
req.extensions_mut().insert(Params(Box::new(params)));
req.extensions_mut().insert(self.state.clone());
handler.call(req)
}
Err(_) => match &self.not_found {
Some(handler) => handler.call(req),
None => Box::pin(async {
Ok(Response::builder().status(404).body(Body::empty()).unwrap())
}),
},
},
None => {
Box::pin(async { Ok(Response::builder().status(404).body(Body::empty()).unwrap()) })
}
}
}
pub fn into_service(self) -> MakeRouterService<RouterService<E, State>> {
MakeRouterService {
inner: RouterService::new(self),
}
}
}
pub trait Handler<E: Into<Box<dyn Error + Send + Sync>>>: Send + Sync + 'static {
fn call(
&self,
req: Request<Body>,
) -> Pin<Box<dyn Future<Output = Result<Response<Body>, E>> + Send + Sync>>;
}
impl<F: Send + Sync + 'static, R, E> Handler<E> for F
where
F: Fn(Request<Body>) -> R + Send + Sync,
R: Future<Output = Result<Response<Body>, E>> + Send + Sync + 'static,
E: Into<Box<dyn Error + Send + Sync>>,
{
fn call(
&self,
req: Request<Body>,
) -> Pin<Box<dyn Future<Output = Result<Response<Body>, E>> + Send + Sync>> {
Box::pin(self(req))
}
}
impl<E> fmt::Debug for dyn Handler<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "keiro::Handler")
}
}
#[derive(Clone)]
pub struct RouterService<E, State>(Arc<Router<E, State>>);
impl<E, State> Service<Request<Body>> for RouterService<E, State>
where
E: Into<Box<dyn Error + Send + Sync>> + 'static,
State: Clone + Send + Sync + 'static,
{
type Response = Response<Body>;
type Error = Box<dyn Error + Send + Sync>;
#[allow(clippy::type_complexity)]
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + Sync>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: Request<Body>) -> Self::Future {
let router = self.0.clone();
let fut = router.serve(req);
let fut = async { fut.await.map_err(Into::into) };
Box::pin(fut)
}
}
impl<E, State> RouterService<E, State>
where
E: Into<Box<dyn Error + Send + Sync>> + 'static,
State: Clone + Send + Sync + 'static,
{
pub fn new(router: Router<E, State>) -> Self {
Self(Arc::new(router))
}
}
pub struct MakeRouterService<Svc> {
pub inner: Svc,
}
impl<T, Svc> Service<T> for MakeRouterService<Svc>
where
Svc: Service<Request<Body>> + Clone,
Svc::Response: 'static,
Svc::Error: Into<Box<dyn Error + Send + Sync>>,
Svc::Future: 'static,
{
type Response = Svc;
type Error = Box<dyn Error + Send + Sync>;
type Future = futures_util::future::Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _req: T) -> Self::Future {
futures_util::future::ok(self.inner.clone())
}
}
pub struct Params(Box<route_recognizer::Params>);
impl Params {
pub fn find(&self, key: &str) -> Option<&str> {
self.0.find(key)
}
}