use super::{BoxedHandler, RouteBuilder, Router};
use crate::http::{Request, Response};
use crate::middleware::{into_boxed, BoxedMiddleware, Middleware};
use std::future::Future;
use std::sync::Arc;
pub struct GroupBuilder {
outer_router: Router,
group_routes: Vec<GroupRoute>,
prefix: String,
middleware: Vec<BoxedMiddleware>,
}
struct GroupRoute {
method: GroupMethod,
path: String,
handler: Arc<BoxedHandler>,
}
#[derive(Clone, Copy)]
enum GroupMethod {
Get,
Post,
Put,
Delete,
}
impl GroupBuilder {
pub fn middleware<M: Middleware + 'static>(mut self, middleware: M) -> Self {
self.middleware.push(into_boxed(middleware));
self
}
fn finalize(mut self) -> Router {
for route in self.group_routes {
let full_path = format!("{}{}", self.prefix, route.path);
match route.method {
GroupMethod::Get => {
self.outer_router.insert_get(&full_path, route.handler);
}
GroupMethod::Post => {
self.outer_router.insert_post(&full_path, route.handler);
}
GroupMethod::Put => {
self.outer_router.insert_put(&full_path, route.handler);
}
GroupMethod::Delete => {
self.outer_router.insert_delete(&full_path, route.handler);
}
}
for mw in &self.middleware {
self.outer_router.add_middleware(&full_path, mw.clone());
}
}
self.outer_router
}
}
pub struct GroupRouter {
routes: Vec<GroupRoute>,
}
impl GroupRouter {
fn new() -> Self {
Self { routes: Vec::new() }
}
pub fn get<H, Fut>(mut self, path: &str, handler: H) -> Self
where
H: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Response> + Send + 'static,
{
let boxed: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
self.routes.push(GroupRoute {
method: GroupMethod::Get,
path: path.to_string(),
handler: Arc::new(boxed),
});
self
}
pub fn post<H, Fut>(mut self, path: &str, handler: H) -> Self
where
H: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Response> + Send + 'static,
{
let boxed: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
self.routes.push(GroupRoute {
method: GroupMethod::Post,
path: path.to_string(),
handler: Arc::new(boxed),
});
self
}
pub fn put<H, Fut>(mut self, path: &str, handler: H) -> Self
where
H: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Response> + Send + 'static,
{
let boxed: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
self.routes.push(GroupRoute {
method: GroupMethod::Put,
path: path.to_string(),
handler: Arc::new(boxed),
});
self
}
pub fn delete<H, Fut>(mut self, path: &str, handler: H) -> Self
where
H: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Response> + Send + 'static,
{
let boxed: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
self.routes.push(GroupRoute {
method: GroupMethod::Delete,
path: path.to_string(),
handler: Arc::new(boxed),
});
self
}
}
impl Router {
pub fn group<F>(self, prefix: &str, builder_fn: F) -> GroupBuilder
where
F: FnOnce(GroupRouter) -> GroupRouter,
{
let inner = GroupRouter::new();
let built = builder_fn(inner);
GroupBuilder {
outer_router: self,
group_routes: built.routes,
prefix: prefix.to_string(),
middleware: Vec::new(),
}
}
}
impl From<GroupBuilder> for Router {
fn from(builder: GroupBuilder) -> Self {
builder.finalize()
}
}
impl RouteBuilder {
pub fn group<F>(self, prefix: &str, builder_fn: F) -> GroupBuilder
where
F: FnOnce(GroupRouter) -> GroupRouter,
{
self.router.group(prefix, builder_fn)
}
}