filters/failable/filter.rs
1//
2// This Source Code Form is subject to the terms of the Mozilla Public
3// License, v. 2.0. If a copy of the MPL was not distributed with this
4// file, You can obtain one at http://mozilla.org/MPL/2.0/.
5//
6
7use std::borrow::Borrow;
8
9pub use failable::ops::and::FailableAnd;
10pub use failable::ops::bool::FailableBool;
11pub use failable::ops::not::FailableNot;
12pub use failable::ops::xor::FailableXOr;
13pub use failable::ops::or::FailableOr;
14pub use failable::ops::map::{FailableMapInput, FailableMapErr};
15
16/// Trait for converting something into a Filter
17pub trait IntoFailableFilter<N> {
18 type IntoFilt: FailableFilter<N>;
19
20 fn into_failable_filter(self) -> Self::IntoFilt;
21}
22
23/// All Filters can be turned into Filters
24impl<N, I: FailableFilter<N>> IntoFailableFilter<N> for I {
25 type IntoFilt = I;
26
27 fn into_failable_filter(self) -> Self::IntoFilt {
28 self
29 }
30}
31
32pub trait FailableFilter<N> {
33 type Error: Sized;
34
35 /// The function which is used to filter something
36 fn filter(&self, &N) -> Result<bool, Self::Error>;
37
38 /// Helper to invert a filter.
39 ///
40 /// ```
41 /// # #[derive(Debug)]
42 /// # struct ErrorStub { }
43 /// #
44 /// use filters::failable::filter::FailableFilter;
45 ///
46 /// let f = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a == 1) }).not();
47 ///
48 /// assert!(f.filter(&2).unwrap());
49 /// ```
50 fn not(self) -> FailableNot<Self>
51 where Self: Sized
52 {
53 FailableNot::new(self)
54 }
55
56 /// Helper to connect two filters via logical OR
57 ///
58 /// ```
59 /// # #[derive(Debug)]
60 /// # struct ErrorStub { }
61 /// #
62 /// use filters::failable::filter::FailableFilter;
63 ///
64 /// let a = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a == 1) });
65 /// let b = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a == 2) });
66 /// let c = a.or(b);
67 ///
68 /// assert!(c.filter(&1).unwrap());
69 /// assert!(c.filter(&2).unwrap());
70 /// assert!(!c.filter(&7).unwrap());
71 /// ```
72 fn or<F>(self, other: F) -> FailableOr<Self, F::IntoFilt>
73 where Self: Sized,
74 F: IntoFailableFilter<N> + Sized
75 {
76 FailableOr::new(self, other.into_failable_filter())
77 }
78
79 /// Helper to connect two filters via logical OR and NOT
80 ///
81 /// ```
82 /// # #[derive(Debug)]
83 /// # struct ErrorStub { }
84 /// #
85 /// use filters::failable::filter::FailableFilter;
86 ///
87 /// let a = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a == 1) });
88 /// let b = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a == 2) });
89 /// let c = a.or_not(b);
90 ///
91 /// assert!(c.filter(&1).unwrap());
92 /// assert!(!c.filter(&2).unwrap());
93 /// assert!(c.filter(&7).unwrap());
94 /// ```
95 fn or_not<F>(self, other: F) -> FailableOr<Self, FailableNot<F::IntoFilt>>
96 where Self: Sized,
97 F: IntoFailableFilter<N> + Sized,
98 {
99 self.or(FailableNot::new(other.into_failable_filter()))
100 }
101
102 /// Helper to connect three filters via logical OR
103 ///
104 /// ```
105 /// # #[derive(Debug)]
106 /// # struct ErrorStub { }
107 /// #
108 /// use filters::failable::filter::FailableFilter;
109 ///
110 /// let a = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a == 1) });
111 /// let b = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a == 2) });
112 /// let c = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a == 3) });
113 /// let d = a.or3(b, c);
114 ///
115 /// assert!(d.filter(&1).unwrap());
116 /// assert!(d.filter(&2).unwrap());
117 /// assert!(d.filter(&3).unwrap());
118 /// assert!(!d.filter(&4).unwrap());
119 /// ```
120 fn or3<F, F2>(self, other: F, other2: F2) -> FailableOr<Self, FailableOr<F::IntoFilt, F2::IntoFilt>>
121 where Self: Sized,
122 F: IntoFailableFilter<N> + Sized,
123 F2: IntoFailableFilter<N> + Sized
124 {
125 FailableOr::new(self, FailableOr::new(other.into_failable_filter(), other2.into_failable_filter()))
126 }
127
128 /// Helper to connect two filters via logical NOR
129 ///
130 /// ```
131 /// # #[derive(Debug)]
132 /// # struct ErrorStub { }
133 /// #
134 /// use filters::failable::filter::FailableFilter;
135 ///
136 /// let a = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a == 1) });
137 /// let b = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a == 2) });
138 /// let c = a.nor(b); /* !(a == 1 || a == 2) */
139 ///
140 /// assert!(!c.filter(&1).unwrap());
141 /// assert!(!c.filter(&2).unwrap());
142 /// assert!(c.filter(&3).unwrap());
143 /// assert!(c.filter(&4).unwrap());
144 /// ```
145 fn nor<F>(self, other: F) -> FailableNot<FailableOr<Self, F>>
146 where Self: Sized,
147 {
148 FailableNot::new(FailableOr::new(self, other))
149 }
150
151 /// Helper to connect two filters via logical XOR
152 ///
153 /// ```
154 /// # #[derive(Debug)]
155 /// # struct ErrorStub { }
156 /// #
157 /// use filters::failable::filter::FailableFilter;
158 ///
159 /// let a = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a > 3) });
160 /// let b = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a < 7) });
161 /// let c = a.xor(b);
162 ///
163 /// assert!(c.filter(&1).unwrap());
164 /// assert!(c.filter(&3).unwrap());
165 /// assert!(!c.filter(&4).unwrap());
166 /// assert!(!c.filter(&6).unwrap());
167 /// assert!(c.filter(&9).unwrap());
168 /// ```
169 fn xor<F>(self, other: F) -> FailableXOr<Self, F>
170 where Self: Sized,
171 {
172 FailableXOr::new(self, other)
173 }
174
175 /// Helper to connect two filters via logical AND
176 ///
177 /// ```
178 /// # #[derive(Debug)]
179 /// # struct ErrorStub { }
180 /// #
181 /// use filters::failable::filter::FailableFilter;
182 ///
183 /// let a = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a > 1) });
184 /// let b = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a < 7) });
185 /// let c = a.and(b);
186 ///
187 /// assert!(!c.filter(&1).unwrap());
188 /// assert!(c.filter(&3).unwrap());
189 /// assert!(c.filter(&4).unwrap());
190 /// assert!(c.filter(&6).unwrap());
191 /// assert!(!c.filter(&9).unwrap());
192 /// ```
193 fn and<F>(self, other: F) -> FailableAnd<Self, F::IntoFilt>
194 where Self: Sized,
195 F: IntoFailableFilter<N> + Sized
196 {
197 FailableAnd::new(self, other.into_failable_filter())
198 }
199
200 /// Helper to connect three filters via logical AND
201 ///
202 /// ```
203 /// # #[derive(Debug)]
204 /// # struct ErrorStub { }
205 /// #
206 /// use filters::failable::filter::FailableFilter;
207 ///
208 /// let a = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a > 1) });
209 /// let b = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a < 20) });
210 /// let c = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a % 2 == 0) });
211 /// let d = a.and3(b, c);
212 ///
213 /// assert!(!d.filter(&1).unwrap());
214 /// assert!(!d.filter(&3).unwrap());
215 /// assert!(d.filter(&8).unwrap());
216 /// assert!(d.filter(&10).unwrap());
217 /// assert!(d.filter(&14).unwrap());
218 /// assert!(!d.filter(&15).unwrap());
219 /// assert!(!d.filter(&19).unwrap());
220 /// ```
221 fn and3<F, F2>(self, other: F, other2: F2) -> FailableAnd<Self, FailableAnd<F::IntoFilt, F2::IntoFilt>>
222 where Self: Sized,
223 F: IntoFailableFilter<N> + Sized,
224 F2: IntoFailableFilter<N> + Sized
225 {
226 FailableAnd::new(self, FailableAnd::new(other.into_failable_filter(), other2.into_failable_filter()))
227 }
228
229 /// Helper to connect two filters via logical AND and NOT
230 ///
231 /// ```
232 /// # #[derive(Debug)]
233 /// # struct ErrorStub { }
234 /// #
235 /// use filters::failable::filter::FailableFilter;
236 ///
237 /// let a = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a > 10) });
238 /// let b = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a < 20) });
239 /// let c = a.and_not(b);
240 ///
241 /// assert!(!c.filter(&1).unwrap());
242 /// assert!(!c.filter(&3).unwrap());
243 /// assert!(!c.filter(&8).unwrap());
244 /// assert!(!c.filter(&11).unwrap());
245 /// assert!(c.filter(&24).unwrap());
246 /// assert!(c.filter(&25).unwrap());
247 /// assert!(c.filter(&29).unwrap());
248 /// ```
249 fn and_not<F>(self, other: F) -> FailableAnd<Self, FailableNot<F::IntoFilt>>
250 where Self: Sized,
251 F: IntoFailableFilter<N> + Sized
252 {
253 self.and(FailableNot::new(other.into_failable_filter()))
254 }
255
256 /// Helper to connect two filters via logical NAND
257 ///
258 /// ```
259 /// # #[derive(Debug)]
260 /// # struct ErrorStub { }
261 /// #
262 /// use filters::failable::filter::FailableFilter;
263 ///
264 /// let a = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a > 10) });
265 /// let b = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a < 20) });
266 /// let c = a.nand(b);
267 ///
268 /// assert!(c.filter(&1).unwrap());
269 /// assert!(c.filter(&3).unwrap());
270 /// assert!(c.filter(&8).unwrap());
271 /// assert!(!c.filter(&11).unwrap());
272 /// assert!(!c.filter(&14).unwrap());
273 /// assert!(c.filter(&25).unwrap());
274 /// assert!(c.filter(&29).unwrap());
275 /// ```
276 fn nand<F>(self, other: F) -> FailableNot<FailableAnd<Self, F>>
277 where Self: Sized,
278 {
279 FailableNot::new(FailableAnd::new(self, other))
280 }
281
282 /// Helper to transform the input of a filter
283 ///
284 /// ```
285 /// # #[derive(Debug)]
286 /// # struct ErrorStub { }
287 /// #
288 /// use filters::failable::filter::FailableFilter;
289 ///
290 /// let a = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a > 1) });
291 /// let b = (|&a: &i64| -> Result<bool, ErrorStub> { Ok(a < 7) });
292 /// let b = b.map_input(|&x: &usize| x as i64);
293 /// let c = a.and(b);
294 ///
295 /// assert!(!c.filter(&1).unwrap());
296 /// assert!(c.filter(&3).unwrap());
297 /// assert!(c.filter(&4).unwrap());
298 /// assert!(c.filter(&6).unwrap());
299 /// assert!(!c.filter(&9).unwrap());
300 /// ```
301 fn map_input<O, B, T, M>(self, map: M) -> FailableMapInput<Self, M, O, B>
302 where Self: Sized,
303 M: Fn(&T) -> N,
304 B: Borrow<O> + Sized
305 {
306 FailableMapInput::new(self, map)
307 }
308
309 /// Helper to transform the input of a filter
310 ///
311 /// ```
312 /// # use std::fmt;
313 /// # #[derive(Debug)]
314 /// # struct ErrorStub { }
315 /// #
316 /// use filters::failable::filter::FailableFilter;
317 ///
318 /// let a = (|&a: &usize| -> Result<bool, ErrorStub> { Ok(a > 1) });
319 /// let b = (|&a: &usize| -> Result<bool, fmt::Error> { Ok(a < 7) });
320 /// let b = b.map_err(|_: fmt::Error| ErrorStub {});
321 /// let c = a.and(b);
322 ///
323 /// assert!(!c.filter(&1).unwrap());
324 /// assert!(c.filter(&3).unwrap());
325 /// assert!(c.filter(&4).unwrap());
326 /// assert!(c.filter(&6).unwrap());
327 /// assert!(!c.filter(&9).unwrap());
328 /// ```
329 fn map_err<M, OE>(self, map: M) -> FailableMapErr<Self, M, OE>
330 where Self: Sized,
331 M: Fn(Self::Error) -> OE
332 {
333 FailableMapErr::new(self, map)
334 }
335
336}
337
338/// All closures that take a ref to something and return Result<bool, E> are failable filters
339impl<I, E, T> FailableFilter<I> for T
340 where T: Fn(&I) -> Result<bool, E>
341{
342 type Error = E;
343
344 fn filter(&self, other: &I) -> Result<bool, Self::Error> {
345 self(other)
346 }
347}
348
349#[cfg(test)]
350mod tests {
351 use super::*;
352
353 #[derive(Debug)]
354 struct StupError { }
355
356 #[test]
357 fn compile_test() {
358 let a = |_: &i32| -> Result<bool, StupError> { Ok(true) };
359
360 assert!(a.filter(&1).unwrap());
361 }
362
363 #[test]
364 fn test_error_return() {
365 let a = |_: &i32| -> Result<bool, StupError> { Err(StupError {}) };
366
367 assert!(a.filter(&1).is_err());
368 }
369
370 #[test]
371 fn test_error_return_and_chained() {
372 let a = |_: &i32| -> Result<bool, StupError> { Err(StupError {}) };
373 let b = |_: &i32| -> Result<bool, StupError> { Ok(true) };
374 let c = |_: &i32| -> Result<bool, StupError> { Ok(true) };
375 let d = |_: &i32| -> Result<bool, StupError> { Ok(true) };
376
377 let e = d.and(b).and(c).and(a);
378
379 assert!(e.filter(&1).is_err());
380 }
381
382 #[test]
383 fn test_error_return_or_chained() {
384 let a = |_: &i32| -> Result<bool, StupError> { Err(StupError {}) };
385 let b = |_: &i32| -> Result<bool, StupError> { Ok(true) };
386 let c = |_: &i32| -> Result<bool, StupError> { Ok(true) };
387 let d = |_: &i32| -> Result<bool, StupError> { Ok(true) };
388
389 let e = a.or(b).or(c).or(d);
390
391 assert!(e.filter(&1).is_err());
392 }
393
394 #[test]
395 fn test_both_filter_types() {
396 use filter::Filter;
397
398 let a = |_: &i32| -> Result<bool, StupError> { Ok(true) };
399 let b = |_: &i32| -> bool { true };
400 let c = |_: &i32| -> Result<bool, StupError> { Ok(true) };
401 let d = |_: &i32| -> bool { false };
402
403 let e = a // true
404 .and(b.into_failable().map_err(|_| StupError {})) // true
405 .xor(c) // true
406 .or(d.into_failable().map_err(|_| StupError {})); // true
407
408 assert!(!e.filter(&1).unwrap());
409 }
410
411
412 #[test]
413 fn test_both_filter_types_in_one_scope() {
414 use filter::Filter;
415 use failable::filter::FailableFilter;
416
417 let failable = |_: &i32| -> Result<bool, StupError> { Ok(true) };
418 let unfailable = |_: &i32| -> bool { true };
419
420 assert!(failable.filter(&1).unwrap());
421 assert!(unfailable.filter(&1));
422
423 }
424}
425