diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2017-10-03 10:20:58 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-03 10:20:58 +0200 |
commit | bdc2c062c2632fd6e0f9be4113b239f1cf84f0b9 (patch) | |
tree | e1573c1dd5e95e3217b2d5c2848b92ea267bc9fe /src | |
parent | f80413b5a481badd19a5ccd09f1d071498228781 (diff) | |
parent | a8d0c99d991889125340c5e09c32bae8776189b9 (diff) |
Merge pull request #21 from PlasmaPower/filter-map
Add filter map functions
Diffstat (limited to 'src')
-rw-r--r-- | src/failable/filter.rs | 76 | ||||
-rw-r--r-- | src/failable/ops/map.rs | 58 | ||||
-rw-r--r-- | src/failable/ops/mod.rs | 1 | ||||
-rw-r--r-- | src/filter.rs | 27 | ||||
-rw-r--r-- | src/ops/map.rs | 35 | ||||
-rw-r--r-- | src/ops/mod.rs | 1 |
6 files changed, 197 insertions, 1 deletions
diff --git a/src/failable/filter.rs b/src/failable/filter.rs index de49512..af08fbb 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<N, E: Error + Sized> { @@ -376,6 +378,80 @@ pub trait FailableFilter<N, E: Error> { 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<bool, ErrorStub> { Ok(a > 1) }); + /// let b = (|&a: &i64| -> Result<bool, ErrorStub> { 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<O, B, T, M>(self, map: M) -> FailableMapInput<Self, M, O, B> + where Self: Sized, + M: Fn(&T) -> N, + B: Borrow<O> + 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<bool, ErrorStub> { Ok(a > 1) }); + /// let b = (|&a: &usize| -> Result<bool, fmt::Error> { 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<M, OE>(self, map: M) -> FailableMapErr<Self, M, E, OE> + where Self: Sized, + M: Fn(E) -> OE + { + FailableMapErr::new(self, map) + } + } /// All closures that take a ref to something and return Result<bool, E> 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, FT, B>(F, M, PhantomData<FT>, PhantomData<B>); + +impl<F, M, FT, B> FailableMapInput<F, M, FT, B> { + pub fn new(a: F, m: M) -> FailableMapInput<F, M, FT, B> { + FailableMapInput(a, m, PhantomData, PhantomData) + } +} + +impl<FT, E, F, T, B, M> FailableFilter<T, E> for FailableMapInput<F, M, FT, B> + where E: Error, + F: FailableFilter<FT, E>, + B: Borrow<FT> + Sized, + M: Fn(&T) -> B +{ + fn filter(&self, e: &T) -> Result<bool, E> { + self.0.filter(self.1(e).borrow()) + } +} + +#[must_use = "filters are lazy and do nothing unless consumed"] +#[derive(Clone)] +pub struct FailableMapErr<F, M, FE, E>(F, M, PhantomData<FE>, PhantomData<E>); + +impl<F, M, FE, E> FailableMapErr<F, M, FE, E> { + pub fn new(a: F, m: M) -> FailableMapErr<F, M, FE, E> { + FailableMapErr(a, m, PhantomData, PhantomData) + } +} + +impl<FE, E, F, T, M> FailableFilter<T, E> for FailableMapErr<F, M, FE, E> + where E: Error, + FE: Error, + F: FailableFilter<T, FE>, + M: Fn(FE) -> E +{ + fn filter(&self, e: &T) -> Result<bool, E> { + 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<N> { @@ -36,7 +38,7 @@ impl<I, T: Fn(&I) -> bool> Filter<I> for T { } } -/// The filter trai +/// The filter trait pub trait Filter<N> { /// The function which is used to filter something @@ -256,6 +258,29 @@ pub trait Filter<N> { 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<O, B, T, M>(self, map: M) -> MapInput<Self, M, O, B> + where Self: Sized, + M: Fn(&T) -> N, + B: Borrow<O> + 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, FT, B>(F, M, PhantomData<FT>, PhantomData<B>); + +impl<F, M, FT, B> MapInput<F, M, FT, B> { + pub fn new(a: F, m: M) -> MapInput<F, M, FT, B> { + MapInput(a, m, PhantomData, PhantomData) + } +} + +impl<FT, F, T, B, M> Filter<T> for MapInput<F, M, FT, B> + where F: Filter<FT>, + B: Borrow<FT> + 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; |