tower_async/filter/
mod.rs

1//! Conditionally dispatch requests to the inner service based on the result of
2//! a predicate.
3//!
4//! A predicate takes some request type and returns a `Result<Request, Error>`.
5//! If the predicate returns [`Ok`], the inner service is called with the request
6//! returned by the predicate &mdash; which may be the original request or a
7//! modified one. If the predicate returns [`Err`], the request is rejected and
8//! the inner service is not called.
9//!
10//! Predicates may either be synchronous (simple functions from a `Request` to
11//! a [`Result`]) or asynchronous (functions returning [`Future`]s). Separate
12//! traits, [`Predicate`] and [`AsyncPredicate`], represent these two types of
13//! predicate. Note that when it is not necessary to await some other
14//! asynchronous operation in the predicate, the synchronous predicate should be
15//! preferred, as it introduces less overhead.
16//!
17//! The predicate traits are implemented for closures and function pointers.
18//! However, users may also implement them for other types, such as when the
19//! predicate requires some state carried between requests. For example,
20//! [`Predicate`] could be implemented for a type that rejects a fixed set of
21//! requests by checking if they are contained by a a [`HashSet`] or other
22//! collection.
23//!
24//! [`Future`]: std::future::Future
25//! [`HashSet`]: std::collections::HashSet
26mod layer;
27mod predicate;
28
29pub use self::{
30    layer::{AsyncFilterLayer, FilterLayer},
31    predicate::{AsyncPredicate, Predicate},
32};
33
34use crate::BoxError;
35use futures_util::TryFutureExt;
36use tower_async_service::Service;
37
38/// Conditionally dispatch requests to the inner service based on a [predicate].
39///
40/// [predicate]: Predicate
41#[derive(Clone, Debug)]
42pub struct Filter<T, U> {
43    inner: T,
44    predicate: U,
45}
46
47/// Conditionally dispatch requests to the inner service based on an
48/// [asynchronous predicate].
49///
50/// [asynchronous predicate]: AsyncPredicate
51#[derive(Clone, Debug)]
52pub struct AsyncFilter<T, U> {
53    inner: T,
54    predicate: U,
55}
56
57// ==== impl Filter ====
58
59impl<T, U> Filter<T, U> {
60    /// Returns a new [`Filter`] service wrapping `inner`.
61    pub fn new(inner: T, predicate: U) -> Self {
62        Self { inner, predicate }
63    }
64
65    /// Returns a new [`Layer`] that wraps services with a [`Filter`] service
66    /// with the given [`Predicate`].
67    ///
68    /// [`Layer`]: crate::Layer
69    pub fn layer(predicate: U) -> FilterLayer<U> {
70        FilterLayer::new(predicate)
71    }
72
73    /// Check a `Request` value against this filter's predicate.
74    pub fn check<R>(&self, request: R) -> Result<U::Request, BoxError>
75    where
76        U: Predicate<R>,
77    {
78        self.predicate.check(request)
79    }
80
81    /// Get a reference to the inner service
82    pub fn get_ref(&self) -> &T {
83        &self.inner
84    }
85
86    /// Consume `self`, returning the inner service
87    pub fn into_inner(self) -> T {
88        self.inner
89    }
90}
91
92impl<T, U, Request> Service<Request> for Filter<T, U>
93where
94    U: Predicate<Request>,
95    T: Service<U::Request>,
96    T::Error: Into<BoxError>,
97{
98    type Response = T::Response;
99    type Error = BoxError;
100
101    async fn call(&self, request: Request) -> Result<Self::Response, Self::Error> {
102        match self.predicate.check(request) {
103            Ok(request) => self.inner.call(request).err_into().await,
104            Err(e) => Err(e),
105        }
106    }
107}
108
109// ==== impl AsyncFilter ====
110
111impl<T, U> AsyncFilter<T, U> {
112    /// Returns a new [`AsyncFilter`] service wrapping `inner`.
113    pub fn new(inner: T, predicate: U) -> Self {
114        Self { inner, predicate }
115    }
116
117    /// Returns a new [`Layer`] that wraps services with an [`AsyncFilter`]
118    /// service with the given [`AsyncPredicate`].
119    ///
120    /// [`Layer`]: crate::Layer
121    pub fn layer(predicate: U) -> FilterLayer<U> {
122        FilterLayer::new(predicate)
123    }
124
125    /// Check a `Request` value against this filter's predicate.
126    pub async fn check<R>(&self, request: R) -> Result<U::Request, BoxError>
127    where
128        U: AsyncPredicate<R>,
129    {
130        self.predicate.check(request).await
131    }
132
133    /// Get a reference to the inner service
134    pub fn get_ref(&self) -> &T {
135        &self.inner
136    }
137
138    /// Consume `self`, returning the inner service
139    pub fn into_inner(self) -> T {
140        self.inner
141    }
142}
143
144impl<T, U, Request> Service<Request> for AsyncFilter<T, U>
145where
146    U: AsyncPredicate<Request>,
147    T: Service<U::Request> + Clone,
148    T::Error: Into<BoxError>,
149{
150    type Response = T::Response;
151    type Error = BoxError;
152
153    async fn call(&self, request: Request) -> Result<Self::Response, Self::Error> {
154        match self.predicate.check(request).await {
155            Ok(request) => self.inner.call(request).err_into().await,
156            Err(e) => Err(e),
157        }
158    }
159}