use crate::method;
use crate::request;
use crate::response;
use hashbrown::HashMap;
use tokio::prelude::*;
use std::sync::Arc;
pub type ResponseFut = Box<dyn Future<Item = response::Response, Error = ()> + Send + Sync>;
pub struct Router {
get: Node,
put: Node,
post: Node,
head: Node,
patch: Node,
delete: Node,
options: Node,
routes: Node,
default: Option<StoreFunc>,
}
impl Router {
pub fn new() -> Router {
Router {
default: None,
routes: Node::default(),
get: Node::default(),
put: Node::default(),
post: Node::default(),
head: Node::default(),
patch: Node::default(),
delete: Node::default(),
options: Node::default(),
}
}
pub fn build(self) -> Arc<Self> {
Arc::new(self)
}
pub fn add<F>(&mut self, method: &str, path: &'static str, func: F)
where
F: Fn(request::Request) -> ResponseFut + Send + Sync + 'static,
{
let mut node = match method {
method::GET => &mut self.get,
method::PUT => &mut self.put,
method::POST => &mut self.post,
method::HEAD => &mut self.head,
method::PATCH => &mut self.patch,
method::DELETE => &mut self.delete,
method::OPTIONS => &mut self.options,
_ => &mut self.routes,
};
match path {
"/" => {
node.set_func(Box::new(func));
}
_ => {
for seg in path.split('/') {
if !seg.is_empty() {
let mut seg_arr = seg.chars();
if seg_arr.next() == Some(':') {
node = node.add_child(":", Some(seg_arr.as_str()));
continue;
}
node = node.add_child(seg, None);
}
}
node.set_func(Box::new(func));
}
}
}
pub fn find(&self, mut req: request::Request) -> ResponseFut {
let mut node = match req.method() {
method::GET => &self.get,
method::PUT => &self.put,
method::POST => &self.post,
method::HEAD => &self.head,
method::PATCH => &self.patch,
method::DELETE => &self.delete,
method::OPTIONS => &self.options,
_ => &self.routes,
};
if req.uri().path() == "/" {
return match node.method.as_ref() {
Some(v) => (v)(req),
None => (self.default.as_ref().unwrap())(req),
};
}
let mut params: Vec<(&'static str, String)> = Vec::with_capacity(10);
for seg in req.uri().path().split('/') {
if !seg.is_empty() {
if node.children.is_none() {
return (self.default.as_ref().unwrap())(req);
}
let children = node.children.as_ref().unwrap();
let found_node = match children.get(seg) {
Some(v) => v,
None => {
match children.get(":") {
Some(v) => {
params.push((v.param.unwrap(), seg.to_string()));
v
}
None => match children.get("*") {
Some(v) => {
if !params.is_empty() {
req.set_params(Some(params));
}
return (v.method.as_ref().unwrap())(req);
}
None => {
return (self.default.as_ref().unwrap())(req);
}
},
}
}
};
node = found_node;
}
}
match node.method.as_ref() {
Some(v) => {
if !params.is_empty() {
req.set_params(Some(params));
}
(v)(req)
}
None => (self.default.as_ref().unwrap())(req),
}
}
pub fn add_default<F>(&mut self, func: F)
where
F: Fn(request::Request) -> ResponseFut + Send + Sync + 'static,
{
self.default = Some(Box::new(func));
}
}
impl Router {
pub fn get<F>(&mut self, path: &'static str, func: F)
where
F: Fn(request::Request) -> ResponseFut + Send + Sync + 'static,
{
self.add(method::GET, path, func)
}
pub fn put<F>(&mut self, path: &'static str, func: F)
where
F: Fn(request::Request) -> ResponseFut + Send + Sync + 'static,
{
self.add(method::PUT, path, func)
}
pub fn post<F>(&mut self, path: &'static str, func: F)
where
F: Fn(request::Request) -> ResponseFut + Send + Sync + 'static,
{
self.add(method::POST, path, func)
}
pub fn head<F>(&mut self, path: &'static str, func: F)
where
F: Fn(request::Request) -> ResponseFut + Send + Sync + 'static,
{
self.add(method::HEAD, path, func)
}
pub fn patch<F>(&mut self, path: &'static str, func: F)
where
F: Fn(request::Request) -> ResponseFut + Send + Sync + 'static,
{
self.add(method::PATCH, path, func)
}
pub fn delete<F>(&mut self, path: &'static str, func: F)
where
F: Fn(request::Request) -> ResponseFut + Send + Sync + 'static,
{
self.add(method::DELETE, path, func)
}
pub fn options<F>(&mut self, path: &'static str, func: F)
where
F: Fn(request::Request) -> ResponseFut + Send + Sync + 'static,
{
self.add(method::OPTIONS, path, func)
}
}
type StoreFunc = Box<
dyn Fn(request::Request) -> Box<dyn Future<Item = response::Response, Error = ()> + Send + Sync>
+ Send
+ Sync,
>;
struct Node {
param: Option<&'static str>,
method: Option<StoreFunc>,
children: Option<HashMap<&'static str, Node>>,
}
impl Node {
pub fn default() -> Node {
Node {
param: None,
method: None,
children: None,
}
}
pub fn set_func(&mut self, func: StoreFunc) {
self.method = Some(func);
}
pub fn add_child(&mut self, seg: &'static str, param: Option<&'static str>) -> &mut Node {
if self.children.is_none() {
self.children = Some(HashMap::new())
}
let node_map = self.children.as_mut().unwrap();
if node_map.contains_key(seg) {
return node_map.get_mut(seg).unwrap();
}
node_map.insert(
seg,
Node {
param,
method: None,
children: None,
},
);
node_map.get_mut(seg).unwrap()
}
}
impl std::fmt::Debug for Router {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"Router {{ \n get: {:#?}, \npost: {:#?} \ndelete:{:#?}\nput:{:#?} \nroutes:{:#?} \n}}",
self.get, self.post, self.delete, self.put, self.routes
)
}
}
impl std::fmt::Debug for Node {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"Node {{ \n\tchildren: {:#?}, \n\tmethod: {:#?} \n\tparam:{:#?}\n}}",
self.children,
self.method.is_some(),
self.param
)
}
}