Skip to content

Commit 52fd139

Browse files
davidpdrsnjplatte
andauthored
Require Sync for services (#2473)
Co-authored-by: Jonas Platte <[email protected]>
1 parent 19101f6 commit 52fd139

File tree

14 files changed

+137
-47
lines changed

14 files changed

+137
-47
lines changed

axum-extra/src/handler/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ pub struct IntoHandler<H, T, S> {
165165

166166
impl<H, T, S> Handler<T, S> for IntoHandler<H, T, S>
167167
where
168-
H: HandlerCallWithExtractors<T, S> + Clone + Send + 'static,
168+
H: HandlerCallWithExtractors<T, S> + Clone + Send + Sync + 'static,
169169
T: FromRequest<S> + Send + 'static,
170170
T::Rejection: Send,
171171
S: Send + Sync + 'static,

axum-extra/src/handler/or.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ where
5454

5555
impl<S, L, R, Lt, Rt, M> Handler<(M, Lt, Rt), S> for Or<L, R, Lt, Rt, S>
5656
where
57-
L: HandlerCallWithExtractors<Lt, S> + Clone + Send + 'static,
58-
R: HandlerCallWithExtractors<Rt, S> + Clone + Send + 'static,
57+
L: HandlerCallWithExtractors<Lt, S> + Clone + Send + Sync + 'static,
58+
R: HandlerCallWithExtractors<Rt, S> + Clone + Send + Sync + 'static,
5959
Lt: FromRequestParts<S> + Send + 'static,
6060
Rt: FromRequest<S, M> + Send + 'static,
6161
Lt::Rejection: Send,

axum-extra/src/routing/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ pub trait RouterExt<S>: sealed::Sealed {
165165
/// This works like [`RouterExt::route_with_tsr`] but accepts any [`Service`].
166166
fn route_service_with_tsr<T>(self, path: &str, service: T) -> Self
167167
where
168-
T: Service<Request, Error = Infallible> + Clone + Send + 'static,
168+
T: Service<Request, Error = Infallible> + Clone + Send + Sync + 'static,
169169
T::Response: IntoResponse,
170170
T::Future: Send + 'static,
171171
Self: Sized;
@@ -268,7 +268,7 @@ where
268268
#[track_caller]
269269
fn route_service_with_tsr<T>(mut self, path: &str, service: T) -> Self
270270
where
271-
T: Service<Request, Error = Infallible> + Clone + Send + 'static,
271+
T: Service<Request, Error = Infallible> + Clone + Send + Sync + 'static,
272272
T::Response: IntoResponse,
273273
T::Future: Send + 'static,
274274
Self: Sized,

axum/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
# Unreleased
99

10+
- **breaking:** Require `Sync` for all handlers and services added to `Router`
11+
and `MethodRouter` ([#2473])
1012
- **breaking:** The tuple and tuple_struct `Path` extractor deserializers now check that the number of parameters matches the tuple length exactly ([#2931])
1113
- **change:** Update minimum rust version to 1.75 ([#2943])
1214

15+
[#2473]: https://github.com/tokio-rs/axum/pull/2473
1316
[#2931]: https://github.com/tokio-rs/axum/pull/2931
1417
[#2943]: https://github.com/tokio-rs/axum/pull/2943
1518

@@ -55,7 +58,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5558

5659
[#2201]: https://github.com/tokio-rs/axum/pull/2201
5760
[#2483]: https://github.com/tokio-rs/axum/pull/2483
58-
[#2201]: https://github.com/tokio-rs/axum/pull/2201
5961
[#2484]: https://github.com/tokio-rs/axum/pull/2484
6062

6163
# 0.7.3 (29. December, 2023)

axum/src/box_clone_service.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
use futures_util::future::BoxFuture;
2+
use std::{
3+
fmt,
4+
task::{Context, Poll},
5+
};
6+
use tower::ServiceExt;
7+
use tower_service::Service;
8+
9+
/// Like `tower::BoxCloneService` but `Sync`
10+
pub(crate) struct BoxCloneService<T, U, E>(
11+
Box<
12+
dyn CloneService<T, Response = U, Error = E, Future = BoxFuture<'static, Result<U, E>>>
13+
+ Send
14+
+ Sync,
15+
>,
16+
);
17+
18+
impl<T, U, E> BoxCloneService<T, U, E> {
19+
pub(crate) fn new<S>(inner: S) -> Self
20+
where
21+
S: Service<T, Response = U, Error = E> + Clone + Send + Sync + 'static,
22+
S::Future: Send + 'static,
23+
{
24+
let inner = inner.map_future(|f| Box::pin(f) as _);
25+
BoxCloneService(Box::new(inner))
26+
}
27+
}
28+
29+
impl<T, U, E> Service<T> for BoxCloneService<T, U, E> {
30+
type Response = U;
31+
type Error = E;
32+
type Future = BoxFuture<'static, Result<U, E>>;
33+
34+
#[inline]
35+
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), E>> {
36+
self.0.poll_ready(cx)
37+
}
38+
39+
#[inline]
40+
fn call(&mut self, request: T) -> Self::Future {
41+
self.0.call(request)
42+
}
43+
}
44+
45+
impl<T, U, E> Clone for BoxCloneService<T, U, E> {
46+
fn clone(&self) -> Self {
47+
Self(self.0.clone_box())
48+
}
49+
}
50+
51+
trait CloneService<R>: Service<R> {
52+
fn clone_box(
53+
&self,
54+
) -> Box<
55+
dyn CloneService<R, Response = Self::Response, Error = Self::Error, Future = Self::Future>
56+
+ Send
57+
+ Sync,
58+
>;
59+
}
60+
61+
impl<R, T> CloneService<R> for T
62+
where
63+
T: Service<R> + Send + Sync + Clone + 'static,
64+
{
65+
fn clone_box(
66+
&self,
67+
) -> Box<
68+
dyn CloneService<R, Response = T::Response, Error = T::Error, Future = T::Future>
69+
+ Send
70+
+ Sync,
71+
> {
72+
Box::new(self.clone())
73+
}
74+
}
75+
76+
impl<T, U, E> fmt::Debug for BoxCloneService<T, U, E> {
77+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
78+
fmt.debug_struct("BoxCloneService").finish()
79+
}
80+
}

axum/src/boxed.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl<S, E> BoxedIntoRoute<S, E> {
3333
where
3434
S: 'static,
3535
E: 'static,
36-
F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + 'static,
36+
F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + Sync + 'static,
3737
E2: 'static,
3838
{
3939
BoxedIntoRoute(AxumMutex::new(Box::new(Map {
@@ -59,7 +59,7 @@ impl<S, E> fmt::Debug for BoxedIntoRoute<S, E> {
5959
}
6060
}
6161

62-
pub(crate) trait ErasedIntoRoute<S, E>: Send {
62+
pub(crate) trait ErasedIntoRoute<S, E>: Send + Sync {
6363
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, E>>;
6464

6565
fn into_route(self: Box<Self>, state: S) -> Route<E>;
@@ -75,7 +75,7 @@ pub(crate) struct MakeErasedHandler<H, S> {
7575

7676
impl<H, S> ErasedIntoRoute<S, Infallible> for MakeErasedHandler<H, S>
7777
where
78-
H: Clone + Send + 'static,
78+
H: Clone + Send + Sync + 'static,
7979
S: 'static,
8080
{
8181
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, Infallible>> {
@@ -165,13 +165,13 @@ where
165165
}
166166
}
167167

168-
pub(crate) trait LayerFn<E, E2>: FnOnce(Route<E>) -> Route<E2> + Send {
168+
pub(crate) trait LayerFn<E, E2>: FnOnce(Route<E>) -> Route<E2> + Send + Sync {
169169
fn clone_box(&self) -> Box<dyn LayerFn<E, E2>>;
170170
}
171171

172172
impl<F, E, E2> LayerFn<E, E2> for F
173173
where
174-
F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + 'static,
174+
F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + Sync + 'static,
175175
{
176176
fn clone_box(&self) -> Box<dyn LayerFn<E, E2>> {
177177
Box::new(self.clone())

axum/src/handler/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ pub use self::service::HandlerService;
131131
note = "Consider using `#[axum::debug_handler]` to improve the error message"
132132
)
133133
)]
134-
pub trait Handler<T, S>: Clone + Send + Sized + 'static {
134+
pub trait Handler<T, S>: Clone + Send + Sync + Sized + 'static {
135135
/// The type of future calling this handler returns.
136136
type Future: Future<Output = Response> + Send + 'static;
137137

@@ -192,7 +192,7 @@ pub trait Handler<T, S>: Clone + Send + Sized + 'static {
192192

193193
impl<F, Fut, Res, S> Handler<((),), S> for F
194194
where
195-
F: FnOnce() -> Fut + Clone + Send + 'static,
195+
F: FnOnce() -> Fut + Clone + Send + Sync + 'static,
196196
Fut: Future<Output = Res> + Send,
197197
Res: IntoResponse,
198198
{
@@ -210,7 +210,7 @@ macro_rules! impl_handler {
210210
#[allow(non_snake_case, unused_mut)]
211211
impl<F, Fut, S, Res, M, $($ty,)* $last> Handler<(M, $($ty,)* $last,), S> for F
212212
where
213-
F: FnOnce($($ty,)* $last,) -> Fut + Clone + Send + 'static,
213+
F: FnOnce($($ty,)* $last,) -> Fut + Clone + Send + Sync + 'static,
214214
Fut: Future<Output = Res> + Send,
215215
S: Send + Sync + 'static,
216216
Res: IntoResponse,
@@ -257,7 +257,7 @@ mod private {
257257

258258
impl<T, S> Handler<private::IntoResponseHandler, S> for T
259259
where
260-
T: IntoResponse + Clone + Send + 'static,
260+
T: IntoResponse + Clone + Send + Sync + 'static,
261261
{
262262
type Future = std::future::Ready<Response>;
263263

@@ -302,7 +302,7 @@ where
302302

303303
impl<H, S, T, L> Handler<T, S> for Layered<L, H, T, S>
304304
where
305-
L: Layer<HandlerService<H, T, S>> + Clone + Send + 'static,
305+
L: Layer<HandlerService<H, T, S>> + Clone + Send + Sync + 'static,
306306
H: Handler<T, S>,
307307
L::Service: Service<Request, Error = Infallible> + Clone + Send + 'static,
308308
<L::Service as Service<Request>>::Response: IntoResponse,

axum/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@
463463
#[macro_use]
464464
pub(crate) mod macros;
465465

466+
mod box_clone_service;
466467
mod boxed;
467468
mod extension;
468469
#[cfg(feature = "form")]

axum/src/middleware/from_fn.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::box_clone_service::BoxCloneService;
12
use crate::response::{IntoResponse, Response};
23
use axum_core::extract::{FromRequest, FromRequestParts, Request};
34
use futures_util::future::BoxFuture;
@@ -10,7 +11,7 @@ use std::{
1011
pin::Pin,
1112
task::{Context, Poll},
1213
};
13-
use tower::{util::BoxCloneService, ServiceBuilder};
14+
use tower::ServiceBuilder;
1415
use tower_layer::Layer;
1516
use tower_service::Service;
1617

@@ -260,6 +261,7 @@ macro_rules! impl_service {
260261
I: Service<Request, Error = Infallible>
261262
+ Clone
262263
+ Send
264+
+ Sync
263265
+ 'static,
264266
I::Response: IntoResponse,
265267
I::Future: Send + 'static,
@@ -298,7 +300,7 @@ macro_rules! impl_service {
298300
};
299301

300302
let inner = ServiceBuilder::new()
301-
.boxed_clone()
303+
.layer_fn(BoxCloneService::new)
302304
.map_response(IntoResponse::into_response)
303305
.service(ready_inner);
304306
let next = Next { inner };

axum/src/routing/method_routing.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ macro_rules! top_level_service_fn {
7878
$(#[$m])+
7979
pub fn $name<T, S>(svc: T) -> MethodRouter<S, T::Error>
8080
where
81-
T: Service<Request> + Clone + Send + 'static,
81+
T: Service<Request> + Clone + Send + Sync + 'static,
8282
T::Response: IntoResponse + 'static,
8383
T::Future: Send + 'static,
8484
S: Clone,
@@ -210,6 +210,7 @@ macro_rules! chained_service_fn {
210210
T: Service<Request, Error = E>
211211
+ Clone
212212
+ Send
213+
+ Sync
213214
+ 'static,
214215
T::Response: IntoResponse + 'static,
215216
T::Future: Send + 'static,
@@ -312,7 +313,7 @@ top_level_service_fn!(trace_service, TRACE);
312313
/// ```
313314
pub fn on_service<T, S>(filter: MethodFilter, svc: T) -> MethodRouter<S, T::Error>
314315
where
315-
T: Service<Request> + Clone + Send + 'static,
316+
T: Service<Request> + Clone + Send + Sync + 'static,
316317
T::Response: IntoResponse + 'static,
317318
T::Future: Send + 'static,
318319
S: Clone,
@@ -371,7 +372,7 @@ where
371372
/// ```
372373
pub fn any_service<T, S>(svc: T) -> MethodRouter<S, T::Error>
373374
where
374-
T: Service<Request> + Clone + Send + 'static,
375+
T: Service<Request> + Clone + Send + Sync + 'static,
375376
T::Response: IntoResponse + 'static,
376377
T::Future: Send + 'static,
377378
S: Clone,
@@ -736,7 +737,7 @@ where
736737
#[track_caller]
737738
pub fn on_service<T>(self, filter: MethodFilter, svc: T) -> Self
738739
where
739-
T: Service<Request, Error = E> + Clone + Send + 'static,
740+
T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
740741
T::Response: IntoResponse + 'static,
741742
T::Future: Send + 'static,
742743
{
@@ -868,7 +869,7 @@ where
868869
#[doc = include_str!("../docs/method_routing/fallback.md")]
869870
pub fn fallback_service<T>(mut self, svc: T) -> Self
870871
where
871-
T: Service<Request, Error = E> + Clone + Send + 'static,
872+
T: Service<Request, Error = E> + Clone + Send + Sync + 'static,
872873
T::Response: IntoResponse + 'static,
873874
T::Future: Send + 'static,
874875
{
@@ -879,8 +880,8 @@ where
879880
#[doc = include_str!("../docs/method_routing/layer.md")]
880881
pub fn layer<L, NewError>(self, layer: L) -> MethodRouter<S, NewError>
881882
where
882-
L: Layer<Route<E>> + Clone + Send + 'static,
883-
L::Service: Service<Request> + Clone + Send + 'static,
883+
L: Layer<Route<E>> + Clone + Send + Sync + 'static,
884+
L::Service: Service<Request> + Clone + Send + Sync + 'static,
884885
<L::Service as Service<Request>>::Response: IntoResponse + 'static,
885886
<L::Service as Service<Request>>::Error: Into<NewError> + 'static,
886887
<L::Service as Service<Request>>::Future: Send + 'static,
@@ -908,8 +909,8 @@ where
908909
#[track_caller]
909910
pub fn route_layer<L>(mut self, layer: L) -> MethodRouter<S, E>
910911
where
911-
L: Layer<Route<E>> + Clone + Send + 'static,
912-
L::Service: Service<Request, Error = E> + Clone + Send + 'static,
912+
L: Layer<Route<E>> + Clone + Send + Sync + 'static,
913+
L::Service: Service<Request, Error = E> + Clone + Send + Sync + 'static,
913914
<L::Service as Service<Request>>::Response: IntoResponse + 'static,
914915
<L::Service as Service<Request>>::Future: Send + 'static,
915916
E: 'static,
@@ -1151,7 +1152,7 @@ where
11511152
where
11521153
S: 'static,
11531154
E: 'static,
1154-
F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + 'static,
1155+
F: FnOnce(Route<E>) -> Route<E2> + Clone + Send + Sync + 'static,
11551156
E2: 'static,
11561157
{
11571158
match self {

0 commit comments

Comments
 (0)