tower_async_layer/
layer_fn.rs

1use super::Layer;
2use std::fmt;
3
4/// Returns a new [`LayerFn`] that implements [`Layer`] by calling the
5/// given function.
6///
7/// The [`Layer::layer`] method takes a type implementing [`Service`] and
8/// returns a different type implementing [`Service`]. In many cases, this can
9/// be implemented by a function or a closure. The [`LayerFn`] helper allows
10/// writing simple [`Layer`] implementations without needing the boilerplate of
11/// a new struct implementing [`Layer`].
12///
13/// # Example
14/// ```rust
15/// # use tower_async::Service;
16/// # use std::task::{Poll, Context};
17/// # use tower_async_layer::{Layer, layer_fn};
18/// # use std::fmt;
19/// # use std::convert::Infallible;
20/// #
21/// // A middleware that logs requests before forwarding them to another service
22/// pub struct LogService<S> {
23///     target: &'static str,
24///     service: S,
25/// }
26///
27/// impl<S, Request> Service<Request> for LogService<S>
28/// where
29///     S: Service<Request>,
30///     Request: fmt::Debug,
31/// {
32///     type Response = S::Response;
33///     type Error = S::Error;
34///
35///     async fn call(&self, request: Request) -> Result<Self::Response, Self::Error> {
36///         // Log the request
37///         println!("request = {:?}, target = {:?}", request, self.target);
38///
39///         self.service.call(request).await
40///     }
41/// }
42///
43/// // A `Layer` that wraps services in `LogService`
44/// let log_layer = layer_fn(|service| {
45///     LogService {
46///         service,
47///         target: "tower-docs",
48///     }
49/// });
50///
51/// // An example service. This one uppercases strings
52/// let uppercase_service = tower_async::service_fn(|request: String| async move {
53///     Ok::<_, Infallible>(request.to_uppercase())
54/// });
55///
56/// // Wrap our service in a `LogService` so requests are logged.
57/// let wrapped_service = log_layer.layer(uppercase_service);
58/// ```
59///
60/// [`Service`]: https://docs.rs/tower-async-service/latest/tower_async_service/trait.Service.html
61/// [`Layer::layer`]: crate::Layer::layer
62pub fn layer_fn<T>(f: T) -> LayerFn<T> {
63    LayerFn { f }
64}
65
66/// A `Layer` implemented by a closure. See the docs for [`layer_fn`] for more details.
67#[derive(Clone, Copy)]
68pub struct LayerFn<F> {
69    f: F,
70}
71
72impl<F, S, Out> Layer<S> for LayerFn<F>
73where
74    F: Fn(S) -> Out,
75{
76    type Service = Out;
77
78    fn layer(&self, inner: S) -> Self::Service {
79        (self.f)(inner)
80    }
81}
82
83impl<F> fmt::Debug for LayerFn<F> {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        f.debug_struct("LayerFn")
86            .field("f", &format_args!("{}", std::any::type_name::<F>()))
87            .finish()
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[allow(dead_code)]
96    #[test]
97    fn layer_fn_has_useful_debug_impl() {
98        struct WrappedService<S> {
99            inner: S,
100        }
101        let layer = layer_fn(|svc| WrappedService { inner: svc });
102        let _svc = layer.layer("foo");
103
104        assert_eq!(
105            "LayerFn { f: tower_async_layer::layer_fn::tests::layer_fn_has_useful_debug_impl::{{closure}} }".to_string(),
106            format!("{:?}", layer),
107        );
108    }
109}