tower/util/boxed/
layer_clone_sync.rs

1use std::{fmt, sync::Arc};
2use tower_layer::{layer_fn, Layer};
3use tower_service::Service;
4
5use crate::util::BoxCloneSyncService;
6
7/// A [`Clone`] + [`Send`] + [`Sync`] boxed [`Layer`].
8///
9/// [`BoxCloneSyncServiceLayer`] turns a layer into a trait object, allowing both the [`Layer`] itself
10/// and the output [`Service`] to be dynamic, while having consistent types.
11///
12/// This [`Layer`] produces [`BoxCloneSyncService`] instances erasing the type of the
13/// [`Service`] produced by the wrapped [`Layer`].
14///
15/// This is similar to [`BoxCloneServiceLayer`](super::BoxCloneServiceLayer) except the layer and resulting
16/// service implements [`Sync`].
17///
18/// # Example
19///
20/// `BoxCloneSyncServiceLayer` can, for example, be useful to create layers dynamically that otherwise wouldn't have
21/// the same types, when the underlying service must be clone and sync (for example, when building a Hyper connector).
22/// In this example, we include a [`Timeout`] layer only if an environment variable is set. We can use
23/// `BoxCloneSyncServiceLayer` to return a consistent type regardless of runtime configuration:
24///
25/// ```
26/// use std::time::Duration;
27/// use tower::{Service, ServiceBuilder, BoxError};
28/// use tower::util::{BoxCloneSyncServiceLayer, BoxCloneSyncService};
29///
30/// #
31/// # struct Request;
32/// # struct Response;
33/// # impl Response {
34/// #     fn new() -> Self { Self }
35/// # }
36///
37/// fn common_layer<S, T>() -> BoxCloneSyncServiceLayer<S, T, S::Response, BoxError>
38/// where
39///     S: Service<T> + Clone + Send + Sync + 'static,
40///     S::Future: Send + 'static,
41///     S::Error: Into<BoxError> + 'static,
42/// {
43///     let builder = ServiceBuilder::new()
44///         .concurrency_limit(100);
45///
46///     if std::env::var("SET_TIMEOUT").is_ok() {
47///         let layer = builder
48///             .timeout(Duration::from_secs(30))
49///             .into_inner();
50///
51///         BoxCloneSyncServiceLayer::new(layer)
52///     } else {
53///         let layer = builder
54///             .map_err(Into::into)
55///             .into_inner();
56///
57///         BoxCloneSyncServiceLayer::new(layer)
58///     }
59/// }
60///
61/// // We can clone the layer (this is true of BoxLayer as well)
62/// let boxed_clone_sync_layer = common_layer();
63///
64/// let cloned_sync_layer = boxed_clone_sync_layer.clone();
65///
66/// // Using the `BoxCloneSyncServiceLayer` we can create a `BoxCloneSyncService`
67/// let service: BoxCloneSyncService<Request, Response, BoxError> = ServiceBuilder::new().layer(cloned_sync_layer)
68///      .service_fn(|req: Request| async {
69///         Ok::<_, BoxError>(Response::new())
70///     });
71///
72/// # let service = assert_service(service);
73///
74/// // And we can still clone the service
75/// let cloned_service = service.clone();
76/// #
77/// # fn assert_service<S, R>(svc: S) -> S
78/// # where S: Service<R> { svc }
79///
80/// ```
81///
82/// [`Layer`]: tower_layer::Layer
83/// [`Service`]: tower_service::Service
84/// [`BoxService`]: super::BoxService
85/// [`Timeout`]: crate::timeout
86pub struct BoxCloneSyncServiceLayer<In, T, U, E> {
87    boxed: Arc<dyn Layer<In, Service = BoxCloneSyncService<T, U, E>> + Send + Sync + 'static>,
88}
89
90impl<In, T, U, E> BoxCloneSyncServiceLayer<In, T, U, E> {
91    /// Create a new [`BoxCloneSyncServiceLayer`].
92    pub fn new<L>(inner_layer: L) -> Self
93    where
94        L: Layer<In> + Send + Sync + 'static,
95        L::Service: Service<T, Response = U, Error = E> + Send + Sync + Clone + 'static,
96        <L::Service as Service<T>>::Future: Send + 'static,
97    {
98        let layer = layer_fn(move |inner: In| {
99            let out = inner_layer.layer(inner);
100            BoxCloneSyncService::new(out)
101        });
102
103        Self {
104            boxed: Arc::new(layer),
105        }
106    }
107}
108
109impl<In, T, U, E> Layer<In> for BoxCloneSyncServiceLayer<In, T, U, E> {
110    type Service = BoxCloneSyncService<T, U, E>;
111
112    fn layer(&self, inner: In) -> Self::Service {
113        self.boxed.layer(inner)
114    }
115}
116
117impl<In, T, U, E> Clone for BoxCloneSyncServiceLayer<In, T, U, E> {
118    fn clone(&self) -> Self {
119        Self {
120            boxed: Arc::clone(&self.boxed),
121        }
122    }
123}
124
125impl<In, T, U, E> fmt::Debug for BoxCloneSyncServiceLayer<In, T, U, E> {
126    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
127        fmt.debug_struct("BoxCloneSyncServiceLayer").finish()
128    }
129}