use crate::constants;
use crate::data_map::{DataMap, ScopedDataMap};
use crate::middleware::{Middleware, PostMiddleware, PreMiddleware};
use crate::route::Route;
use crate::router::Router;
use crate::router::{ErrHandler, ErrHandlerWithInfo, ErrHandlerWithoutInfo};
use crate::types::RequestInfo;
use http_body_util::Full;
use hyper::body::Bytes;
use hyper::{Method, Request, Response};
use std::collections::HashMap;
use std::future::Future;
use std::sync::Arc;
pub struct RouterBuilder<E> {
inner: crate::Result<BuilderInner<E>>,
}
struct BuilderInner<E> {
pre_middlewares: Vec<PreMiddleware<E>>,
routes: Vec<Route<E>>,
post_middlewares: Vec<PostMiddleware<E>>,
data_maps: HashMap<String, Vec<DataMap>>,
err_handler: Option<ErrHandler>,
}
impl<E: Into<Box<dyn std::error::Error + Send + Sync>> + 'static> RouterBuilder<E> {
pub fn new() -> RouterBuilder<E> {
RouterBuilder::default()
}
pub fn build(self) -> crate::Result<Router<E>> {
self.inner.and_then(|inner| {
let scoped_data_maps = inner
.data_maps
.into_iter()
.flat_map(|(path, data_map_arr)| {
data_map_arr
.into_iter()
.map(|data_map| ScopedDataMap::new(path.clone(), Arc::new(data_map)))
.collect::<Vec<crate::Result<ScopedDataMap>>>()
})
.collect::<Result<Vec<ScopedDataMap>, crate::RouteError>>()?;
Ok(Router::new(
inner.pre_middlewares,
inner.routes,
inner.post_middlewares,
scoped_data_maps,
inner.err_handler,
))
})
}
fn and_then<F>(self, func: F) -> Self
where
F: FnOnce(BuilderInner<E>) -> crate::Result<BuilderInner<E>>,
{
RouterBuilder {
inner: self.inner.and_then(func),
}
}
}
impl<E: Into<Box<dyn std::error::Error + Send + Sync>> + 'static> RouterBuilder<E> {
pub fn get<P, H, R>(self, path: P, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add(path, vec![Method::GET], handler)
}
pub fn get_or_head<P, H, R>(self, path: P, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add(path, vec![Method::GET, Method::HEAD], handler)
}
pub fn post<P, H, R>(self, path: P, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add(path, vec![Method::POST], handler)
}
pub fn put<P, H, R>(self, path: P, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add(path, vec![Method::PUT], handler)
}
pub fn delete<P, H, R>(self, path: P, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add(path, vec![Method::DELETE], handler)
}
pub fn head<P, H, R>(self, path: P, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add(path, vec![Method::HEAD], handler)
}
pub fn trace<P, H, R>(self, path: P, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add(path, vec![Method::TRACE], handler)
}
pub fn connect<P, H, R>(self, path: P, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add(path, vec![Method::CONNECT], handler)
}
pub fn patch<P, H, R>(self, path: P, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add(path, vec![Method::PATCH], handler)
}
pub fn options<P, H, R>(self, path: P, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add(path, vec![Method::OPTIONS], handler)
}
pub fn any<H, R>(self, handler: H) -> Self
where
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add("/*", constants::ALL_POSSIBLE_HTTP_METHODS.to_vec(), handler)
}
pub fn any_method<H, R, P>(self, path: P, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.add(path, constants::ALL_POSSIBLE_HTTP_METHODS.to_vec(), handler)
}
pub fn add<P, H, R>(self, path: P, methods: Vec<Method>, handler: H) -> Self
where
P: Into<String>,
H: Fn(Request<Full<Bytes>>) -> R + Send + Sync + 'static,
R: Future<Output = Result<Response<Full<Bytes>>, E>> + Send + 'static,
{
self.and_then(move |mut inner| {
let mut path = path.into();
if !path.ends_with('/') && !path.ends_with('*') {
path.push('/');
}
let route = Route::new(path, methods, handler)?;
inner.routes.push(route);
crate::Result::Ok(inner)
})
}
pub fn scope<P>(self, path: P, mut router: Router<E>) -> Self
where
P: Into<String>,
{
let mut path = path.into();
if path.ends_with('/') {
path = path[..path.len() - 1].to_string();
}
let mut builder = self;
for pre_middleware in router.pre_middlewares.iter_mut() {
let new_pre_middleware = PreMiddleware::new_with_boxed_handler(
format!("{}{}", path.as_str(), pre_middleware.path.as_str()),
pre_middleware
.handler
.take()
.expect("No handler found in one of the pre-middlewares"),
pre_middleware.scope_depth + 1,
);
builder = builder.and_then(move |mut inner| {
inner.pre_middlewares.push(new_pre_middleware?);
crate::Result::Ok(inner)
});
}
for route in router.routes.iter_mut() {
let new_route = Route::new_with_boxed_handler(
format!("{}{}", path.as_str(), route.path.as_str()),
route.methods.clone(),
route.handler.take().expect("No handler found in one of the routes"),
route.scope_depth + 1,
);
builder = builder.and_then(move |mut inner| {
inner.routes.push(new_route?);
crate::Result::Ok(inner)
});
}
for post_middleware in router.post_middlewares.iter_mut() {
let new_post_middleware = PostMiddleware::new_with_boxed_handler(
format!("{}{}", path.as_str(), post_middleware.path.as_str()),
post_middleware
.handler
.take()
.expect("No handler found in one of the post-middlewares"),
post_middleware.scope_depth + 1,
);
builder = builder.and_then(move |mut inner| {
inner.post_middlewares.push(new_post_middleware?);
crate::Result::Ok(inner)
});
}
for scoped_data_map in router.scoped_data_maps.iter_mut() {
let new_path = format!("{}{}", path.as_str(), scoped_data_map.path.as_str());
let data_map = Arc::try_unwrap(
scoped_data_map
.data_map
.take()
.expect("No data map found in one of the scoped data maps"),
)
.expect("Non-zero owner of the shared data map in one of the scoped data maps");
builder = builder.and_then(move |mut inner| {
let data_maps = &mut inner.data_maps;
let data_map_arr = data_maps.get_mut(&new_path);
if let Some(data_map_arr) = data_map_arr {
data_map_arr.push(data_map);
} else {
data_maps.insert(new_path, vec![data_map]);
}
crate::Result::Ok(inner)
});
}
builder
}
}
impl<E: Into<Box<dyn std::error::Error + Send + Sync>> + 'static> RouterBuilder<E> {
pub fn middleware(self, m: Middleware<E>) -> Self {
self.and_then(move |mut inner| {
match m {
Middleware::Pre(middleware) => {
inner.pre_middlewares.push(middleware);
}
Middleware::Post(middleware) => {
inner.post_middlewares.push(middleware);
}
}
crate::Result::Ok(inner)
})
}
pub fn data<K: Send + Sync + Clone + 'static>(self, data: K) -> Self {
self.and_then(move |mut inner| {
let data_maps = &mut inner.data_maps;
let data_map_arr = data_maps.get_mut(&"/*".to_owned());
if let Some(data_map_arr) = data_map_arr {
let first_data_map = data_map_arr.get_mut(0).unwrap();
first_data_map.insert(data);
} else {
let mut data_map = DataMap::new();
data_map.insert(data);
data_maps.insert("/*".to_owned(), vec![data_map]);
}
crate::Result::Ok(inner)
})
}
pub fn err_handler<H, R>(self, handler: H) -> Self
where
H: Fn(crate::RouteError) -> R + Send + Sync + 'static,
R: Future<Output = Response<Full<Bytes>>> + Send + 'static,
{
let handler: ErrHandlerWithoutInfo = Box::new(move |err: crate::RouteError| Box::new(handler(err)));
self.and_then(move |mut inner| {
inner.err_handler = Some(ErrHandler::WithoutInfo(handler));
crate::Result::Ok(inner)
})
}
pub fn err_handler_with_info<H, R>(self, handler: H) -> Self
where
H: Fn(crate::RouteError, RequestInfo) -> R + Send + Sync + 'static,
R: Future<Output = Response<Full<Bytes>>> + Send + 'static,
{
let handler: ErrHandlerWithInfo =
Box::new(move |err: crate::RouteError, req_info: RequestInfo| Box::new(handler(err, req_info)));
self.and_then(move |mut inner| {
inner.err_handler = Some(ErrHandler::WithInfo(handler));
crate::Result::Ok(inner)
})
}
}
impl<E: Into<Box<dyn std::error::Error + Send + Sync>> + 'static> Default for RouterBuilder<E> {
fn default() -> RouterBuilder<E> {
RouterBuilder {
inner: Ok(BuilderInner {
pre_middlewares: Vec::new(),
routes: Vec::new(),
post_middlewares: Vec::new(),
data_maps: HashMap::new(),
err_handler: None,
}),
}
}
}