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 — 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}