From ebd9d4e90c252ff8f20c3f1733b4884e08a66c78 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sun, 1 Oct 2017 11:24:01 +0200 Subject: Add failable filter infrastructure --- src/failable/filter.rs | 250 +++++++++++++++++++++++++++++++++++++++++++++++ src/failable/mod.rs | 9 ++ src/failable/ops/and.rs | 37 +++++++ src/failable/ops/bool.rs | 41 ++++++++ src/failable/ops/mod.rs | 11 +++ src/failable/ops/not.rs | 35 +++++++ src/failable/ops/or.rs | 37 +++++++ src/failable/ops/xor.rs | 38 +++++++ src/lib.rs | 1 + 9 files changed, 459 insertions(+) create mode 100644 src/failable/filter.rs create mode 100644 src/failable/mod.rs create mode 100644 src/failable/ops/and.rs create mode 100644 src/failable/ops/bool.rs create mode 100644 src/failable/ops/mod.rs create mode 100644 src/failable/ops/not.rs create mode 100644 src/failable/ops/or.rs create mode 100644 src/failable/ops/xor.rs diff --git a/src/failable/filter.rs b/src/failable/filter.rs new file mode 100644 index 0000000..c611c86 --- /dev/null +++ b/src/failable/filter.rs @@ -0,0 +1,250 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +use std::error::Error; + +pub use failable::ops::and::FailableAnd; +pub use failable::ops::bool::FailableBool; +pub use failable::ops::not::FailableNot; +pub use failable::ops::xor::FailableXOr; +pub use failable::ops::or::FailableOr; + +/// Trait for converting something into a Filter +pub trait IntoFailableFilter { + type IntoFilt: FailableFilter; + + fn into_failable_filter(self) -> Self::IntoFilt; +} + +/// All Filters can be turned into Filters +impl> IntoFailableFilter for I { + type IntoFilt = I; + + fn into_failable_filter(self) -> Self::IntoFilt { + self + } +} + +pub trait FailableFilter { + /// The function which is used to filter something + fn filter(&self, &N) -> Result; + + /// Helper to invert a filter. + /// + /// ``` + /// use filters::filter::Filter; + /// + /// let f = (|&a: &usize| { a == 1 }).not(); + /// + /// assert!(f.filter(&2)); + /// ``` + fn not(self) -> FailableNot + where Self: Sized + { + FailableNot::new(self) + } + + /// Helper to connect two filters via logical OR + /// + /// ``` + /// use filters::filter::Filter; + /// + /// let a = (|&a: &usize| { a == 1 }); + /// let b = (|&a: &usize| { a == 2 }); + /// let c = a.or(b); + /// + /// assert!(c.filter(&1)); + /// assert!(c.filter(&2)); + /// assert!(!c.filter(&7)); + /// ``` + fn or(self, other: F) -> FailableOr + where Self: Sized, + F: IntoFailableFilter + Sized + { + FailableOr::new(self, other.into_failable_filter()) + } + + /// Helper to connect two filters via logical OR and NOT + /// + /// ``` + /// use filters::filter::Filter; + /// + /// let a = (|&a: &usize| { a == 1 }); + /// let b = (|&a: &usize| { a == 2 }); + /// let c = a.or_not(b); + /// + /// assert!(c.filter(&1)); + /// assert!(!c.filter(&2)); + /// assert!(c.filter(&7)); + /// ``` + fn or_not(self, other: F) -> FailableOr> + where Self: Sized, + F: IntoFailableFilter + Sized, + { + self.or(FailableNot::new(other.into_failable_filter())) + } + + /// Helper to connect three filters via logical OR + /// + /// ``` + /// use filters::filter::Filter; + /// + /// let a = (|&a: &usize| { a == 1 }); + /// let b = (|&a: &usize| { a == 2 }); + /// let c = (|&a: &usize| { a == 3 }); + /// let d = a.or3(b, c); + /// + /// assert!(d.filter(&1)); + /// assert!(d.filter(&2)); + /// assert!(d.filter(&3)); + /// assert!(!d.filter(&4)); + /// ``` + fn or3(self, other: F, other2: F2) -> FailableOr> + where Self: Sized, + F: IntoFailableFilter + Sized, + F2: IntoFailableFilter + Sized + { + FailableOr::new(self, FailableOr::new(other.into_failable_filter(), other2.into_failable_filter())) + } + + /// Helper to connect two filters via logical NOR + /// + /// ``` + /// use filters::filter::Filter; + /// + /// let a = (|&a: &usize| { a == 1 }); + /// let b = (|&a: &usize| { a == 2 }); + /// let c = a.nor(b); /* !(a == 1 || a == 2) */ + /// + /// assert!(!c.filter(&1)); + /// assert!(!c.filter(&2)); + /// assert!(c.filter(&3)); + /// assert!(c.filter(&4)); + /// ``` + fn nor(self, other: F) -> FailableNot> + where Self: Sized, + { + FailableNot::new(FailableOr::new(self, other)) + } + + /// Helper to connect two filters via logical XOR + /// + /// ``` + /// use filters::filter::Filter; + /// + /// let a = (|&a: &usize| { a > 3 }); + /// let b = (|&a: &usize| { a < 7 }); + /// let c = a.xor(b); + /// + /// assert!(c.filter(&1)); + /// assert!(c.filter(&3)); + /// assert!(!c.filter(&4)); + /// assert!(!c.filter(&6)); + /// assert!(c.filter(&9)); + /// ``` + fn xor(self, other: F) -> FailableXOr + where Self: Sized, + { + FailableXOr::new(self, other) + } + + /// Helper to connect two filters via logical AND + /// + /// ``` + /// use filters::filter::Filter; + /// + /// let a = (|&a: &usize| { a > 1 }); + /// let b = (|&a: &usize| { a < 7 }); + /// let c = a.and(b); + /// + /// assert!(!c.filter(&1)); + /// assert!(c.filter(&3)); + /// assert!(c.filter(&4)); + /// assert!(c.filter(&6)); + /// assert!(!c.filter(&9)); + /// ``` + fn and(self, other: F) -> FailableAnd + where Self: Sized, + F: IntoFailableFilter + Sized + { + FailableAnd::new(self, other.into_failable_filter()) + } + + /// Helper to connect three filters via logical AND + /// + /// ``` + /// use filters::filter::Filter; + /// + /// let a = (|&a: &usize| { a > 1 }); + /// let b = (|&a: &usize| { a < 20 }); + /// let c = (|&a: &usize| { a % 2 == 0 }); + /// let d = a.and3(b, c); + /// + /// assert!(!d.filter(&1)); + /// assert!(!d.filter(&3)); + /// assert!(d.filter(&8)); + /// assert!(d.filter(&10)); + /// assert!(d.filter(&14)); + /// assert!(!d.filter(&15)); + /// assert!(!d.filter(&19)); + /// ``` + fn and3(self, other: F, other2: F2) -> FailableAnd> + where Self: Sized, + F: IntoFailableFilter + Sized, + F2: IntoFailableFilter + Sized + { + FailableAnd::new(self, FailableAnd::new(other.into_failable_filter(), other2.into_failable_filter())) + } + + /// Helper to connect two filters via logical AND and NOT + /// + /// ``` + /// use filters::filter::Filter; + /// + /// let a = (|&a: &usize| { a > 10 }); + /// let b = (|&a: &usize| { a < 20 }); + /// let c = a.and_not(b); + /// + /// assert!(!c.filter(&1)); + /// assert!(!c.filter(&3)); + /// assert!(!c.filter(&8)); + /// assert!(!c.filter(&11)); + /// assert!(c.filter(&24)); + /// assert!(c.filter(&25)); + /// assert!(c.filter(&29)); + /// ``` + fn and_not(self, other: F) -> FailableAnd> + where Self: Sized, + F: IntoFailableFilter + Sized + { + self.and(FailableNot::new(other.into_failable_filter())) + } + + /// Helper to connect two filters via logical NAND + /// + /// ``` + /// use filters::filter::Filter; + /// + /// let a = (|&a: &usize| { a > 10 }); + /// let b = (|&a: &usize| { a < 20 }); + /// let c = a.nand(b); + /// + /// assert!(c.filter(&1)); + /// assert!(c.filter(&3)); + /// assert!(c.filter(&8)); + /// assert!(!c.filter(&11)); + /// assert!(!c.filter(&14)); + /// assert!(c.filter(&25)); + /// assert!(c.filter(&29)); + /// ``` + fn nand(self, other: F) -> FailableNot> + where Self: Sized, + { + FailableNot::new(FailableAnd::new(self, other)) + } + +} + diff --git a/src/failable/mod.rs b/src/failable/mod.rs new file mode 100644 index 0000000..2ae44a6 --- /dev/null +++ b/src/failable/mod.rs @@ -0,0 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +pub mod filter; +pub mod ops; + diff --git a/src/failable/ops/and.rs b/src/failable/ops/and.rs new file mode 100644 index 0000000..7cb883d --- /dev/null +++ b/src/failable/ops/and.rs @@ -0,0 +1,37 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +//! AND implementation. +//! +//! Will be automatically included when incluing `filter::Filter`, so importing this module +//! shouldn't be necessary. +//! + +use std::error::Error; +use failable::filter::FailableFilter; + +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct FailableAnd(T, U); + +impl FailableAnd { + + pub fn new(a: T, b: U) -> FailableAnd { + FailableAnd(a, b) + } + +} + +impl FailableFilter for FailableAnd + where E: Error, + T: FailableFilter, + U: FailableFilter +{ + fn filter(&self, e: &N) -> Result { + Ok(try!(self.0.filter(e)) && try!(self.1.filter(e))) + } +} + diff --git a/src/failable/ops/bool.rs b/src/failable/ops/bool.rs new file mode 100644 index 0000000..aef1077 --- /dev/null +++ b/src/failable/ops/bool.rs @@ -0,0 +1,41 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +//! FailableBool Filter implementation, so we can insert this in filter construction +//! +//! Will be automatically included when incluing `filter::Filter`, so importing this module +//! shouldn't be necessary. +//! + +use std::error::Error; +use failable::filter::FailableFilter; + +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct FailableBool(bool); + +impl FailableBool { + + pub fn new(b: bool) -> FailableBool { + FailableBool(b) + } + +} + +impl From for FailableBool { + + fn from(b: bool) -> FailableBool { + FailableBool::new(b) + } + +} + +impl FailableFilter for FailableBool { + fn filter(&self, _: &N) -> Result { + Ok(self.0) + } +} + diff --git a/src/failable/ops/mod.rs b/src/failable/ops/mod.rs new file mode 100644 index 0000000..feaad07 --- /dev/null +++ b/src/failable/ops/mod.rs @@ -0,0 +1,11 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +pub mod and; +pub mod bool; +pub mod not; +pub mod xor; +pub mod or; diff --git a/src/failable/ops/not.rs b/src/failable/ops/not.rs new file mode 100644 index 0000000..14c5a7e --- /dev/null +++ b/src/failable/ops/not.rs @@ -0,0 +1,35 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +//! NOT implementation. +//! +//! Will be automatically included when incluing `filter::Filter`, so importing this module +//! shouldn't be necessary. +//! + +use std::error::Error; +use failable::filter::FailableFilter; + +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct FailableNot(T); + +impl FailableNot { + + pub fn new(a: T) -> FailableNot { + FailableNot(a) + } + +} + +impl FailableFilter for FailableNot + where E: Error, + T: FailableFilter +{ + fn filter(&self, e: &N) -> Result { + self.0.filter(e).map(|b| !b) + } +} diff --git a/src/failable/ops/or.rs b/src/failable/ops/or.rs new file mode 100644 index 0000000..2a35aee --- /dev/null +++ b/src/failable/ops/or.rs @@ -0,0 +1,37 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +//! OR implementation. +//! +//! Will be automatically included when incluing `filter::Filter`, so importing this module +//! shouldn't be necessary. +//! + +use std::error::Error; +use failable::filter::FailableFilter; + +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct FailableOr(T, U); + +impl FailableOr { + + pub fn new(a: T, b: U) -> FailableOr { + FailableOr(a, b) + } + +} + +impl FailableFilter for FailableOr + where E: Error, + T: FailableFilter, + U: FailableFilter +{ + fn filter(&self, e: &N) -> Result { + Ok(try!(self.0.filter(e)) || try!(self.1.filter(e))) + } +} + diff --git a/src/failable/ops/xor.rs b/src/failable/ops/xor.rs new file mode 100644 index 0000000..b0a100d --- /dev/null +++ b/src/failable/ops/xor.rs @@ -0,0 +1,38 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +//! XOR implementation. +//! +//! Will be automatically included when incluing `filter::Filter`, so importing this module +//! shouldn't be necessary. +//! + +use std::error::Error; +use failable::filter::FailableFilter; + +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct FailableXOr(T, U); + +impl FailableXOr { + + pub fn new(a: T, b: U) -> FailableXOr { + FailableXOr(a, b) + } + +} + +impl FailableFilter for FailableXOr + where E: Error, + T: FailableFilter, + U: FailableFilter +{ + fn filter(&self, e: &N) -> Result { + Ok(try!(self.0.filter(e)) ^ try!(self.1.filter(e))) + } +} + + diff --git a/src/lib.rs b/src/lib.rs index 3c63624..b80c7e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,6 +75,7 @@ #![cfg_attr(feature = "unstable-filter-as-fn", feature(unboxed_closures, fn_traits))] pub mod filter; +pub mod failable; #[macro_use] pub mod impl_traits; pub mod ops; -- cgit v1.2.3