summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2016-08-10 10:08:37 +0200
committerMatthias Beyer <mail@beyermatthias.de>2016-08-11 15:59:43 +0200
commite57b599ee19a0d11bcb73151c1f19e61e89c3be8 (patch)
tree06c586d2c1474f9bbbf685b4079938106f2a36fe
parentb79d8963fc79da66b9efc55fd5fa45bb0b98c051 (diff)
Make everything work
With patches from Marcel Müller <neikos@neikos.email>
-rw-r--r--src/filter.rs169
-rw-r--r--src/ops/and.rs16
-rw-r--r--src/ops/not.rs10
-rw-r--r--src/ops/or.rs16
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)
}