diff --git a/axum-extra/Cargo.toml b/axum-extra/Cargo.toml index 52072240..53bf3f54 100644 --- a/axum-extra/Cargo.toml +++ b/axum-extra/Cargo.toml @@ -43,7 +43,10 @@ typed-routing = ["dep:axum-macros", "dep:percent-encoding", "dep:serde_html_form axum = { path = "../axum", version = "0.8.0-alpha.1", default-features = false, features = ["original-uri"] } axum-core = { path = "../axum-core", version = "0.5.0-alpha.1" } bytes = "1.1.0" -futures-util = { version = "0.3", default-features = false, features = ["alloc"] } +futures = "*" +futures-util = { version = "0.3", default-features = false, features = [ + "alloc", +] } http = "1.0.0" http-body = "1.0.0" http-body-util = "0.1.0" diff --git a/axum-extra/src/lib.rs b/axum-extra/src/lib.rs index 02dd6e69..94b4f4bd 100644 --- a/axum-extra/src/lib.rs +++ b/axum-extra/src/lib.rs @@ -78,6 +78,7 @@ pub mod handler; pub mod middleware; pub mod response; pub mod routing; +mod test_method_routing; #[cfg(feature = "json-lines")] pub mod json_lines; diff --git a/axum-extra/src/test_method_routing.rs b/axum-extra/src/test_method_routing.rs new file mode 100644 index 00000000..173ac560 --- /dev/null +++ b/axum-extra/src/test_method_routing.rs @@ -0,0 +1,59 @@ +use std::{ + collections::HashMap, + convert::Infallible, + marker::PhantomData, + task::{Context, Poll}, +}; + +use axum::{ + body::Body, + extract::Request, + http::StatusCode, + response::{IntoResponse, Response}, + routing::MethodRouter, +}; +use futures::{future::BoxFuture, FutureExt}; +use tower::Service; + +trait CommandFromBody { + fn command_from_body(body: &[u8]) -> Option<&str>; +} + +struct ExampleService { + routes: HashMap, + _phantom_c: PhantomData C>, +} + +impl Service for ExampleService +where + C: CommandFromBody, +{ + type Error = Infallible; + type Response = Response; + type Future = BoxFuture<'static, Result>; + + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, req: Request) -> Self::Future { + async move { + let (parts, body) = req.into_parts(); + + let Ok(bytes) = axum::body::to_bytes(body, usize::MAX).await else { + return Ok(StatusCode::INTERNAL_SERVER_ERROR.into_response()); + }; + + match C::command_from_body(&bytes).and_then(|cmd| self.routes.get(cmd)) { + Some(router) => { + let req = Request::from_parts(parts, Body::from(bytes)); + + router.call_with_state(req, ()).await + } + + None => Ok(StatusCode::NOT_FOUND.into_response()), + } + } + .boxed() + } +} diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs index cfc47e1f..7a4d7a15 100644 --- a/axum/src/routing/method_routing.rs +++ b/axum/src/routing/method_routing.rs @@ -1110,7 +1110,7 @@ where self } - pub(crate) fn call_with_state(&self, req: Request, state: S) -> RouteFuture { + pub fn call_with_state(&self, req: Request, state: S) -> RouteFuture { macro_rules! call { ( $req:expr,