summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLee Bousfield <ljbousfield@gmail.com>2016-08-23 12:15:01 -0600
committerLee Bousfield <ljbousfield@gmail.com>2016-08-25 07:05:03 -0600
commit97b83fe851fe2448d6f90427e8ea0a965f5a7a49 (patch)
tree69fe1ab4e732fe057dda4f9a20f54426dcde53f8 /src
parentef94a396ccc491ddc9dd734aba15540d7a9ea53e (diff)
Implement Fn(I) -> bool for Filter structs
Diffstat (limited to 'src')
-rw-r--r--src/filter.rs66
-rw-r--r--src/impl_traits.rs63
-rw-r--r--src/lib.rs3
-rw-r--r--src/ops/and.rs8
-rw-r--r--src/ops/bool.rs9
-rw-r--r--src/ops/not.rs8
-rw-r--r--src/ops/or.rs8
-rw-r--r--src/ops/xor.rs8
8 files changed, 136 insertions, 37 deletions
diff --git a/src/filter.rs b/src/filter.rs
index dd8dfc6..83f466d 100644
--- a/src/filter.rs
+++ b/src/filter.rs
@@ -263,7 +263,9 @@ mod test {
fn closures() {
let a = (|&a: &usize|{ a < 3 }).and(|&a: &usize| a > 1);
+ assert_eq!(a.filter(&0), false);
assert_eq!(a.filter(&2), true);
+ assert_eq!(a.filter(&3), false);
}
#[test]
@@ -330,7 +332,7 @@ mod test {
assert_eq!(eq.and(Bool::new(true)).filter(&1), true);
let eq = |&a: &usize| { a == 1 };
- assert_eq!(eq.or(Bool::new(true)).filter(&17), true);
+ assert_eq!(eq.xor(Bool::new(true)).filter(&1), false);
let eq = |&a: &usize| { a == 1 };
assert_eq!(eq.or(Bool::new(true)).filter(&42), true);
@@ -376,3 +378,65 @@ mod test {
assert_eq!(r, vec![6, 7, 8, 9, 10, 11, 12, 13, 14]);
}
}
+
+
+#[cfg(test)]
+#[cfg(feature = "unstable-filter-as-fn")]
+mod test_unstable {
+ use filter::Filter;
+ use ops::bool::Bool;
+
+ #[test]
+ fn closures() {
+ let a = (|&a: &usize|{ a < 3 }).and(|&a: &usize| a > 1);
+
+ assert_eq!(a(&0), false);
+ assert_eq!(a(&2), true);
+ assert_eq!(a(&3), false);
+ }
+
+ #[test]
+ fn xor_filter() {
+ let a = (|&a: &usize| a == 0).xor(|&a: &usize| a == 3);
+
+ assert_eq!(a(&3), true);
+ assert_eq!(a(&5), false);
+ assert_eq!(a(&0), true);
+ }
+
+ #[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(&21), true);
+ assert_eq!(a(&11), false);
+ }
+
+ #[test]
+ fn filter_with_bool() {
+ let eq = |&a: &usize| { a == 1 };
+ assert_eq!(eq.and(Bool::new(true))(&0), false);
+
+ let eq = |&a: &usize| { a == 1 };
+ assert_eq!(eq.and(Bool::new(true))(&1), true);
+
+ let eq = |&a: &usize| { a == 1 };
+ assert_eq!(eq.xor(Bool::new(true))(&1), false);
+
+ let eq = |&a: &usize| { a == 1 };
+ assert_eq!(eq.or(Bool::new(true))(&42), true);
+ }
+
+ #[test]
+ fn filter_iterator() {
+ let v = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
+
+ let inrange = (|&a: &usize| { a > 5 }).and(|&a: &usize| { a < 15 });
+
+ let r : Vec<usize> = v.into_iter().filter(inrange).collect();
+
+ assert_eq!(r, vec![6, 7, 8, 9, 10, 11, 12, 13, 14]);
+ }
+}
+
diff --git a/src/impl_traits.rs b/src/impl_traits.rs
new file mode 100644
index 0000000..4d6c8cc
--- /dev/null
+++ b/src/impl_traits.rs
@@ -0,0 +1,63 @@
+/// Creates operator implementations for a Filter struct
+/// Currently only Fn and Filter implementations are handled
+///
+/// Takes at least two arguments: the struct to implement the traits for, and
+/// the block to define the filter function. Preceeding the block should be the
+/// variables for self and the passed in argument to filter, separated by spaces.
+/// After that, any filter generics needed for the struct should be specified.
+///
+/// # Examples
+///
+/// ```
+/// # #![cfg_attr(feature = "unstable-filter-as-fn", feature(unboxed_closures, fn_traits))]
+/// # #[macro_use] extern crate filters;
+/// # use filters::filter::Filter;
+/// # fn main() {
+/// struct Or<T, U> {
+/// a: T,
+/// b: U
+/// }
+///
+/// impl_operators!(Or, self e { self.a.filter(e) || self.b.filter(e) }, T, U);
+///
+/// let or = Or {a: |&x: &i32| x < 5, b: |&x: &i32| x > 10};
+/// assert_eq!(or.filter(&0), true);
+/// assert_eq!(or.filter(&7), false);
+/// assert_eq!(or.filter(&15), true);
+/// // If unstable-filter-as-fn is enabled `or` will also be a Fn(&i32) -> bool
+/// # }
+/// ```
+#[macro_export]
+macro_rules! impl_operators {
+ ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl:block, $( $generic:ident ),*) => {
+ #[cfg(feature = "unstable-filter-as-fn")]
+ impl<'a, I, $( $generic: Filter<I>, )*> FnOnce<(&'a I,)> for $struct_ident<$( $generic, )*> {
+ type Output = bool;
+ extern "rust-call" fn call_once<'b>(self, (arg,): (&'a I,)) -> Self::Output {
+ self.filter(arg)
+ }
+ }
+
+ #[cfg(feature = "unstable-filter-as-fn")]
+ impl<'a, I, $( $generic: Filter<I>, )*> FnMut<(&'a I,)> for $struct_ident<$( $generic, )*> {
+ extern "rust-call" fn call_mut<'b>(&mut self, (arg,): (&'a I,)) -> Self::Output {
+ self.filter(arg)
+ }
+ }
+
+ #[cfg(feature = "unstable-filter-as-fn")]
+ impl<'a, I, $( $generic: Filter<I>, )*> Fn<(&'a I,)> for $struct_ident<$( $generic, )*> {
+ #[allow(unused_variables)]
+ extern "rust-call" fn call<'b>(&$self_var, ($arg_var,): (&'a I,)) -> Self::Output $filter_impl
+ }
+
+ #[cfg(not(feature = "unstable-filter-as-fn"))]
+ impl<I, $( $generic: Filter<I>, )*> Filter<I> for $struct_ident<$( $generic, )*> {
+ #[allow(unused_variables)]
+ fn filter(&$self_var, $arg_var: &I) -> bool $filter_impl
+ }
+ };
+ ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl: block) => {
+ impl_operators!($struct_ident, $self_var $arg_var $filter_impl, );
+ };
+}
diff --git a/src/lib.rs b/src/lib.rs
index 5f4e268..b8966ff 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -66,7 +66,10 @@
//! ```
#![doc(html_root_url = "https://matthiasbeyer.github.io/filters/")]
+#![cfg_attr(feature = "unstable-filter-as-fn", feature(unboxed_closures, fn_traits))]
pub mod filter;
+#[macro_use]
+pub mod impl_traits;
pub mod ops;
diff --git a/src/ops/and.rs b/src/ops/and.rs
index 545df83..92937ec 100644
--- a/src/ops/and.rs
+++ b/src/ops/and.rs
@@ -20,10 +20,4 @@ impl<T, U> And<T, U> {
}
-impl<I, T: Filter<I>, U: Filter<I>> Filter<I> for And<T, U> {
-
- fn filter(&self, e: &I) -> bool {
- self.a.filter(e) && self.b.filter(e)
- }
-
-}
+impl_operators!(And, self e { self.a.filter(e) && self.b.filter(e) }, T, U);
diff --git a/src/ops/bool.rs b/src/ops/bool.rs
index fa33da2..3c32271 100644
--- a/src/ops/bool.rs
+++ b/src/ops/bool.rs
@@ -19,14 +19,6 @@ impl Bool {
}
-impl<I> Filter<I> for Bool {
-
- fn filter(&self, _: &I) -> bool {
- self.b
- }
-
-}
-
impl From<bool> for Bool {
fn from(b: bool) -> Bool {
@@ -35,3 +27,4 @@ impl From<bool> for Bool {
}
+impl_operators!(Bool, self e { self.b }, );
diff --git a/src/ops/not.rs b/src/ops/not.rs
index bddb7ed..e0f10f5 100644
--- a/src/ops/not.rs
+++ b/src/ops/not.rs
@@ -19,10 +19,4 @@ impl<T> Not<T> {
}
-impl<I, T: Filter<I>> Filter<I> for Not<T> {
-
- fn filter(&self, e: &I) -> bool {
- !self.a.filter(e)
- }
-
-}
+impl_operators!(Not, self e { !self.a.filter(e) }, T);
diff --git a/src/ops/or.rs b/src/ops/or.rs
index d27e152..c4819ba 100644
--- a/src/ops/or.rs
+++ b/src/ops/or.rs
@@ -20,10 +20,4 @@ impl<T, U> Or<T, U> {
}
-impl<I, T: Filter<I>, U: Filter<I>> Filter<I> for Or<T, U> {
-
- fn filter(&self, e: &I) -> bool {
- self.a.filter(e) || self.b.filter(e)
- }
-
-}
+impl_operators!(Or, self e { self.a.filter(e) || self.b.filter(e) }, T, U);
diff --git a/src/ops/xor.rs b/src/ops/xor.rs
index 32f264b..a41b59f 100644
--- a/src/ops/xor.rs
+++ b/src/ops/xor.rs
@@ -20,10 +20,4 @@ impl<T, U> XOr<T, U> {
}
-impl<I, T: Filter<I>, U: Filter<I>> Filter<I> for XOr<T, U> {
-
- fn filter(&self, e: &I) -> bool {
- self.a.filter(e) ^ self.b.filter(e)
- }
-
-}
+impl_operators!(XOr, self e { self.a.filter(e) ^ self.b.filter(e) }, T, U);