From 97b83fe851fe2448d6f90427e8ea0a965f5a7a49 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Tue, 23 Aug 2016 12:15:01 -0600 Subject: Implement Fn(I) -> bool for Filter structs --- src/filter.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/impl_traits.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +++ src/ops/and.rs | 8 +------ src/ops/bool.rs | 9 +------- src/ops/not.rs | 8 +------ src/ops/or.rs | 8 +------ src/ops/xor.rs | 8 +------ 8 files changed, 136 insertions(+), 37 deletions(-) create mode 100644 src/impl_traits.rs (limited to 'src') 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 = 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 { +/// 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, )*> 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, )*> 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, )*> 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, )*> Filter 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 And { } -impl, U: Filter> Filter for And { - - 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 Filter for Bool { - - fn filter(&self, _: &I) -> bool { - self.b - } - -} - impl From for Bool { fn from(b: bool) -> Bool { @@ -35,3 +27,4 @@ impl From 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 Not { } -impl> Filter for Not { - - 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 Or { } -impl, U: Filter> Filter for Or { - - 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 XOr { } -impl, U: Filter> Filter for XOr { - - 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); -- cgit v1.2.3