summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2017-10-01 11:24:01 +0200
committerMatthias Beyer <mail@beyermatthias.de>2017-10-01 13:55:16 +0200
commitebd9d4e90c252ff8f20c3f1733b4884e08a66c78 (patch)
treea50476ed645006872aafa449cffe5fbee891371e
parent3d99f7879186c6be4c4b1ef86d02113bf6685e8b (diff)
Add failable filter infrastructure
-rw-r--r--src/failable/filter.rs250
-rw-r--r--src/failable/mod.rs9
-rw-r--r--src/failable/ops/and.rs37
-rw-r--r--src/failable/ops/bool.rs41
-rw-r--r--src/failable/ops/mod.rs11
-rw-r--r--src/failable/ops/not.rs35
-rw-r--r--src/failable/ops/or.rs37
-rw-r--r--src/failable/ops/xor.rs38
-rw-r--r--src/lib.rs1
9 files changed, 459 insertions, 0 deletions
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<N, E: Error + Sized> {
+ type IntoFilt: FailableFilter<N, E>;
+
+ fn into_failable_filter(self) -> Self::IntoFilt;
+}
+
+/// All Filters can be turned into Filters
+impl<N, E: Error + Sized, I: FailableFilter<N, E>> IntoFailableFilter<N, E> for I {
+ type IntoFilt = I;
+
+ fn into_failable_filter(self) -> Self::IntoFilt {
+ self
+ }
+}
+
+pub trait FailableFilter<N, E: Error> {
+ /// The function which is used to filter something
+ fn filter(&self, &N) -> Result<bool, E>;
+
+ /// Helper to invert a filter.
+ ///
+ /// ```
+ /// use filters::filter::Filter;
+ ///
+ /// let f = (|&a: &usize| { a == 1 }).not();
+ ///
+ /// assert!(f.filter(&2));
+ /// ```
+ fn not(self) -> FailableNot<Self>
+ 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<F>(self, other: F) -> FailableOr<Self, F::IntoFilt>
+ where Self: Sized,
+ F: IntoFailableFilter<N, E> + 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<F>(self, other: F) -> FailableOr<Self, FailableNot<F::IntoFilt>>
+ where Self: Sized,
+ F: IntoFailableFilter<N, E> + 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<F, F2>(self, other: F, other2: F2) -> FailableOr<Self, FailableOr<F::IntoFilt, F2::IntoFilt>>
+ where Self: Sized,
+ F: IntoFailableFilter<N, E> + Sized,
+ F2: IntoFailableFilter<N, E> + 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<F>(self, other: F) -> FailableNot<FailableOr<Self, F>>
+ 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<F>(self, other: F) -> FailableXOr<Self, F>
+ 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<F>(self, other: F) -> FailableAnd<Self, F::IntoFilt>
+ where Self: Sized,
+ F: IntoFailableFilter<N, E> + 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<F, F2>(self, other: F, other2: F2) -> FailableAnd<Self, FailableAnd<F::IntoFilt, F2::IntoFilt>>
+ where Self: Sized,
+ F: IntoFailableFilter<N, E> + Sized,
+ F2: IntoFailableFilter<N, E> + 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<F>(self, other: F) -> FailableAnd<Self, FailableNot<F::IntoFilt>>
+ where Self: Sized,
+ F: IntoFailableFilter<N, E> + 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<F>(self, other: F) -> FailableNot<FailableAnd<Self, F>>
+ 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>(T, U);
+
+impl<T, U> FailableAnd<T, U> {
+
+ pub fn new(a: T, b: U) -> FailableAnd<T, U> {
+ FailableAnd(a, b)
+ }
+
+}
+
+impl<N, E, T, U> FailableFilter<N, E> for FailableAnd<T, U>
+ where E: Error,
+ T: FailableFilter<N, E>,
+ U: FailableFilter<N, E>
+{
+ fn filter(&self, e: &N) -> Result<bool, E> {
+ 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<bool> for FailableBool {
+
+ fn from(b: bool) -> FailableBool {
+ FailableBool::new(b)
+ }
+
+}
+
+impl<N, E: Error> FailableFilter<N, E> for FailableBool {
+ fn filter(&self, _: &N) -> Result<bool, E> {
+ 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>(T);
+
+impl<T> FailableNot<T> {
+
+ pub fn new(a: T) -> FailableNot<T> {
+ FailableNot(a)
+ }
+
+}
+
+impl<N, E, T> FailableFilter<N, E> for FailableNot<T>
+ where E: Error,
+ T: FailableFilter<N, E>
+{
+ fn filter(&self, e: &N) -> Result<bool, E> {
+ 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>(T, U);
+
+impl<T, U> FailableOr<T, U> {
+
+ pub fn new(a: T, b: U) -> FailableOr<T, U> {
+ FailableOr(a, b)
+ }
+
+}
+
+impl<N, E, T, U> FailableFilter<N, E> for FailableOr<T, U>
+ where E: Error,
+ T: FailableFilter<N, E>,
+ U: FailableFilter<N, E>
+{
+ fn filter(&self, e: &N) -> Result<bool, E> {
+ 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>(T, U);
+
+impl<T, U> FailableXOr<T, U> {
+
+ pub fn new(a: T, b: U) -> FailableXOr<T, U> {
+ FailableXOr(a, b)
+ }
+
+}
+
+impl<N, E, T, U> FailableFilter<N, E> for FailableXOr<T, U>
+ where E: Error,
+ T: FailableFilter<N, E>,
+ U: FailableFilter<N, E>
+{
+ fn filter(&self, e: &N) -> Result<bool, E> {
+ 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;