diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2016-08-10 10:08:37 +0200 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2016-08-11 15:59:43 +0200 |
commit | e57b599ee19a0d11bcb73151c1f19e61e89c3be8 (patch) | |
tree | 06c586d2c1474f9bbbf685b4079938106f2a36fe | |
parent | b79d8963fc79da66b9efc55fd5fa45bb0b98c051 (diff) |
Make everything work
With patches from Marcel Müller <neikos@neikos.email>
-rw-r--r-- | src/filter.rs | 169 | ||||
-rw-r--r-- | src/ops/and.rs | 16 | ||||
-rw-r--r-- | src/ops/not.rs | 10 | ||||
-rw-r--r-- | src/ops/or.rs | 16 |
4 files changed, 191 insertions, 20 deletions
diff --git a/src/filter.rs b/src/filter.rs index 976bd53..6502fc1 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -1,5 +1,170 @@ -pub trait Filter<T> { +pub use ops::and::And; +pub use ops::not::Not; +pub use ops::or::Or; - fn filter(&self, &T) -> bool; +pub trait IntoFilter<N> { + type IntoFilt: Filter<N>; + + fn into_filter(self) -> Self::IntoFilt; +} + +impl<N, I: Filter<N>> IntoFilter<N> for I { + type IntoFilt = I; + + fn into_filter(self) -> I { + self + } +} + +impl<I, T: Fn(&I) -> bool> Filter<I> for T { + fn filter(&self, other: &I) -> bool { + self(other) + } +} + +pub trait Filter<N> { + + fn filter(&self, &N) -> bool; + + fn not(self) -> Not<Self> + where Self: Sized + { + Not::new(self) + } + + fn or<F>(self, other: F) -> Or<Self, F::IntoFilt> + where Self: Sized, + F: IntoFilter<N> + Sized + { + Or::new(self, other.into_filter()) + } + + fn or_not<F>(self, other: F) -> Or<Self, Not<F::IntoFilt>> + where Self: Sized, + F: IntoFilter<N> + Sized, + { + self.or(Not::new(other.into_filter())) + } + + fn or3<F, F2>(self, other: F, other2: F2) -> Or<Self, Or<F::IntoFilt, F2::IntoFilt>> + where Self: Sized, + F: IntoFilter<N> + Sized, + F2: IntoFilter<N> + Sized + { + Or::new(self, Or::new(other.into_filter(), other2.into_filter())) + } + + fn and<F>(self, other: F) -> And<Self, F::IntoFilt> + where Self: Sized, + F: IntoFilter<N> + Sized + { + And::new(self, other.into_filter()) + } + + fn and3<F, F2>(self, other: F, other2: F2) -> And<Self, And<F::IntoFilt, F2::IntoFilt>> + where Self: Sized, + F: IntoFilter<N> + Sized, + F2: IntoFilter<N> + Sized + { + And::new(self, And::new(other.into_filter(), other2.into_filter())) + } + + fn and_not<F>(self, other: F) -> And<Self, Not<F::IntoFilt>> + where Self: Sized, + F: IntoFilter<N> + Sized + { + self.and(Not::new(other.into_filter())) + } + + +} + + +#[cfg(test)] +mod test { + use filter::Filter; + use ops::and::And; + + #[test] + fn closures() { + let a = (|&a: &usize|{ a < 3 }).and(|&a: &usize| a > 1); + + assert_eq!(a.filter(&2), true); + } + + #[test] + fn and_filter() { + let a = And::new(|&a: &usize| a > 0, |&a: &usize| a == 3); + + assert_eq!(a.filter(&3), true); + assert_eq!(a.filter(&5), false); + assert_eq!(a.filter(&0), false); + } + + #[test] + fn complex_filter() { + let a = (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).or(|&a: &usize| a == 10); + // We now have ((a > 5) && !(a < 20) ) || a == 10 + + assert_eq!(a.filter(&21), true); + assert_eq!(a.filter(&10), true); + assert_eq!(a.filter(&11), false); + assert_eq!(a.filter(&5), false); + } + + #[test] + fn complex_filter_closured() { + let a = (|&a: &usize| (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).filter(&a)).or(|&a: &usize| a == 10); + // We now have ((a > 5) && !(a < 20)) || a == 10 + + assert_eq!(a.filter(&21), true); + assert_eq!(a.filter(&10), true); + assert_eq!(a.filter(&11), false); + assert_eq!(a.filter(&5), false); + } + + #[test] + fn complex_filter_named_closures() { + let not_eq_to_one = |&a: &usize| { a != 1 }; + let not_eq_to_two = |&a: &usize| { a != 2 }; + let not_eq_to_three = |&a: &usize| { a != 3 }; + + let a = not_eq_to_one.and(not_eq_to_two).and(not_eq_to_three); + // We now have ((a > 5) && !(a < 20)) || a == 10 + + assert_eq!(a.filter(&21), true); + assert_eq!(a.filter(&10), true); + assert_eq!(a.filter(&1), false); + assert_eq!(a.filter(&3), false); + } + + struct EqTo { + pub i: usize, + } + + impl Filter<usize> for EqTo { + fn filter(&self, n: &usize) -> bool { + self.i == *n + } + } + + #[test] + fn filter_with_eqto() { + let eq = EqTo { i: 0 }; + assert_eq!(eq.filter(&0), true); + assert_eq!(eq.filter(&1), false); + assert_eq!(eq.filter(&17), false); + assert_eq!(eq.filter(&42), false); + } + + #[test] + fn filter_with_combined_eqto() { + let aeq = EqTo { i: 1 }.not().and_not(EqTo { i: 17 }); + + assert_eq!(aeq.filter(&0), true); + assert_eq!(aeq.filter(&1), false); + assert_eq!(aeq.filter(&2), true); + assert_eq!(aeq.filter(&17), false); + } } diff --git a/src/ops/and.rs b/src/ops/and.rs index 8d79b42..074446e 100644 --- a/src/ops/and.rs +++ b/src/ops/and.rs @@ -1,21 +1,23 @@ use filter::Filter; -pub struct And<T> { - a: Box<Filter<T>>, - b: Box<Filter<T>> +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct And<T, U> { + a: T, + b: U } -impl<T> And<T> { +impl<T, U> And<T, U> { - pub fn new(a: Box<Filter<T>>, b: Box<Filter<T>>) -> And<T> { + pub fn new(a: T, b: U) -> And<T, U> { And { a: a, b: b } } } -impl<T> Filter<T> for And<T> { +impl<I, T: Filter<I>, U: Filter<I>> Filter<I> for And<T, U> { - fn filter(&self, e: &T) -> bool { + fn filter(&self, e: &I) -> bool { self.a.filter(e) && self.b.filter(e) } diff --git a/src/ops/not.rs b/src/ops/not.rs index a7c5c76..895b7de 100644 --- a/src/ops/not.rs +++ b/src/ops/not.rs @@ -1,20 +1,22 @@ use filter::Filter; +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] pub struct Not<T> { - a: Box<Filter<T>> + a: T } impl<T> Not<T> { - pub fn new(a: Box<Filter<T>>) -> Not<T> { + pub fn new(a: T) -> Not<T> { Not { a: a } } } -impl<T> Filter<T> for Not<T> { +impl<I, T: Filter<I>> Filter<I> for Not<T> { - fn filter(&self, e: &T) -> bool { + fn filter(&self, e: &I) -> bool { !self.a.filter(e) } diff --git a/src/ops/or.rs b/src/ops/or.rs index b001d75..c6f6a67 100644 --- a/src/ops/or.rs +++ b/src/ops/or.rs @@ -1,21 +1,23 @@ use filter::Filter; -pub struct Or<T> { - a: Box<Filter<T>>, - b: Box<Filter<T>> +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct Or<T, U> { + a: T, + b: U } -impl<T> Or<T> { +impl<T, U> Or<T, U> { - pub fn new(a: Box<Filter<T>>, b: Box<Filter<T>>) -> Or<T> { + pub fn new(a: T, b: U) -> Or<T, U> { Or { a: a, b: b } } } -impl<T> Filter<T> for Or<T> { +impl<I, T: Filter<I>, U: Filter<I>> Filter<I> for Or<T, U> { - fn filter(&self, e: &T) -> bool { + fn filter(&self, e: &I) -> bool { self.a.filter(e) || self.b.filter(e) } |