diff options
Diffstat (limited to 'vendor/tower-layer/src/layer_fn.rs')
| -rw-r--r-- | vendor/tower-layer/src/layer_fn.rs | 114 |
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), + ); + } +} |
