use std::str::FromStr;
use crate::handler::matcher::Route;
use crate::handler::stack::{self, Stack};
use crate::handler::{Error, Result, Scope, TryIntoHandler};
use crate::http::Method;
use crate::middleware::{Middleware, TryIntoMiddleware};
pub use crate::handler::matcher::Params;
mod action;
mod routes;
pub use action::Action;
use routes::Routes;
#[derive(Debug)]
enum Builder {
Stack(stack::Builder),
Routes(routes::Builder),
}
#[derive(Debug)]
pub struct Router {
builders: Vec<Builder>,
path: String,
}
impl Router {
pub fn new<P>(path: P) -> Self
where
P: Into<String>,
{
Self {
builders: Vec::new(),
path: path.into(),
}
}
#[inline]
#[must_use]
pub fn get<P, A>(self, path: P, action: A) -> Self
where
P: Into<String>,
A: Action,
{
self.route(Method::Get, path, action)
}
#[inline]
#[must_use]
pub fn post<P, A>(self, path: P, action: A) -> Self
where
P: Into<String>,
A: Action,
{
self.route(Method::Post, path, action)
}
#[inline]
#[must_use]
pub fn put<P, A>(self, path: P, action: A) -> Self
where
P: Into<String>,
A: Action,
{
self.route(Method::Put, path, action)
}
#[inline]
#[must_use]
pub fn delete<P, A>(self, path: P, action: A) -> Self
where
P: Into<String>,
A: Action,
{
self.route(Method::Delete, path, action)
}
#[inline]
#[must_use]
pub fn patch<P, A>(self, path: P, action: A) -> Self
where
P: Into<String>,
A: Action,
{
self.route(Method::Patch, path, action)
}
#[inline]
#[must_use]
pub fn head<P, A>(self, path: P, action: A) -> Self
where
P: Into<String>,
A: Action,
{
self.route(Method::Head, path, action)
}
#[inline]
#[must_use]
pub fn options<P, A>(self, path: P, action: A) -> Self
where
P: Into<String>,
A: Action,
{
self.route(Method::Options, path, action)
}
#[inline]
#[must_use]
pub fn trace<P, A>(self, path: P, action: A) -> Self
where
P: Into<String>,
A: Action,
{
self.route(Method::Trace, path, action)
}
#[must_use]
pub fn with<M>(mut self, middleware: M) -> Self
where
M: TryIntoMiddleware,
{
if let Some(Builder::Stack(builder)) = self.builders.last_mut() {
builder.push(middleware);
} else {
let mut builder = Stack::new();
builder.push(middleware);
self.builders.push(Builder::Stack(builder));
}
self
}
fn route<P, A>(mut self, method: Method, path: P, action: A) -> Self
where
P: Into<String>,
A: Action,
{
if let Some(Builder::Routes(builder)) = self.builders.last_mut() {
builder.add(method, path, action);
} else {
let mut builder = Routes::builder();
builder.add(method, path, action);
self.builders.push(Builder::Routes(builder));
}
self
}
}
impl TryIntoMiddleware for Router {
type Output = Stack;
fn try_into_middleware(self, scope: &Scope) -> Result<Self::Output> {
let path = Route::from_str(&self.path)
.map_err(|err| Error::Matcher(err.into()))?;
let scope = scope.join(path);
let iter = self.builders.into_iter().map(|item| match item {
Builder::Stack(builder) => builder
.try_into_middleware(&scope)
.map(|middleware| Box::new(middleware) as Box<dyn Middleware>),
Builder::Routes(builder) => builder
.try_into_middleware(&scope)
.map(|middleware| Box::new(middleware) as Box<dyn Middleware>),
});
iter.collect()
}
}
impl TryIntoHandler for Router {
type Output = Stack;
fn try_into_handler(self) -> Result<Self::Output> {
let scope = Scope::default();
self.try_into_middleware(&scope)
}
}
impl Default for Router {
fn default() -> Self {
Self {
builders: Vec::default(),
path: String::from("/"),
}
}
}