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}