From e1d5f4b03cc5e3c9142a9e7d652fb1efcb3bc7d9 Mon Sep 17 00:00:00 2001 From: tim gretler Date: Mon, 18 Mar 2024 11:39:59 +0100 Subject: [PATCH 1/2] implement BoxCloneSyncService --- tower/src/util/boxed_clone_sync.rs | 96 ++++++++++++++++++++++++++++++ tower/src/util/mod.rs | 2 + 2 files changed, 98 insertions(+) create mode 100644 tower/src/util/boxed_clone_sync.rs diff --git a/tower/src/util/boxed_clone_sync.rs b/tower/src/util/boxed_clone_sync.rs new file mode 100644 index 000000000..355592e4b --- /dev/null +++ b/tower/src/util/boxed_clone_sync.rs @@ -0,0 +1,96 @@ +use super::ServiceExt; +use futures_util::future::BoxFuture; +use std::{ + fmt, + task::{Context, Poll}, +}; +use tower_layer::{layer_fn, LayerFn}; +use tower_service::Service; + +/// A [`Clone`] + [`Send`] + [`Sync`] boxed [`Service`]. +/// +/// [`BoxCloneSyncService`] turns a service into a trait object, allowing the +/// response future type to be dynamic, and allowing the service to be cloned and shared. +/// +/// This is similar to [`BoxCloneService`](super::BoxCloneService) except the resulting +/// service implements [`Sync`]. +/// ``` +pub struct BoxCloneSyncService( + Box< + dyn CloneService>> + + Send, + >, +); + +impl BoxCloneSyncService { + /// Create a new `BoxCloneService`. + pub fn new(inner: S) -> Self + where + S: Service + Clone + Send + 'static, + S::Future: Send + 'static, + { + let inner = inner.map_future(|f| Box::pin(f) as _); + BoxCloneSyncService(Box::new(inner)) + } + + /// Returns a [`Layer`] for wrapping a [`Service`] in a [`BoxCloneSyncService`] + /// middleware. + /// + /// [`Layer`]: crate::Layer + pub fn layer() -> LayerFn Self> + where + S: Service + Clone + Send + 'static, + S::Future: Send + 'static, + { + layer_fn(Self::new) + } +} + +impl Service for BoxCloneSyncService { + type Response = U; + type Error = E; + type Future = BoxFuture<'static, Result>; + + #[inline] + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.0.poll_ready(cx) + } + + #[inline] + fn call(&mut self, request: T) -> Self::Future { + self.0.call(request) + } +} + +impl Clone for BoxCloneSyncService { + fn clone(&self) -> Self { + Self(self.0.clone_box()) + } +} + +trait CloneService: Service { + fn clone_box( + &self, + ) -> Box< + dyn CloneService + + Send, + >; +} + +impl CloneService for T +where + T: Service + Send + Clone + 'static, +{ + fn clone_box( + &self, + ) -> Box + Send> + { + Box::new(self.clone()) + } +} + +impl fmt::Debug for BoxCloneSyncService { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BoxCloneSyncService").finish() + } +} diff --git a/tower/src/util/mod.rs b/tower/src/util/mod.rs index c617a9e05..dcc35cc42 100644 --- a/tower/src/util/mod.rs +++ b/tower/src/util/mod.rs @@ -3,6 +3,7 @@ mod and_then; mod boxed; mod boxed_clone; +mod boxed_clone_sync; mod call_all; mod either; @@ -25,6 +26,7 @@ pub use self::{ and_then::{AndThen, AndThenLayer}, boxed::{BoxCloneServiceLayer, BoxLayer, BoxService, UnsyncBoxService}, boxed_clone::BoxCloneService, + boxed_clone_sync::BoxCloneSyncService, either::Either, future_service::{future_service, FutureService}, map_err::{MapErr, MapErrLayer}, From 1f2711a8e85754e239debb15f7144e18b0c3078c Mon Sep 17 00:00:00 2001 From: tim gretler Date: Mon, 18 Mar 2024 11:43:06 +0100 Subject: [PATCH 2/2] add sync bound --- tower/src/util/boxed_clone_sync.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tower/src/util/boxed_clone_sync.rs b/tower/src/util/boxed_clone_sync.rs index 355592e4b..e8cbe0077 100644 --- a/tower/src/util/boxed_clone_sync.rs +++ b/tower/src/util/boxed_clone_sync.rs @@ -18,7 +18,8 @@ use tower_service::Service; pub struct BoxCloneSyncService( Box< dyn CloneService>> - + Send, + + Send + + Sync, >, ); @@ -26,7 +27,7 @@ impl BoxCloneSyncService { /// Create a new `BoxCloneService`. pub fn new(inner: S) -> Self where - S: Service + Clone + Send + 'static, + S: Service + Clone + Send + Sync + 'static, S::Future: Send + 'static, { let inner = inner.map_future(|f| Box::pin(f) as _); @@ -39,7 +40,7 @@ impl BoxCloneSyncService { /// [`Layer`]: crate::Layer pub fn layer() -> LayerFn Self> where - S: Service + Clone + Send + 'static, + S: Service + Clone + Send + Sync + 'static, S::Future: Send + 'static, { layer_fn(Self::new) @@ -73,18 +74,22 @@ trait CloneService: Service { &self, ) -> Box< dyn CloneService - + Send, + + Send + + Sync, >; } impl CloneService for T where - T: Service + Send + Clone + 'static, + T: Service + Send + Sync + Clone + 'static, { fn clone_box( &self, - ) -> Box + Send> - { + ) -> Box< + dyn CloneService + + Send + + Sync, + > { Box::new(self.clone()) } }