use axum::handler::Handler;
use axum::routing::MethodRouter;
use indexmap::IndexMap;
#[cfg(feature = "ts")]
use crate::bindings::register_runtime_route;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Method {
GET,
POST,
PUT,
PATCH,
DELETE,
HEAD,
OPTIONS,
}
impl Method {
pub fn as_str(self) -> &'static str {
match self {
Method::GET => "get",
Method::POST => "post",
Method::PUT => "put",
Method::PATCH => "patch",
Method::DELETE => "delete",
Method::HEAD => "head",
Method::OPTIONS => "options",
}
}
fn into_router<H, T, S>(self, handler: H) -> MethodRouter<S>
where
H: Handler<T, S>,
T: 'static,
S: Clone + Send + Sync + 'static,
{
use axum::routing as r;
match self {
Method::GET => r::get(handler),
Method::POST => r::post(handler),
Method::PUT => r::put(handler),
Method::PATCH => r::patch(handler),
Method::DELETE => r::delete(handler),
Method::HEAD => r::head(handler),
Method::OPTIONS => r::options(handler),
}
}
}
pub struct Router<S = ()> {
routes: IndexMap<&'static str, MethodRouter<S>>,
names: Vec<NamedRoute>,
raw: Vec<RawRoute<S>>,
}
#[cfg_attr(not(feature = "ts"), allow(dead_code))]
struct NamedRoute {
name: &'static str,
path: &'static str,
method: &'static str,
}
struct RawRoute<S> {
path: &'static str,
router: MethodRouter<S>,
}
impl<S> Default for Router<S> {
fn default() -> Self {
Self {
routes: IndexMap::new(),
names: Vec::new(),
raw: Vec::new(),
}
}
}
impl<S> Router<S>
where
S: Clone + Send + Sync + 'static,
{
pub fn new() -> Self {
Self::default()
}
pub fn named_route<H, T>(
mut self,
method: Method,
name: &'static str,
path: &'static str,
handler: H,
) -> Self
where
H: Handler<T, S>,
T: 'static,
{
let mr = method.into_router(handler);
match self.routes.swap_remove(path) {
Some(prev) => {
self.routes.insert(path, prev.merge(mr));
}
None => {
self.routes.insert(path, mr);
}
}
self.names.push(NamedRoute {
name,
path,
method: method.as_str(),
});
self
}
pub fn route(mut self, path: &'static str, method_router: MethodRouter<S>) -> Self {
self.raw.push(RawRoute {
path,
router: method_router,
});
self
}
pub fn build(self) -> axum::Router<S> {
#[cfg(feature = "ts")]
for r in &self.names {
register_runtime_route(r.name, r.path, r.method);
}
#[cfg(not(feature = "ts"))]
let _ = &self.names;
let mut r = axum::Router::new();
for (path, mr) in self.routes {
r = r.route(path, mr);
}
for raw in self.raw {
r = r.route(raw.path, raw.router);
}
r
}
}