simplify RumaHandler for Router building.

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-05-23 18:43:12 +00:00 committed by June 🍓🦴
parent 27dcf213f1
commit 3f5349ad76

View file

@ -1,7 +1,6 @@
use std::future::Future; use std::future::Future;
use axum::{ use axum::{
extract::FromRequestParts,
response::IntoResponse, response::IntoResponse,
routing::{any, get, on, post, MethodFilter}, routing::{any, get, on, post, MethodFilter},
Router, Router,
@ -244,63 +243,47 @@ trait RouterExt {
} }
impl RouterExt for Router { impl RouterExt for Router {
#[inline(always)]
fn ruma_route<H, T>(self, handler: H) -> Self fn ruma_route<H, T>(self, handler: H) -> Self
where where
H: RumaHandler<T>, H: RumaHandler<T>,
T: 'static, T: 'static,
{ {
handler.add_to_router(self) handler.add_routes(self)
} }
} }
trait RumaHandler<T> { trait RumaHandler<T> {
// Can't transform to a handler without boxing or relying on the nightly-only fn add_routes(&self, router: Router) -> Router;
// impl-trait-in-traits feature. Moving a small amount of extra logic into the
// trait allows bypassing both. fn add_route(&self, router: Router, path: &str) -> Router;
fn add_to_router(self, router: Router) -> Router;
} }
macro_rules! impl_ruma_handler { impl<Req, E, F, Fut> RumaHandler<Ruma<Req>> for F
( $($ty:ident),* $(,)? ) => {
#[axum::async_trait]
#[allow(non_snake_case)]
impl<Req, E, F, Fut, $($ty,)*> RumaHandler<($($ty,)* Ruma<Req>,)> for F
where where
Req: IncomingRequest + Send + 'static, Req: IncomingRequest + Send + 'static,
F: FnOnce($($ty,)* Ruma<Req>) -> Fut + Clone + Send + 'static, F: FnOnce(Ruma<Req>) -> Fut + Clone + Send + Sync + 'static,
Fut: Future<Output = Result<Req::OutgoingResponse, E>> Fut: Future<Output = Result<Req::OutgoingResponse, E>> + Send,
+ Send,
E: IntoResponse, E: IntoResponse,
$( $ty: FromRequestParts<()> + Send + 'static, )*
{ {
fn add_to_router(self, mut router: Router) -> Router { #[inline(always)]
let meta = Req::METADATA; fn add_routes(&self, router: Router) -> Router {
let method_filter = method_to_filter(meta.method); Req::METADATA
.history
for path in meta.history.all_paths() { .all_paths()
let handler = self.clone(); .fold(router, |router, path| self.add_route(router, path))
router = router.route(path, on(method_filter, |$( $ty: $ty, )* req| async move {
handler($($ty,)* req).await.map(RumaResponse)
}))
} }
router #[inline(always)]
fn add_route(&self, router: Router, path: &str) -> Router {
let handle = self.clone();
let method = method_to_filter(Req::METADATA.method);
let action = |req| async { handle(req).await.map(RumaResponse) };
router.route(path, on(method, action))
} }
} }
};
}
impl_ruma_handler!();
impl_ruma_handler!(T1);
impl_ruma_handler!(T1, T2);
impl_ruma_handler!(T1, T2, T3);
impl_ruma_handler!(T1, T2, T3, T4);
impl_ruma_handler!(T1, T2, T3, T4, T5);
impl_ruma_handler!(T1, T2, T3, T4, T5, T6);
impl_ruma_handler!(T1, T2, T3, T4, T5, T6, T7);
impl_ruma_handler!(T1, T2, T3, T4, T5, T6, T7, T8);
#[inline]
fn method_to_filter(method: Method) -> MethodFilter { fn method_to_filter(method: Method) -> MethodFilter {
match method { match method {
Method::DELETE => MethodFilter::DELETE, Method::DELETE => MethodFilter::DELETE,