micro_web/router/
filter.rs1use std::any::type_name_of_val;
32use std::fmt::{Debug, Formatter};
33use crate::RequestContext;
34use http::{HeaderName, HeaderValue, Method};
35
36pub trait Filter: Send + Sync + Debug {
46 fn matches(&self, req: &RequestContext) -> bool;
50}
51
52struct FnFilter<F: Fn(&RequestContext) -> bool>(F);
54
55impl<F: Fn(&RequestContext) -> bool> Debug for FnFilter<F> {
56 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
57 f.debug_struct("FnFilter")
58 .field("fn", &type_name_of_val(&self.0))
59 .finish()
60 }
61}
62
63impl<F: Fn(&RequestContext) -> bool + Send + Sync> Filter for FnFilter<F> {
64 fn matches(&self, req: &RequestContext) -> bool {
65 self.0(req)
66 }
67}
68
69pub fn filter_fn<F>(f: F) -> impl Filter
82where
83 F: Fn(&RequestContext) -> bool + Send + Sync,
84{
85 FnFilter(f)
86}
87
88#[inline(always)]
90pub const fn true_filter() -> TrueFilter {
91 TrueFilter
92}
93
94#[inline(always)]
96pub const fn false_filter() -> FalseFilter {
97 FalseFilter
98}
99
100#[derive(Debug)]
102pub struct TrueFilter;
103impl Filter for TrueFilter {
104 #[inline(always)]
105 fn matches(&self, _req: &RequestContext) -> bool {
106 true
107 }
108}
109
110#[derive(Debug)]
112pub struct FalseFilter;
113impl Filter for FalseFilter {
114 #[inline(always)]
115 fn matches(&self, _req: &RequestContext) -> bool {
116 false
117 }
118}
119
120pub fn any_filter() -> AnyFilter {
122 AnyFilter::new()
123}
124
125#[derive(Debug)]
130pub struct AnyFilter {
131 filters: Vec<Box<dyn Filter>>,
132}
133
134impl AnyFilter {
135 fn new() -> Self {
136 Self { filters: vec![] }
137 }
138
139 pub fn or<F: Filter + 'static>(&mut self, filter: F) -> &mut Self {
141 self.filters.push(Box::new(filter));
142 self
143 }
144}
145
146impl Filter for AnyFilter {
147 fn matches(&self, req: &RequestContext) -> bool {
148 if self.filters.is_empty() {
149 return true;
150 }
151
152 for filter in &self.filters {
153 if filter.matches(req) {
154 return true;
155 }
156 }
157
158 false
159 }
160}
161
162pub fn all_filter() -> AllFilter {
164 AllFilter::new()
165}
166
167#[derive(Debug)]
172pub struct AllFilter {
173 filters: Vec<Box<dyn Filter>>,
174}
175
176impl AllFilter {
177 fn new() -> Self {
178 Self { filters: vec![] }
179 }
180
181 pub fn and<F: Filter + 'static>(&mut self, filter: F) -> &mut Self {
183 self.filters.push(Box::new(filter));
184 self
185 }
186}
187
188impl Filter for AllFilter {
189 fn matches(&self, req: &RequestContext) -> bool {
190 if self.filters.is_empty() {
191 return true;
192 }
193
194 for filter in &self.filters {
195 if !filter.matches(req) {
196 return false;
197 }
198 }
199
200 true
201 }
202}
203
204#[derive(Debug)]
206pub struct MethodFilter(Method);
207
208impl Filter for MethodFilter {
209 fn matches(&self, req: &RequestContext) -> bool {
210 self.0.eq(req.method())
211 }
212}
213
214macro_rules! method_filter {
215 ($method:ident, $upper_case_method:ident) => {
216 #[doc = concat!("Creates a filter that matches HTTP ", stringify!($upper_case_method), " requests.")]
217 #[inline]
218 pub fn $method() -> MethodFilter {
219 MethodFilter(Method::$upper_case_method)
220 }
221 };
222}
223
224method_filter!(get_method, GET);
225method_filter!(post_method, POST);
226method_filter!(put_method, PUT);
227method_filter!(delete_method, DELETE);
228method_filter!(head_method, HEAD);
229method_filter!(options_method, OPTIONS);
230method_filter!(connect_method, CONNECT);
231method_filter!(patch_method, PATCH);
232method_filter!(trace_method, TRACE);
233
234#[inline]
236pub fn header<K, V>(header_name: K, header_value: V) -> HeaderFilter
237where
238 HeaderName: TryFrom<K>,
239 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
240 HeaderValue: TryFrom<V>,
241 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
242{
243 let name = <HeaderName as TryFrom<K>>::try_from(header_name).map_err(Into::into).unwrap();
245 let value = <HeaderValue as TryFrom<V>>::try_from(header_value).map_err(Into::into).unwrap();
246 HeaderFilter(name, value)
247}
248
249#[derive(Debug)]
251pub struct HeaderFilter(HeaderName, HeaderValue);
252
253impl Filter for HeaderFilter {
254 fn matches(&self, req: &RequestContext) -> bool {
255 let value_option = req.headers().get(&self.0);
256 value_option.map(|value| self.1.eq(value)).unwrap_or(false)
257 }
258}