From a8d0c99d991889125340c5e09c32bae8776189b9 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Mon, 2 Oct 2017 13:22:33 -0600 Subject: Add filter map functions --- src/failable/filter.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ src/failable/ops/map.rs | 58 +++++++++++++++++++++++++++++++++++++ src/failable/ops/mod.rs | 1 + src/filter.rs | 27 +++++++++++++++++- src/ops/map.rs | 35 +++++++++++++++++++++++ src/ops/mod.rs | 1 + 6 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 src/failable/ops/map.rs create mode 100644 src/ops/map.rs diff --git a/src/failable/filter.rs b/src/failable/filter.rs index a940cf5..c1be17b 100644 --- a/src/failable/filter.rs +++ b/src/failable/filter.rs @@ -5,12 +5,14 @@ // use std::error::Error; +use std::borrow::Borrow; 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; +pub use failable::ops::map::{FailableMapInput, FailableMapErr}; /// Trait for converting something into a Filter pub trait IntoFailableFilter { @@ -376,6 +378,80 @@ pub trait FailableFilter { FailableNot::new(FailableAnd::new(self, other)) } + /// Helper to transform the input of a filter + /// + /// ``` + /// # #[derive(Debug)] + /// # struct ErrorStub { } + /// # + /// # impl ::std::fmt::Display for ErrorStub { + /// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + /// # Ok(()) + /// # } + /// # } + /// # + /// # impl ::std::error::Error for ErrorStub { + /// # fn description(&self) -> &str { "stub" } + /// # } + /// # + /// use filters::failable::filter::FailableFilter; + /// + /// let a = (|&a: &usize| -> Result { Ok(a > 1) }); + /// let b = (|&a: &i64| -> Result { Ok(a < 7) }); + /// let b = b.map_input(|&x: &usize| x as i64); + /// let c = a.and(b); + /// + /// assert!(!c.filter(&1).unwrap()); + /// assert!(c.filter(&3).unwrap()); + /// assert!(c.filter(&4).unwrap()); + /// assert!(c.filter(&6).unwrap()); + /// assert!(!c.filter(&9).unwrap()); + /// ``` + fn map_input(self, map: M) -> FailableMapInput + where Self: Sized, + M: Fn(&T) -> N, + B: Borrow + Sized + { + FailableMapInput::new(self, map) + } + + /// Helper to transform the input of a filter + /// + /// ``` + /// # use std::fmt; + /// # #[derive(Debug)] + /// # struct ErrorStub { } + /// # + /// # impl ::std::fmt::Display for ErrorStub { + /// # fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + /// # Ok(()) + /// # } + /// # } + /// # + /// # impl ::std::error::Error for ErrorStub { + /// # fn description(&self) -> &str { "stub" } + /// # } + /// # + /// use filters::failable::filter::FailableFilter; + /// + /// let a = (|&a: &usize| -> Result { Ok(a > 1) }); + /// let b = (|&a: &usize| -> Result { Ok(a < 7) }); + /// let b = b.map_err(|_: fmt::Error| ErrorStub {}); + /// let c = a.and(b); + /// + /// assert!(!c.filter(&1).unwrap()); + /// assert!(c.filter(&3).unwrap()); + /// assert!(c.filter(&4).unwrap()); + /// assert!(c.filter(&6).unwrap()); + /// assert!(!c.filter(&9).unwrap()); + /// ``` + fn map_err(self, map: M) -> FailableMapErr + where Self: Sized, + M: Fn(E) -> OE + { + FailableMapErr::new(self, map) + } + } /// All closures that take a ref to something and return Result are failable filters diff --git a/src/failable/ops/map.rs b/src/failable/ops/map.rs new file mode 100644 index 0000000..8e1155c --- /dev/null +++ b/src/failable/ops/map.rs @@ -0,0 +1,58 @@ +// +// 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/. +// + +//! Map implementation. +//! +//! Will be automatically included when incluing `filter::Filter`, so importing this module +//! shouldn't be necessary. +//! +use std::marker::PhantomData; +use std::borrow::Borrow; +use std::error::Error; + +use failable::filter::FailableFilter; + +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct FailableMapInput(F, M, PhantomData, PhantomData); + +impl FailableMapInput { + pub fn new(a: F, m: M) -> FailableMapInput { + FailableMapInput(a, m, PhantomData, PhantomData) + } +} + +impl FailableFilter for FailableMapInput + where E: Error, + F: FailableFilter, + B: Borrow + Sized, + M: Fn(&T) -> B +{ + fn filter(&self, e: &T) -> Result { + self.0.filter(self.1(e).borrow()) + } +} + +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct FailableMapErr(F, M, PhantomData, PhantomData); + +impl FailableMapErr { + pub fn new(a: F, m: M) -> FailableMapErr { + FailableMapErr(a, m, PhantomData, PhantomData) + } +} + +impl FailableFilter for FailableMapErr + where E: Error, + FE: Error, + F: FailableFilter, + M: Fn(FE) -> E +{ + fn filter(&self, e: &T) -> Result { + self.0.filter(e).map_err(&self.1) + } +} diff --git a/src/failable/ops/mod.rs b/src/failable/ops/mod.rs index feaad07..618c0e8 100644 --- a/src/failable/ops/mod.rs +++ b/src/failable/ops/mod.rs @@ -9,3 +9,4 @@ pub mod bool; pub mod not; pub mod xor; pub mod or; +pub mod map; diff --git a/src/filter.rs b/src/filter.rs index ac0d7b1..d2748bd 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -6,12 +6,14 @@ //! The filter implementation //! +use std::borrow::Borrow; pub use ops::and::And; pub use ops::bool::Bool; pub use ops::not::Not; pub use ops::xor::XOr; pub use ops::or::Or; +pub use ops::map::MapInput; /// Trait for converting something into a Filter pub trait IntoFilter { @@ -36,7 +38,7 @@ impl bool> Filter for T { } } -/// The filter trai +/// The filter trait pub trait Filter { /// The function which is used to filter something @@ -256,6 +258,29 @@ pub trait Filter { Not::new(And::new(self, other)) } + /// Helper to transform the input of a filter + /// + /// ``` + /// use filters::filter::Filter; + /// + /// let a = (|&a: &usize| { a > 1 }); + /// let b = (|&a: &i64| { a < 7 }); + /// let b = b.map_input(|&x: &usize| { x as i64 }); + /// 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 map_input(self, map: M) -> MapInput + where Self: Sized, + M: Fn(&T) -> N, + B: Borrow + Sized + { + MapInput::new(self, map) + } } diff --git a/src/ops/map.rs b/src/ops/map.rs new file mode 100644 index 0000000..b7a2028 --- /dev/null +++ b/src/ops/map.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/. +// + +//! Map implementation. +//! +//! Will be automatically included when incluing `filter::Filter`, so importing this module +//! shouldn't be necessary. +//! +use std::marker::PhantomData; +use std::borrow::Borrow; + +use filter::Filter; + +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct MapInput(F, M, PhantomData, PhantomData); + +impl MapInput { + pub fn new(a: F, m: M) -> MapInput { + MapInput(a, m, PhantomData, PhantomData) + } +} + +impl Filter for MapInput + where F: Filter, + B: Borrow + Sized, + M: Fn(&T) -> B +{ + fn filter(&self, e: &T) -> bool { + self.0.filter(self.1(e).borrow()) + } +} diff --git a/src/ops/mod.rs b/src/ops/mod.rs index d152cce..a5dd6b6 100644 --- a/src/ops/mod.rs +++ b/src/ops/mod.rs @@ -9,3 +9,4 @@ pub mod bool; pub mod not; pub mod or; pub mod xor; +pub mod map; -- cgit v1.2.3