/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tower-0.5.2/src/builder/mod.rs
Line | Count | Source |
1 | | //! Builder types to compose layers and services |
2 | | |
3 | | use tower_layer::{Identity, Layer, Stack}; |
4 | | use tower_service::Service; |
5 | | |
6 | | use std::fmt; |
7 | | |
8 | | /// Declaratively construct [`Service`] values. |
9 | | /// |
10 | | /// [`ServiceBuilder`] provides a [builder-like interface][builder] for composing |
11 | | /// layers to be applied to a [`Service`]. |
12 | | /// |
13 | | /// # Service |
14 | | /// |
15 | | /// A [`Service`] is a trait representing an asynchronous function of a request |
16 | | /// to a response. It is similar to `async fn(Request) -> Result<Response, Error>`. |
17 | | /// |
18 | | /// A [`Service`] is typically bound to a single transport, such as a TCP |
19 | | /// connection. It defines how _all_ inbound or outbound requests are handled |
20 | | /// by that connection. |
21 | | /// |
22 | | /// [builder]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html |
23 | | /// |
24 | | /// # Order |
25 | | /// |
26 | | /// The order in which layers are added impacts how requests are handled. Layers |
27 | | /// that are added first will be called with the request first. The argument to |
28 | | /// `service` will be last to see the request. |
29 | | /// |
30 | | /// ``` |
31 | | /// # // this (and other) doctest is ignored because we don't have a way |
32 | | /// # // to say that it should only be run with cfg(feature = "...") |
33 | | /// # use tower::Service; |
34 | | /// # use tower::builder::ServiceBuilder; |
35 | | /// # #[cfg(all(feature = "buffer", feature = "limit"))] |
36 | | /// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send { |
37 | | /// ServiceBuilder::new() |
38 | | /// .buffer(100) |
39 | | /// .concurrency_limit(10) |
40 | | /// .service(svc) |
41 | | /// # ; |
42 | | /// # } |
43 | | /// ``` |
44 | | /// |
45 | | /// In the above example, the buffer layer receives the request first followed |
46 | | /// by `concurrency_limit`. `buffer` enables up to 100 request to be in-flight |
47 | | /// **on top of** the requests that have already been forwarded to the next |
48 | | /// layer. Combined with `concurrency_limit`, this allows up to 110 requests to be |
49 | | /// in-flight. |
50 | | /// |
51 | | /// ``` |
52 | | /// # use tower::Service; |
53 | | /// # use tower::builder::ServiceBuilder; |
54 | | /// # #[cfg(all(feature = "buffer", feature = "limit"))] |
55 | | /// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send { |
56 | | /// ServiceBuilder::new() |
57 | | /// .concurrency_limit(10) |
58 | | /// .buffer(100) |
59 | | /// .service(svc) |
60 | | /// # ; |
61 | | /// # } |
62 | | /// ``` |
63 | | /// |
64 | | /// The above example is similar, but the order of layers is reversed. Now, |
65 | | /// `concurrency_limit` applies first and only allows 10 requests to be in-flight |
66 | | /// total. |
67 | | /// |
68 | | /// # Examples |
69 | | /// |
70 | | /// A [`Service`] stack with a single layer: |
71 | | /// |
72 | | /// ``` |
73 | | /// # use tower::Service; |
74 | | /// # use tower::builder::ServiceBuilder; |
75 | | /// # #[cfg(feature = "limit")] |
76 | | /// # use tower::limit::concurrency::ConcurrencyLimitLayer; |
77 | | /// # #[cfg(feature = "limit")] |
78 | | /// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send { |
79 | | /// ServiceBuilder::new() |
80 | | /// .concurrency_limit(5) |
81 | | /// .service(svc); |
82 | | /// # ; |
83 | | /// # } |
84 | | /// ``` |
85 | | /// |
86 | | /// A [`Service`] stack with _multiple_ layers that contain rate limiting, |
87 | | /// in-flight request limits, and a channel-backed, clonable [`Service`]: |
88 | | /// |
89 | | /// ``` |
90 | | /// # use tower::Service; |
91 | | /// # use tower::builder::ServiceBuilder; |
92 | | /// # use std::time::Duration; |
93 | | /// # #[cfg(all(feature = "buffer", feature = "limit"))] |
94 | | /// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send { |
95 | | /// ServiceBuilder::new() |
96 | | /// .buffer(5) |
97 | | /// .concurrency_limit(5) |
98 | | /// .rate_limit(5, Duration::from_secs(1)) |
99 | | /// .service(svc); |
100 | | /// # ; |
101 | | /// # } |
102 | | /// ``` |
103 | | /// |
104 | | /// [`Service`]: crate::Service |
105 | | #[derive(Clone)] |
106 | | pub struct ServiceBuilder<L> { |
107 | | layer: L, |
108 | | } |
109 | | |
110 | | impl Default for ServiceBuilder<Identity> { |
111 | 0 | fn default() -> Self { |
112 | 0 | Self::new() |
113 | 0 | } |
114 | | } |
115 | | |
116 | | impl ServiceBuilder<Identity> { |
117 | | /// Create a new [`ServiceBuilder`]. |
118 | 0 | pub const fn new() -> Self { |
119 | 0 | ServiceBuilder { |
120 | 0 | layer: Identity::new(), |
121 | 0 | } |
122 | 0 | } |
123 | | } |
124 | | |
125 | | impl<L> ServiceBuilder<L> { |
126 | | /// Add a new layer `T` into the [`ServiceBuilder`]. |
127 | | /// |
128 | | /// This wraps the inner service with the service provided by a user-defined |
129 | | /// [`Layer`]. The provided layer must implement the [`Layer`] trait. |
130 | | /// |
131 | | /// [`Layer`]: crate::Layer |
132 | 0 | pub fn layer<T>(self, layer: T) -> ServiceBuilder<Stack<T, L>> { |
133 | 0 | ServiceBuilder { |
134 | 0 | layer: Stack::new(layer, self.layer), |
135 | 0 | } |
136 | 0 | } Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#0}>, tower_layer::identity::Identity>>>::layer::<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#1}>>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#2}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>>::layer::<tower::util::either::Either<tower::limit::concurrency::layer::ConcurrencyLimitLayer, tower_layer::identity::Identity>>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>::layer::<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#2}>>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#0}>, tower_layer::identity::Identity>>>::layer::<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#1}>>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#2}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>>::layer::<tower::util::either::Either<tower::limit::concurrency::layer::ConcurrencyLimitLayer, tower_layer::identity::Identity>>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>::layer::<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#2}>>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower::util::either::Either<tower::limit::concurrency::layer::ConcurrencyLimitLayer, tower_layer::identity::Identity>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#2}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>>>::layer::<tower::util::either::Either<tower::limit::rate::layer::RateLimitLayer, tower_layer::identity::Identity>>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower::util::either::Either<tower::limit::concurrency::layer::ConcurrencyLimitLayer, tower_layer::identity::Identity>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#2}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>>>::layer::<tower::util::either::Either<tower::limit::rate::layer::RateLimitLayer, tower_layer::identity::Identity>>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::identity::Identity>>::layer::<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#0}>>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::identity::Identity>>::layer::<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#0}>>Unexecuted instantiation: <tower::builder::ServiceBuilder<_>>::layer::<_> |
137 | | |
138 | | /// Optionally add a new layer `T` into the [`ServiceBuilder`]. |
139 | | /// |
140 | | /// ``` |
141 | | /// # use std::time::Duration; |
142 | | /// # use tower::Service; |
143 | | /// # use tower::builder::ServiceBuilder; |
144 | | /// # use tower::timeout::TimeoutLayer; |
145 | | /// # async fn wrap<S>(svc: S) where S: Service<(), Error = &'static str> + 'static + Send, S::Future: Send { |
146 | | /// # let timeout = Some(Duration::new(10, 0)); |
147 | | /// // Apply a timeout if configured |
148 | | /// ServiceBuilder::new() |
149 | | /// .option_layer(timeout.map(TimeoutLayer::new)) |
150 | | /// .service(svc) |
151 | | /// # ; |
152 | | /// # } |
153 | | /// ``` |
154 | | #[cfg(feature = "util")] |
155 | 0 | pub fn option_layer<T>( |
156 | 0 | self, |
157 | 0 | layer: Option<T>, |
158 | 0 | ) -> ServiceBuilder<Stack<crate::util::Either<T, Identity>, L>> { |
159 | 0 | self.layer(crate::util::option_layer(layer)) |
160 | 0 | } Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#2}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>>::option_layer::<tower::limit::concurrency::layer::ConcurrencyLimitLayer>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#2}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>>::option_layer::<tower::limit::concurrency::layer::ConcurrencyLimitLayer>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower::util::either::Either<tower::limit::concurrency::layer::ConcurrencyLimitLayer, tower_layer::identity::Identity>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#2}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>>>::option_layer::<tower::limit::rate::layer::RateLimitLayer>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower::util::either::Either<tower::limit::concurrency::layer::ConcurrencyLimitLayer, tower_layer::identity::Identity>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#2}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>>>::option_layer::<tower::limit::rate::layer::RateLimitLayer>Unexecuted instantiation: <tower::builder::ServiceBuilder<_>>::option_layer::<_> |
161 | | |
162 | | /// Add a [`Layer`] built from a function that accepts a service and returns another service. |
163 | | /// |
164 | | /// See the documentation for [`layer_fn`] for more details. |
165 | | /// |
166 | | /// [`layer_fn`]: crate::layer::layer_fn |
167 | 0 | pub fn layer_fn<F>(self, f: F) -> ServiceBuilder<Stack<crate::layer::LayerFn<F>, L>> { |
168 | 0 | self.layer(crate::layer::layer_fn(f)) |
169 | 0 | } Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#0}>, tower_layer::identity::Identity>>>::layer_fn::<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#1}>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>::layer_fn::<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#2}>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#0}>, tower_layer::identity::Identity>>>::layer_fn::<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#1}>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>::layer_fn::<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#2}>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::identity::Identity>>::layer_fn::<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#0}>Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::identity::Identity>>::layer_fn::<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#0}>Unexecuted instantiation: <tower::builder::ServiceBuilder<_>>::layer_fn::<_> |
170 | | |
171 | | /// Buffer requests when the next layer is not ready. |
172 | | /// |
173 | | /// This wraps the inner service with an instance of the [`Buffer`] |
174 | | /// middleware. |
175 | | /// |
176 | | /// [`Buffer`]: crate::buffer |
177 | | #[cfg(feature = "buffer")] |
178 | 0 | pub fn buffer<Request>( |
179 | 0 | self, |
180 | 0 | bound: usize, |
181 | 0 | ) -> ServiceBuilder<Stack<crate::buffer::BufferLayer<Request>, L>> { |
182 | 0 | self.layer(crate::buffer::BufferLayer::new(bound)) |
183 | 0 | } |
184 | | |
185 | | /// Limit the max number of in-flight requests. |
186 | | /// |
187 | | /// A request is in-flight from the time the request is received until the |
188 | | /// response future completes. This includes the time spent in the next |
189 | | /// layers. |
190 | | /// |
191 | | /// This wraps the inner service with an instance of the |
192 | | /// [`ConcurrencyLimit`] middleware. |
193 | | /// |
194 | | /// [`ConcurrencyLimit`]: crate::limit::concurrency |
195 | | #[cfg(feature = "limit")] |
196 | 0 | pub fn concurrency_limit( |
197 | 0 | self, |
198 | 0 | max: usize, |
199 | 0 | ) -> ServiceBuilder<Stack<crate::limit::ConcurrencyLimitLayer, L>> { |
200 | 0 | self.layer(crate::limit::ConcurrencyLimitLayer::new(max)) |
201 | 0 | } |
202 | | |
203 | | /// Drop requests when the next layer is unable to respond to requests. |
204 | | /// |
205 | | /// Usually, when a service or middleware does not have capacity to process a |
206 | | /// request (i.e., [`poll_ready`] returns [`Pending`]), the caller waits until |
207 | | /// capacity becomes available. |
208 | | /// |
209 | | /// [`LoadShed`] immediately responds with an error when the next layer is |
210 | | /// out of capacity. |
211 | | /// |
212 | | /// This wraps the inner service with an instance of the [`LoadShed`] |
213 | | /// middleware. |
214 | | /// |
215 | | /// [`LoadShed`]: crate::load_shed |
216 | | /// [`poll_ready`]: crate::Service::poll_ready |
217 | | /// [`Pending`]: std::task::Poll::Pending |
218 | | #[cfg(feature = "load-shed")] |
219 | 0 | pub fn load_shed(self) -> ServiceBuilder<Stack<crate::load_shed::LoadShedLayer, L>> { |
220 | 0 | self.layer(crate::load_shed::LoadShedLayer::new()) |
221 | 0 | } |
222 | | |
223 | | /// Limit requests to at most `num` per the given duration. |
224 | | /// |
225 | | /// This wraps the inner service with an instance of the [`RateLimit`] |
226 | | /// middleware. |
227 | | /// |
228 | | /// [`RateLimit`]: crate::limit::rate |
229 | | #[cfg(feature = "limit")] |
230 | 0 | pub fn rate_limit( |
231 | 0 | self, |
232 | 0 | num: u64, |
233 | 0 | per: std::time::Duration, |
234 | 0 | ) -> ServiceBuilder<Stack<crate::limit::RateLimitLayer, L>> { |
235 | 0 | self.layer(crate::limit::RateLimitLayer::new(num, per)) |
236 | 0 | } |
237 | | |
238 | | /// Retry failed requests according to the given [retry policy][policy]. |
239 | | /// |
240 | | /// `policy` determines which failed requests will be retried. It must |
241 | | /// implement the [`retry::Policy`][policy] trait. |
242 | | /// |
243 | | /// This wraps the inner service with an instance of the [`Retry`] |
244 | | /// middleware. |
245 | | /// |
246 | | /// [`Retry`]: crate::retry |
247 | | /// [policy]: crate::retry::Policy |
248 | | #[cfg(feature = "retry")] |
249 | | pub fn retry<P>(self, policy: P) -> ServiceBuilder<Stack<crate::retry::RetryLayer<P>, L>> { |
250 | | self.layer(crate::retry::RetryLayer::new(policy)) |
251 | | } |
252 | | |
253 | | /// Fail requests that take longer than `timeout`. |
254 | | /// |
255 | | /// If the next layer takes more than `timeout` to respond to a request, |
256 | | /// processing is terminated and an error is returned. |
257 | | /// |
258 | | /// This wraps the inner service with an instance of the [`timeout`] |
259 | | /// middleware. |
260 | | /// |
261 | | /// [`timeout`]: crate::timeout |
262 | | #[cfg(feature = "timeout")] |
263 | | pub fn timeout( |
264 | | self, |
265 | | timeout: std::time::Duration, |
266 | | ) -> ServiceBuilder<Stack<crate::timeout::TimeoutLayer, L>> { |
267 | | self.layer(crate::timeout::TimeoutLayer::new(timeout)) |
268 | | } |
269 | | |
270 | | /// Conditionally reject requests based on `predicate`. |
271 | | /// |
272 | | /// `predicate` must implement the [`Predicate`] trait. |
273 | | /// |
274 | | /// This wraps the inner service with an instance of the [`Filter`] |
275 | | /// middleware. |
276 | | /// |
277 | | /// [`Filter`]: crate::filter |
278 | | /// [`Predicate`]: crate::filter::Predicate |
279 | | #[cfg(feature = "filter")] |
280 | | pub fn filter<P>( |
281 | | self, |
282 | | predicate: P, |
283 | | ) -> ServiceBuilder<Stack<crate::filter::FilterLayer<P>, L>> { |
284 | | self.layer(crate::filter::FilterLayer::new(predicate)) |
285 | | } |
286 | | |
287 | | /// Conditionally reject requests based on an asynchronous `predicate`. |
288 | | /// |
289 | | /// `predicate` must implement the [`AsyncPredicate`] trait. |
290 | | /// |
291 | | /// This wraps the inner service with an instance of the [`AsyncFilter`] |
292 | | /// middleware. |
293 | | /// |
294 | | /// [`AsyncFilter`]: crate::filter::AsyncFilter |
295 | | /// [`AsyncPredicate`]: crate::filter::AsyncPredicate |
296 | | #[cfg(feature = "filter")] |
297 | | pub fn filter_async<P>( |
298 | | self, |
299 | | predicate: P, |
300 | | ) -> ServiceBuilder<Stack<crate::filter::AsyncFilterLayer<P>, L>> { |
301 | | self.layer(crate::filter::AsyncFilterLayer::new(predicate)) |
302 | | } |
303 | | |
304 | | /// Map one request type to another. |
305 | | /// |
306 | | /// This wraps the inner service with an instance of the [`MapRequest`] |
307 | | /// middleware. |
308 | | /// |
309 | | /// # Examples |
310 | | /// |
311 | | /// Changing the type of a request: |
312 | | /// |
313 | | /// ```rust |
314 | | /// use tower::ServiceBuilder; |
315 | | /// use tower::ServiceExt; |
316 | | /// |
317 | | /// # #[tokio::main] |
318 | | /// # async fn main() -> Result<(), ()> { |
319 | | /// // Suppose we have some `Service` whose request type is `String`: |
320 | | /// let string_svc = tower::service_fn(|request: String| async move { |
321 | | /// println!("request: {}", request); |
322 | | /// Ok(()) |
323 | | /// }); |
324 | | /// |
325 | | /// // ...but we want to call that service with a `usize`. What do we do? |
326 | | /// |
327 | | /// let usize_svc = ServiceBuilder::new() |
328 | | /// // Add a middleware that converts the request type to a `String`: |
329 | | /// .map_request(|request: usize| format!("{}", request)) |
330 | | /// // ...and wrap the string service with that middleware: |
331 | | /// .service(string_svc); |
332 | | /// |
333 | | /// // Now, we can call that service with a `usize`: |
334 | | /// usize_svc.oneshot(42).await?; |
335 | | /// # Ok(()) |
336 | | /// # } |
337 | | /// ``` |
338 | | /// |
339 | | /// Modifying the request value: |
340 | | /// |
341 | | /// ```rust |
342 | | /// use tower::ServiceBuilder; |
343 | | /// use tower::ServiceExt; |
344 | | /// |
345 | | /// # #[tokio::main] |
346 | | /// # async fn main() -> Result<(), ()> { |
347 | | /// // A service that takes a number and returns it: |
348 | | /// let svc = tower::service_fn(|request: usize| async move { |
349 | | /// Ok(request) |
350 | | /// }); |
351 | | /// |
352 | | /// let svc = ServiceBuilder::new() |
353 | | /// // Add a middleware that adds 1 to each request |
354 | | /// .map_request(|request: usize| request + 1) |
355 | | /// .service(svc); |
356 | | /// |
357 | | /// let response = svc.oneshot(1).await?; |
358 | | /// assert_eq!(response, 2); |
359 | | /// # Ok(()) |
360 | | /// # } |
361 | | /// ``` |
362 | | /// |
363 | | /// [`MapRequest`]: crate::util::MapRequest |
364 | | #[cfg(feature = "util")] |
365 | 0 | pub fn map_request<F, R1, R2>( |
366 | 0 | self, |
367 | 0 | f: F, |
368 | 0 | ) -> ServiceBuilder<Stack<crate::util::MapRequestLayer<F>, L>> |
369 | 0 | where |
370 | 0 | F: FnMut(R1) -> R2 + Clone, |
371 | | { |
372 | 0 | self.layer(crate::util::MapRequestLayer::new(f)) |
373 | 0 | } |
374 | | |
375 | | /// Map one response type to another. |
376 | | /// |
377 | | /// This wraps the inner service with an instance of the [`MapResponse`] |
378 | | /// middleware. |
379 | | /// |
380 | | /// See the documentation for the [`map_response` combinator] for details. |
381 | | /// |
382 | | /// [`MapResponse`]: crate::util::MapResponse |
383 | | /// [`map_response` combinator]: crate::util::ServiceExt::map_response |
384 | | #[cfg(feature = "util")] |
385 | 0 | pub fn map_response<F>( |
386 | 0 | self, |
387 | 0 | f: F, |
388 | 0 | ) -> ServiceBuilder<Stack<crate::util::MapResponseLayer<F>, L>> { |
389 | 0 | self.layer(crate::util::MapResponseLayer::new(f)) |
390 | 0 | } |
391 | | |
392 | | /// Map one error type to another. |
393 | | /// |
394 | | /// This wraps the inner service with an instance of the [`MapErr`] |
395 | | /// middleware. |
396 | | /// |
397 | | /// See the documentation for the [`map_err` combinator] for details. |
398 | | /// |
399 | | /// [`MapErr`]: crate::util::MapErr |
400 | | /// [`map_err` combinator]: crate::util::ServiceExt::map_err |
401 | | #[cfg(feature = "util")] |
402 | 0 | pub fn map_err<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::MapErrLayer<F>, L>> { |
403 | 0 | self.layer(crate::util::MapErrLayer::new(f)) |
404 | 0 | } |
405 | | |
406 | | /// Composes a function that transforms futures produced by the service. |
407 | | /// |
408 | | /// This wraps the inner service with an instance of the [`MapFutureLayer`] middleware. |
409 | | /// |
410 | | /// See the documentation for the [`map_future`] combinator for details. |
411 | | /// |
412 | | /// [`MapFutureLayer`]: crate::util::MapFutureLayer |
413 | | /// [`map_future`]: crate::util::ServiceExt::map_future |
414 | | #[cfg(feature = "util")] |
415 | 0 | pub fn map_future<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::MapFutureLayer<F>, L>> { |
416 | 0 | self.layer(crate::util::MapFutureLayer::new(f)) |
417 | 0 | } |
418 | | |
419 | | /// Apply an asynchronous function after the service, regardless of whether the future |
420 | | /// succeeds or fails. |
421 | | /// |
422 | | /// This wraps the inner service with an instance of the [`Then`] |
423 | | /// middleware. |
424 | | /// |
425 | | /// This is similar to the [`map_response`] and [`map_err`] functions, |
426 | | /// except that the *same* function is invoked when the service's future |
427 | | /// completes, whether it completes successfully or fails. This function |
428 | | /// takes the [`Result`] returned by the service's future, and returns a |
429 | | /// [`Result`]. |
430 | | /// |
431 | | /// See the documentation for the [`then` combinator] for details. |
432 | | /// |
433 | | /// [`Then`]: crate::util::Then |
434 | | /// [`then` combinator]: crate::util::ServiceExt::then |
435 | | /// [`map_response`]: ServiceBuilder::map_response |
436 | | /// [`map_err`]: ServiceBuilder::map_err |
437 | | #[cfg(feature = "util")] |
438 | 0 | pub fn then<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::ThenLayer<F>, L>> { |
439 | 0 | self.layer(crate::util::ThenLayer::new(f)) |
440 | 0 | } |
441 | | |
442 | | /// Executes a new future after this service's future resolves. This does |
443 | | /// not alter the behaviour of the [`poll_ready`] method. |
444 | | /// |
445 | | /// This method can be used to change the [`Response`] type of the service |
446 | | /// into a different type. You can use this method to chain along a computation once the |
447 | | /// service's response has been resolved. |
448 | | /// |
449 | | /// This wraps the inner service with an instance of the [`AndThen`] |
450 | | /// middleware. |
451 | | /// |
452 | | /// See the documentation for the [`and_then` combinator] for details. |
453 | | /// |
454 | | /// [`Response`]: crate::Service::Response |
455 | | /// [`poll_ready`]: crate::Service::poll_ready |
456 | | /// [`and_then` combinator]: crate::util::ServiceExt::and_then |
457 | | /// [`AndThen`]: crate::util::AndThen |
458 | | #[cfg(feature = "util")] |
459 | 0 | pub fn and_then<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::AndThenLayer<F>, L>> { |
460 | 0 | self.layer(crate::util::AndThenLayer::new(f)) |
461 | 0 | } |
462 | | |
463 | | /// Maps this service's result type (`Result<Self::Response, Self::Error>`) |
464 | | /// to a different value, regardless of whether the future succeeds or |
465 | | /// fails. |
466 | | /// |
467 | | /// This wraps the inner service with an instance of the [`MapResult`] |
468 | | /// middleware. |
469 | | /// |
470 | | /// See the documentation for the [`map_result` combinator] for details. |
471 | | /// |
472 | | /// [`map_result` combinator]: crate::util::ServiceExt::map_result |
473 | | /// [`MapResult`]: crate::util::MapResult |
474 | | #[cfg(feature = "util")] |
475 | 0 | pub fn map_result<F>(self, f: F) -> ServiceBuilder<Stack<crate::util::MapResultLayer<F>, L>> { |
476 | 0 | self.layer(crate::util::MapResultLayer::new(f)) |
477 | 0 | } |
478 | | |
479 | | /// Returns the underlying `Layer` implementation. |
480 | 0 | pub fn into_inner(self) -> L { |
481 | 0 | self.layer |
482 | 0 | } Unexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower::util::either::Either<tower::limit::rate::layer::RateLimitLayer, tower_layer::identity::Identity>, tower_layer::stack::Stack<tower::util::either::Either<tower::limit::concurrency::layer::ConcurrencyLimitLayer, tower_layer::identity::Identity>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#2}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<tonic::transport::channel::uds_connector::UdsConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>>>>::into_innerUnexecuted instantiation: <tower::builder::ServiceBuilder<tower_layer::stack::Stack<tower::util::either::Either<tower::limit::rate::layer::RateLimitLayer, tower_layer::identity::Identity>, tower_layer::stack::Stack<tower::util::either::Either<tower::limit::concurrency::layer::ConcurrencyLimitLayer, tower_layer::identity::Identity>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#2}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#1}>, tower_layer::stack::Stack<tower_layer::layer_fn::LayerFn<<tonic::transport::channel::service::connection::Connection>::new<tonic::transport::channel::service::connector::Connector<hyper_util::client::legacy::connect::http::HttpConnector>>::{closure#0}>, tower_layer::identity::Identity>>>>>>>::into_innerUnexecuted instantiation: <tower::builder::ServiceBuilder<_>>::into_inner |
483 | | |
484 | | /// Wrap the service `S` with the middleware provided by this |
485 | | /// [`ServiceBuilder`]'s [`Layer`]'s, returning a new [`Service`]. |
486 | | /// |
487 | | /// [`Layer`]: crate::Layer |
488 | | /// [`Service`]: crate::Service |
489 | 0 | pub fn service<S>(&self, service: S) -> L::Service |
490 | 0 | where |
491 | 0 | L: Layer<S>, |
492 | | { |
493 | 0 | self.layer.layer(service) |
494 | 0 | } |
495 | | |
496 | | /// Wrap the async function `F` with the middleware provided by this [`ServiceBuilder`]'s |
497 | | /// [`Layer`]s, returning a new [`Service`]. |
498 | | /// |
499 | | /// This is a convenience method which is equivalent to calling |
500 | | /// [`ServiceBuilder::service`] with a [`service_fn`], like this: |
501 | | /// |
502 | | /// ```rust |
503 | | /// # use tower::{ServiceBuilder, service_fn}; |
504 | | /// # async fn handler_fn(_: ()) -> Result<(), ()> { Ok(()) } |
505 | | /// # let _ = { |
506 | | /// ServiceBuilder::new() |
507 | | /// // ... |
508 | | /// .service(service_fn(handler_fn)) |
509 | | /// # }; |
510 | | /// ``` |
511 | | /// |
512 | | /// # Example |
513 | | /// |
514 | | /// ```rust |
515 | | /// use std::time::Duration; |
516 | | /// use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; |
517 | | /// |
518 | | /// # #[tokio::main] |
519 | | /// # async fn main() -> Result<(), BoxError> { |
520 | | /// async fn handle(request: &'static str) -> Result<&'static str, BoxError> { |
521 | | /// Ok(request) |
522 | | /// } |
523 | | /// |
524 | | /// let svc = ServiceBuilder::new() |
525 | | /// .buffer(1024) |
526 | | /// .timeout(Duration::from_secs(10)) |
527 | | /// .service_fn(handle); |
528 | | /// |
529 | | /// let response = svc.oneshot("foo").await?; |
530 | | /// |
531 | | /// assert_eq!(response, "foo"); |
532 | | /// # Ok(()) |
533 | | /// # } |
534 | | /// ``` |
535 | | /// |
536 | | /// [`Layer`]: crate::Layer |
537 | | /// [`Service`]: crate::Service |
538 | | /// [`service_fn`]: crate::service_fn |
539 | | #[cfg(feature = "util")] |
540 | 0 | pub fn service_fn<F>(self, f: F) -> L::Service |
541 | 0 | where |
542 | 0 | L: Layer<crate::util::ServiceFn<F>>, |
543 | | { |
544 | 0 | self.service(crate::util::service_fn(f)) |
545 | 0 | } |
546 | | |
547 | | /// Check that the builder implements `Clone`. |
548 | | /// |
549 | | /// This can be useful when debugging type errors in `ServiceBuilder`s with lots of layers. |
550 | | /// |
551 | | /// Doesn't actually change the builder but serves as a type check. |
552 | | /// |
553 | | /// # Example |
554 | | /// |
555 | | /// ```rust |
556 | | /// use tower::ServiceBuilder; |
557 | | /// |
558 | | /// let builder = ServiceBuilder::new() |
559 | | /// // Do something before processing the request |
560 | | /// .map_request(|request: String| { |
561 | | /// println!("got request!"); |
562 | | /// request |
563 | | /// }) |
564 | | /// // Ensure our `ServiceBuilder` can be cloned |
565 | | /// .check_clone() |
566 | | /// // Do something after processing the request |
567 | | /// .map_response(|response: String| { |
568 | | /// println!("got response!"); |
569 | | /// response |
570 | | /// }); |
571 | | /// ``` |
572 | | #[inline] |
573 | 0 | pub fn check_clone(self) -> Self |
574 | 0 | where |
575 | 0 | Self: Clone, |
576 | | { |
577 | 0 | self |
578 | 0 | } |
579 | | |
580 | | /// Check that the builder when given a service of type `S` produces a service that implements |
581 | | /// `Clone`. |
582 | | /// |
583 | | /// This can be useful when debugging type errors in `ServiceBuilder`s with lots of layers. |
584 | | /// |
585 | | /// Doesn't actually change the builder but serves as a type check. |
586 | | /// |
587 | | /// # Example |
588 | | /// |
589 | | /// ```rust |
590 | | /// use tower::ServiceBuilder; |
591 | | /// |
592 | | /// # #[derive(Clone)] |
593 | | /// # struct MyService; |
594 | | /// # |
595 | | /// let builder = ServiceBuilder::new() |
596 | | /// // Do something before processing the request |
597 | | /// .map_request(|request: String| { |
598 | | /// println!("got request!"); |
599 | | /// request |
600 | | /// }) |
601 | | /// // Ensure that the service produced when given a `MyService` implements |
602 | | /// .check_service_clone::<MyService>() |
603 | | /// // Do something after processing the request |
604 | | /// .map_response(|response: String| { |
605 | | /// println!("got response!"); |
606 | | /// response |
607 | | /// }); |
608 | | /// ``` |
609 | | #[inline] |
610 | 0 | pub fn check_service_clone<S>(self) -> Self |
611 | 0 | where |
612 | 0 | L: Layer<S>, |
613 | 0 | L::Service: Clone, |
614 | | { |
615 | 0 | self |
616 | 0 | } |
617 | | |
618 | | /// Check that the builder when given a service of type `S` produces a service with the given |
619 | | /// request, response, and error types. |
620 | | /// |
621 | | /// This can be useful when debugging type errors in `ServiceBuilder`s with lots of layers. |
622 | | /// |
623 | | /// Doesn't actually change the builder but serves as a type check. |
624 | | /// |
625 | | /// # Example |
626 | | /// |
627 | | /// ```rust |
628 | | /// use tower::ServiceBuilder; |
629 | | /// use std::task::{Poll, Context}; |
630 | | /// use tower::{Service, ServiceExt}; |
631 | | /// |
632 | | /// // An example service |
633 | | /// struct MyService; |
634 | | /// |
635 | | /// impl Service<Request> for MyService { |
636 | | /// type Response = Response; |
637 | | /// type Error = Error; |
638 | | /// type Future = futures_util::future::Ready<Result<Response, Error>>; |
639 | | /// |
640 | | /// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { |
641 | | /// // ... |
642 | | /// # todo!() |
643 | | /// } |
644 | | /// |
645 | | /// fn call(&mut self, request: Request) -> Self::Future { |
646 | | /// // ... |
647 | | /// # todo!() |
648 | | /// } |
649 | | /// } |
650 | | /// |
651 | | /// struct Request; |
652 | | /// struct Response; |
653 | | /// struct Error; |
654 | | /// |
655 | | /// struct WrappedResponse(Response); |
656 | | /// |
657 | | /// let builder = ServiceBuilder::new() |
658 | | /// // At this point in the builder if given a `MyService` it produces a service that |
659 | | /// // accepts `Request`s, produces `Response`s, and fails with `Error`s |
660 | | /// .check_service::<MyService, Request, Response, Error>() |
661 | | /// // Wrap responses in `WrappedResponse` |
662 | | /// .map_response(|response: Response| WrappedResponse(response)) |
663 | | /// // Now the response type will be `WrappedResponse` |
664 | | /// .check_service::<MyService, _, WrappedResponse, _>(); |
665 | | /// ``` |
666 | | #[inline] |
667 | 0 | pub fn check_service<S, T, U, E>(self) -> Self |
668 | 0 | where |
669 | 0 | L: Layer<S>, |
670 | 0 | L::Service: Service<T, Response = U, Error = E>, |
671 | | { |
672 | 0 | self |
673 | 0 | } |
674 | | |
675 | | /// This wraps the inner service with the [`Layer`] returned by [`BoxService::layer()`]. |
676 | | /// |
677 | | /// See that method for more details. |
678 | | /// |
679 | | /// # Example |
680 | | /// |
681 | | /// ``` |
682 | | /// use tower::{Service, ServiceBuilder, BoxError, util::BoxService}; |
683 | | /// use std::time::Duration; |
684 | | /// # |
685 | | /// # struct Request; |
686 | | /// # struct Response; |
687 | | /// # impl Response { |
688 | | /// # fn new() -> Self { Self } |
689 | | /// # } |
690 | | /// |
691 | | /// let service: BoxService<Request, Response, BoxError> = ServiceBuilder::new() |
692 | | /// .boxed() |
693 | | /// .load_shed() |
694 | | /// .concurrency_limit(64) |
695 | | /// .timeout(Duration::from_secs(10)) |
696 | | /// .service_fn(|req: Request| async { |
697 | | /// Ok::<_, BoxError>(Response::new()) |
698 | | /// }); |
699 | | /// # let service = assert_service(service); |
700 | | /// # fn assert_service<S, R>(svc: S) -> S |
701 | | /// # where S: Service<R> { svc } |
702 | | /// ``` |
703 | | /// |
704 | | /// [`BoxService::layer()`]: crate::util::BoxService::layer() |
705 | | #[cfg(feature = "util")] |
706 | 0 | pub fn boxed<S, R>( |
707 | 0 | self, |
708 | 0 | ) -> ServiceBuilder< |
709 | 0 | Stack< |
710 | 0 | tower_layer::LayerFn< |
711 | 0 | fn( |
712 | 0 | L::Service, |
713 | 0 | ) -> crate::util::BoxService< |
714 | 0 | R, |
715 | 0 | <L::Service as Service<R>>::Response, |
716 | 0 | <L::Service as Service<R>>::Error, |
717 | 0 | >, |
718 | 0 | >, |
719 | 0 | L, |
720 | 0 | >, |
721 | 0 | > |
722 | 0 | where |
723 | 0 | L: Layer<S>, |
724 | 0 | L::Service: Service<R> + Send + 'static, |
725 | 0 | <L::Service as Service<R>>::Future: Send + 'static, |
726 | | { |
727 | 0 | self.layer(crate::util::BoxService::layer()) |
728 | 0 | } |
729 | | |
730 | | /// This wraps the inner service with the [`Layer`] returned by [`BoxCloneService::layer()`]. |
731 | | /// |
732 | | /// This is similar to the [`boxed`] method, but it requires that `Self` implement |
733 | | /// [`Clone`], and the returned boxed service implements [`Clone`]. |
734 | | /// |
735 | | /// See [`BoxCloneService`] for more details. |
736 | | /// |
737 | | /// # Example |
738 | | /// |
739 | | /// ``` |
740 | | /// use tower::{Service, ServiceBuilder, BoxError, util::BoxCloneService}; |
741 | | /// use std::time::Duration; |
742 | | /// # |
743 | | /// # struct Request; |
744 | | /// # struct Response; |
745 | | /// # impl Response { |
746 | | /// # fn new() -> Self { Self } |
747 | | /// # } |
748 | | /// |
749 | | /// let service: BoxCloneService<Request, Response, BoxError> = ServiceBuilder::new() |
750 | | /// .boxed_clone() |
751 | | /// .load_shed() |
752 | | /// .concurrency_limit(64) |
753 | | /// .timeout(Duration::from_secs(10)) |
754 | | /// .service_fn(|req: Request| async { |
755 | | /// Ok::<_, BoxError>(Response::new()) |
756 | | /// }); |
757 | | /// # let service = assert_service(service); |
758 | | /// |
759 | | /// // The boxed service can still be cloned. |
760 | | /// service.clone(); |
761 | | /// # fn assert_service<S, R>(svc: S) -> S |
762 | | /// # where S: Service<R> { svc } |
763 | | /// ``` |
764 | | /// |
765 | | /// [`BoxCloneService::layer()`]: crate::util::BoxCloneService::layer() |
766 | | /// [`BoxCloneService`]: crate::util::BoxCloneService |
767 | | /// [`boxed`]: Self::boxed |
768 | | #[cfg(feature = "util")] |
769 | 0 | pub fn boxed_clone<S, R>( |
770 | 0 | self, |
771 | 0 | ) -> ServiceBuilder< |
772 | 0 | Stack< |
773 | 0 | tower_layer::LayerFn< |
774 | 0 | fn( |
775 | 0 | L::Service, |
776 | 0 | ) -> crate::util::BoxCloneService< |
777 | 0 | R, |
778 | 0 | <L::Service as Service<R>>::Response, |
779 | 0 | <L::Service as Service<R>>::Error, |
780 | 0 | >, |
781 | 0 | >, |
782 | 0 | L, |
783 | 0 | >, |
784 | 0 | > |
785 | 0 | where |
786 | 0 | L: Layer<S>, |
787 | 0 | L::Service: Service<R> + Clone + Send + 'static, |
788 | 0 | <L::Service as Service<R>>::Future: Send + 'static, |
789 | | { |
790 | 0 | self.layer(crate::util::BoxCloneService::layer()) |
791 | 0 | } |
792 | | } |
793 | | |
794 | | impl<L: fmt::Debug> fmt::Debug for ServiceBuilder<L> { |
795 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
796 | 0 | f.debug_tuple("ServiceBuilder").field(&self.layer).finish() |
797 | 0 | } |
798 | | } |
799 | | |
800 | | impl<S, L> Layer<S> for ServiceBuilder<L> |
801 | | where |
802 | | L: Layer<S>, |
803 | | { |
804 | | type Service = L::Service; |
805 | | |
806 | 0 | fn layer(&self, inner: S) -> Self::Service { |
807 | 0 | self.layer.layer(inner) |
808 | 0 | } |
809 | | } |