mod route;
mod pattern;
use std::collections::HashMap;
use hyper::{Method, StatusCode};
use regex::RegexSet;
use futures::future;
use handler::Handler;
use context::Context;
use response::{BoxFutureResponse, Response};
pub use router::route::Route;
pub use router::pattern::Pattern;
macro_rules! try_opt {
($e:expr) =>(
match $e {
Some(v) => v,
None => return None,
}
)
}
#[derive(Default)]
pub struct Router {
routes: HashMap<Method, Vec<Route>>,
route_patterns: HashMap<Method, RegexSet>,
}
impl Router {
pub fn new() -> Self {
Default::default()
}
pub fn route<R: Into<Route>>(&mut self, route: R) {
let route: Route = route.into();
let method = route.method().clone();
self.routes
.entry(method.clone())
.or_insert_with(Vec::new)
.push(route);
let routes = &self.routes[&method];
self.route_patterns.insert(
method.clone(),
RegexSet::new(routes.iter().map(|r| r.pattern())).unwrap(),
);
}
pub(crate) fn find(&self, method: &Method, path: &str) -> Option<&Route> {
let routes = try_opt!(self.routes.get(method));
let route_patterns = try_opt!(self.route_patterns.get(method));
let matched_index = try_opt!(route_patterns.matches(path).into_iter().next());
Some(&routes[matched_index])
}
}
impl Handler for Router {
type Result = BoxFutureResponse;
#[inline]
fn call(&self, ctx: Context) -> Self::Result {
let route = match self.find(ctx.method(), ctx.path()) {
Some(route) => route,
None => {
return Box::new(future::ok(Response::with(StatusCode::NotFound)));
}
};
route.call(ctx)
}
}