From b363354eaac02fe4770dc8d750ea0897a97190b5 Mon Sep 17 00:00:00 2001 From: novacrazy Date: Wed, 9 Oct 2024 22:16:18 +0200 Subject: [PATCH] avoid one state clone This is an extraction of a part of https://github.com/tokio-rs/axum/pull/2865 --- axum/src/routing/method_routing.rs | 31 ++++++++++++++---------------- axum/src/routing/route.rs | 6 ++++++ axum/src/routing/tests/mod.rs | 2 +- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/axum/src/routing/method_routing.rs b/axum/src/routing/method_routing.rs index b4a86501..0e4f5ac6 100644 --- a/axum/src/routing/method_routing.rs +++ b/axum/src/routing/method_routing.rs @@ -1101,27 +1101,24 @@ where macro_rules! call { ( $req:expr, - $method:expr, $method_variant:ident, $svc:expr ) => { - if $method == Method::$method_variant { + if *req.method() == Method::$method_variant { match $svc { MethodEndpoint::None => {} MethodEndpoint::Route(route) => { - return route.clone().oneshot_inner($req); + return route.clone().oneshot_inner_owned($req); } MethodEndpoint::BoxedHandler(handler) => { - let mut route = handler.clone().into_route(state); - return route.oneshot_inner($req); + let route = handler.clone().into_route(state); + return route.oneshot_inner_owned($req); } } } }; } - let method = req.method().clone(); - // written with a pattern match like this to ensure we call all routes let Self { get, @@ -1137,16 +1134,16 @@ where allow_header, } = self; - call!(req, method, HEAD, head); - call!(req, method, HEAD, get); - call!(req, method, GET, get); - call!(req, method, POST, post); - call!(req, method, OPTIONS, options); - call!(req, method, PATCH, patch); - call!(req, method, PUT, put); - call!(req, method, DELETE, delete); - call!(req, method, TRACE, trace); - call!(req, method, CONNECT, connect); + call!(req, HEAD, head); + call!(req, HEAD, get); + call!(req, GET, get); + call!(req, POST, post); + call!(req, OPTIONS, options); + call!(req, PATCH, patch); + call!(req, PUT, put); + call!(req, DELETE, delete); + call!(req, TRACE, trace); + call!(req, CONNECT, connect); let future = fallback.clone().call_with_state(req, state); diff --git a/axum/src/routing/route.rs b/axum/src/routing/route.rs index 0953dfbc..1724c30a 100644 --- a/axum/src/routing/route.rs +++ b/axum/src/routing/route.rs @@ -47,6 +47,12 @@ impl Route { RouteFuture::new(method, self.0.clone().oneshot(req)) } + /// Variant of [`Route::oneshot_inner`] that takes ownership of the route to avoid cloning. + pub(crate) fn oneshot_inner_owned(self, req: Request) -> RouteFuture { + let method = req.method().clone(); + RouteFuture::new(method, self.0.oneshot(req)) + } + pub(crate) fn layer(self, layer: L) -> Route where L: Layer> + Clone + Send + 'static, diff --git a/axum/src/routing/tests/mod.rs b/axum/src/routing/tests/mod.rs index c4e37179..a19c78f2 100644 --- a/axum/src/routing/tests/mod.rs +++ b/axum/src/routing/tests/mod.rs @@ -941,7 +941,7 @@ async fn state_isnt_cloned_too_much() { client.get("/").await; - assert_eq!(COUNT.load(Ordering::SeqCst), 4); + assert_eq!(COUNT.load(Ordering::SeqCst), 3); } #[crate::test]