summaryrefslogtreecommitdiff
path: root/vendor/tower-layer/src/layer_fn.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tower-layer/src/layer_fn.rs')
-rw-r--r--vendor/tower-layer/src/layer_fn.rs114
1 files changed, 114 insertions, 0 deletions
diff --git a/vendor/tower-layer/src/layer_fn.rs b/vendor/tower-layer/src/layer_fn.rs
new file mode 100644
index 00000000..06f6e0e3
--- /dev/null
+++ b/vendor/tower-layer/src/layer_fn.rs
@@ -0,0 +1,114 @@
+use super::Layer;
+use std::fmt;
+
+/// Returns a new [`LayerFn`] that implements [`Layer`] by calling the
+/// given function.
+///
+/// The [`Layer::layer`] method takes a type implementing [`Service`] and
+/// returns a different type implementing [`Service`]. In many cases, this can
+/// be implemented by a function or a closure. The [`LayerFn`] helper allows
+/// writing simple [`Layer`] implementations without needing the boilerplate of
+/// a new struct implementing [`Layer`].
+///
+/// # Example
+/// ```rust
+/// # use tower::Service;
+/// # use std::task::{Poll, Context};
+/// # use tower_layer::{Layer, layer_fn};
+/// # use std::fmt;
+/// # use std::convert::Infallible;
+/// #
+/// // A middleware that logs requests before forwarding them to another service
+/// pub struct LogService<S> {
+/// target: &'static str,
+/// service: S,
+/// }
+///
+/// impl<S, Request> Service<Request> for LogService<S>
+/// where
+/// S: Service<Request>,
+/// Request: fmt::Debug,
+/// {
+/// type Response = S::Response;
+/// type Error = S::Error;
+/// type Future = S::Future;
+///
+/// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+/// self.service.poll_ready(cx)
+/// }
+///
+/// fn call(&mut self, request: Request) -> Self::Future {
+/// // Log the request
+/// println!("request = {:?}, target = {:?}", request, self.target);
+///
+/// self.service.call(request)
+/// }
+/// }
+///
+/// // A `Layer` that wraps services in `LogService`
+/// let log_layer = layer_fn(|service| {
+/// LogService {
+/// service,
+/// target: "tower-docs",
+/// }
+/// });
+///
+/// // An example service. This one uppercases strings
+/// let uppercase_service = tower::service_fn(|request: String| async move {
+/// Ok::<_, Infallible>(request.to_uppercase())
+/// });
+///
+/// // Wrap our service in a `LogService` so requests are logged.
+/// let wrapped_service = log_layer.layer(uppercase_service);
+/// ```
+///
+/// [`Service`]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html
+/// [`Layer::layer`]: crate::Layer::layer
+pub fn layer_fn<T>(f: T) -> LayerFn<T> {
+ LayerFn { f }
+}
+
+/// A `Layer` implemented by a closure. See the docs for [`layer_fn`] for more details.
+#[derive(Clone, Copy)]
+pub struct LayerFn<F> {
+ f: F,
+}
+
+impl<F, S, Out> Layer<S> for LayerFn<F>
+where
+ F: Fn(S) -> Out,
+{
+ type Service = Out;
+
+ fn layer(&self, inner: S) -> Self::Service {
+ (self.f)(inner)
+ }
+}
+
+impl<F> fmt::Debug for LayerFn<F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("LayerFn")
+ .field("f", &format_args!("{}", std::any::type_name::<F>()))
+ .finish()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[allow(dead_code)]
+ #[test]
+ fn layer_fn_has_useful_debug_impl() {
+ struct WrappedService<S> {
+ inner: S,
+ }
+ let layer = layer_fn(|svc| WrappedService { inner: svc });
+ let _svc = layer.layer("foo");
+
+ assert_eq!(
+ "LayerFn { f: tower_layer::layer_fn::tests::layer_fn_has_useful_debug_impl::{{closure}} }".to_string(),
+ format!("{:?}", layer),
+ );
+ }
+}