micro_web/router/
filter.rs1use crate::RequestContext;
32use http::{HeaderName, HeaderValue, Method};
33
34pub trait Filter: Send + Sync {
44 fn matches(&self, req: &RequestContext) -> bool;
48}
49
50struct FnFilter<F: Fn(&RequestContext) -> bool>(F);
52
53impl<F: Fn(&RequestContext) -> bool + Send + Sync> Filter for FnFilter<F> {
54 fn matches(&self, req: &RequestContext) -> bool {
55 self.0(req)
56 }
57}
58
59pub fn filter_fn<F>(f: F) -> impl Filter
72where
73 F: Fn(&RequestContext) -> bool + Send + Sync,
74{
75 FnFilter(f)
76}
77
78#[inline(always)]
80pub const fn true_filter() -> TrueFilter {
81 TrueFilter
82}
83
84#[inline(always)]
86pub const fn false_filter() -> FalseFilter {
87 FalseFilter
88}
89
90pub struct TrueFilter;
92impl Filter for TrueFilter {
93 #[inline(always)]
94 fn matches(&self, _req: &RequestContext) -> bool {
95 true
96 }
97}
98
99pub struct FalseFilter;
101impl Filter for FalseFilter {
102 #[inline(always)]
103 fn matches(&self, _req: &RequestContext) -> bool {
104 false
105 }
106}
107
108pub fn any_filter() -> AnyFilter {
110 AnyFilter::new()
111}
112
113pub struct AnyFilter {
118 filters: Vec<Box<dyn Filter>>,
119}
120
121impl AnyFilter {
122 fn new() -> Self {
123 Self { filters: vec![] }
124 }
125
126 pub fn or<F: Filter + 'static>(&mut self, filter: F) -> &mut Self {
128 self.filters.push(Box::new(filter));
129 self
130 }
131}
132
133impl Filter for AnyFilter {
134 fn matches(&self, req: &RequestContext) -> bool {
135 if self.filters.is_empty() {
136 return true;
137 }
138
139 for filter in &self.filters {
140 if filter.matches(req) {
141 return true;
142 }
143 }
144
145 false
146 }
147}
148
149pub fn all_filter() -> AllFilter {
151 AllFilter::new()
152}
153
154pub struct AllFilter {
159 filters: Vec<Box<dyn Filter>>,
160}
161
162impl AllFilter {
163 fn new() -> Self {
164 Self { filters: vec![] }
165 }
166
167 pub fn and<F: Filter + 'static>(&mut self, filter: F) -> &mut Self {
169 self.filters.push(Box::new(filter));
170 self
171 }
172}
173
174impl Filter for AllFilter {
175 fn matches(&self, req: &RequestContext) -> bool {
176 if self.filters.is_empty() {
177 return true;
178 }
179
180 for filter in &self.filters {
181 if !filter.matches(req) {
182 return false;
183 }
184 }
185
186 true
187 }
188}
189
190pub struct MethodFilter(Method);
192
193impl Filter for MethodFilter {
194 fn matches(&self, req: &RequestContext) -> bool {
195 self.0.eq(req.method())
196 }
197}
198
199macro_rules! method_filter {
200 ($method:ident, $upper_case_method:ident) => {
201 #[doc = concat!("Creates a filter that matches HTTP ", stringify!($upper_case_method), " requests.")]
202 #[inline]
203 pub fn $method() -> MethodFilter {
204 MethodFilter(Method::$upper_case_method)
205 }
206 };
207}
208
209method_filter!(get_method, GET);
210method_filter!(post_method, POST);
211method_filter!(put_method, PUT);
212method_filter!(delete_method, DELETE);
213method_filter!(head_method, HEAD);
214method_filter!(options_method, OPTIONS);
215method_filter!(connect_method, CONNECT);
216method_filter!(patch_method, PATCH);
217method_filter!(trace_method, TRACE);
218
219#[inline]
221pub fn header<K, V>(header_name: K, header_value: V) -> HeaderFilter
222where
223 HeaderName: TryFrom<K>,
224 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
225 HeaderValue: TryFrom<V>,
226 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
227{
228 let name = <HeaderName as TryFrom<K>>::try_from(header_name).map_err(Into::into).unwrap();
230 let value = <HeaderValue as TryFrom<V>>::try_from(header_value).map_err(Into::into).unwrap();
231 HeaderFilter(name, value)
232}
233
234pub struct HeaderFilter(HeaderName, HeaderValue);
236
237impl Filter for HeaderFilter {
238 fn matches(&self, req: &RequestContext) -> bool {
239 let value_option = req.headers().get(&self.0);
240 value_option.map(|value| self.1.eq(value)).unwrap_or(false)
241 }
242}