From e57b599ee19a0d11bcb73151c1f19e61e89c3be8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 10 Aug 2016 10:08:37 +0200 Subject: Make everything work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With patches from Marcel Müller --- src/filter.rs | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/ops/and.rs | 16 +++--- src/ops/not.rs | 10 ++-- 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 { +pub use ops::and::And; +pub use ops::not::Not; +pub use ops::or::Or; - fn filter(&self, &T) -> bool; +pub trait IntoFilter { + type IntoFilt: Filter; + + fn into_filter(self) -> Self::IntoFilt; +} + +impl> IntoFilter for I { + type IntoFilt = I; + + fn into_filter(self) -> I { + self + } +} + +impl bool> Filter for T { + fn filter(&self, other: &I) -> bool { + self(other) + } +} + +pub trait Filter { + + fn filter(&self, &N) -> bool; + + fn not(self) -> Not + where Self: Sized + { + Not::new(self) + } + + fn or(self, other: F) -> Or + where Self: Sized, + F: IntoFilter + Sized + { + Or::new(self, other.into_filter()) + } + + fn or_not(self, other: F) -> Or> + where Self: Sized, + F: IntoFilter + Sized, + { + self.or(Not::new(other.into_filter())) + } + + fn or3(self, other: F, other2: F2) -> Or> + where Self: Sized, + F: IntoFilter + Sized, + F2: IntoFilter + Sized + { + Or::new(self, Or::new(other.into_filter(), other2.into_filter())) + } + + fn and(self, other: F) -> And + where Self: Sized, + F: IntoFilter + Sized + { + And::new(self, other.into_filter()) + } + + fn and3(self, other: F, other2: F2) -> And> + where Self: Sized, + F: IntoFilter + Sized, + F2: IntoFilter + Sized + { + And::new(self, And::new(other.into_filter(), other2.into_filter())) + } + + fn and_not(self, other: F) -> And> + where Self: Sized, + F: IntoFilter + 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 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 { - a: Box>, - b: Box> +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct And { + a: T, + b: U } -impl And { +impl And { - pub fn new(a: Box>, b: Box>) -> And { + pub fn new(a: T, b: U) -> And { And { a: a, b: b } } } -impl Filter for And { +impl, U: Filter> Filter for And { - 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 { - a: Box> + a: T } impl Not { - pub fn new(a: Box>) -> Not { + pub fn new(a: T) -> Not { Not { a: a } } } -impl Filter for Not { +impl> Filter for Not { - 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 { - a: Box>, - b: Box> +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct Or { + a: T, + b: U } -impl Or { +impl Or { - pub fn new(a: Box>, b: Box>) -> Or { + pub fn new(a: T, b: U) -> Or { Or { a: a, b: b } } } -impl Filter for Or { +impl, U: Filter> Filter for Or { - fn filter(&self, e: &T) -> bool { + fn filter(&self, e: &I) -> bool { self.a.filter(e) || self.b.filter(e) } -- cgit v1.2.3