diff options
-rw-r--r-- | src/and_then_x.rs | 106 | ||||
-rw-r--r-- | src/filter_map_x.rs | 148 | ||||
-rw-r--r-- | src/lib.rs | 16 | ||||
-rw-r--r-- | src/prelude.rs | 1 |
4 files changed, 270 insertions, 1 deletions
diff --git a/src/and_then_x.rs b/src/and_then_x.rs new file mode 100644 index 0000000..865dd26 --- /dev/null +++ b/src/and_then_x.rs @@ -0,0 +1,106 @@ +// +// 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/. +// + +/// Extension trait for `Iterator<Item = Result<O, E>>` to selectively transform Oks and Errors. +pub trait AndThenX<O, E>: Sized { + fn and_then_ok<F, O2>(self, F) -> AndThenOk<Self, F> + where + F: FnMut(O) -> Result<O2, E>; + fn and_then_err<F, E2>(self, F) -> AndThenErr<Self, F> + where + F: FnMut(E) -> Result<O, E2>; +} + +impl<I, O, E> AndThenX<O, E> for I +where + I: Iterator<Item = Result<O, E>> + Sized, +{ + fn and_then_ok<F, O2>(self, f: F) -> AndThenOk<Self, F> + where + F: FnMut(O) -> Result<O2, E>, + { + AndThenOk { iter: self, f } + } + fn and_then_err<F, E2>(self, f: F) -> AndThenErr<Self, F> + where + F: FnMut(E) -> Result<O, E2>, + { + AndThenErr { iter: self, f } + } +} + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct AndThenOk<I, F> { + iter: I, + f: F, +} + +impl<I, O, E, O2, F> Iterator for AndThenOk<I, F> +where + I: Iterator<Item = Result<O, E>>, + F: FnMut(O) -> Result<O2, E>, +{ + type Item = Result<O2, E>; + + fn next(&mut self) -> Option<Self::Item> { + match self.iter.next() { + Some(Ok(o)) => Some((self.f)(o)), + Some(Err(e)) => Some(Err(e)), + None => None, + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct AndThenErr<I, F> { + iter: I, + f: F, +} + +impl<I, O, E, E2, F> Iterator for AndThenErr<I, F> +where + I: Iterator<Item = Result<O, E>>, + F: FnMut(E) -> Result<O, E2>, +{ + type Item = Result<O, E2>; + + fn next(&mut self) -> Option<Self::Item> { + match self.iter.next() { + Some(Err(e)) => Some((self.f)(e)), + Some(Ok(o)) => Some(Ok(o)), + None => None, + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +#[test] +fn test_and_then_ok() { + use std::str::FromStr; + + let mapped: Vec<_> = ["1", "2", "a", "b", "4", "5"] + .into_iter() + .map(|txt| usize::from_str(txt).map_err(|e| (txt, e))) + .and_then_ok(|i| Ok(2 * i)) + .and_then_err(|(txt, e)| if txt == &"a" { Ok(15) } else { Err(e) }) + .collect(); + + assert_eq!(mapped[0], Ok(2)); + assert_eq!(mapped[1], Ok(4)); + assert_eq!(mapped[2], Ok(15)); + assert!(mapped[3].is_err()); + assert_eq!(mapped[4], Ok(8)); + assert_eq!(mapped[5], Ok(10)); +} diff --git a/src/filter_map_x.rs b/src/filter_map_x.rs new file mode 100644 index 0000000..e2a686b --- /dev/null +++ b/src/filter_map_x.rs @@ -0,0 +1,148 @@ +// +// 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/. +// + +/// Extension trait for `Iterator<Item = Result<O, E>>` to selectively transform and map Oks and Errors. +pub trait FilterMapX<O, E>: Sized { + fn filter_map_ok<F, O2>(self, F) -> FilterMapOk<Self, F> + where + F: FnMut(O) -> Option<O2>; + fn filter_map_err<F, E2>(self, F) -> FilterMapErr<Self, F> + where + F: FnMut(E) -> Option<E2>; +} + +impl<I, O, E> FilterMapX<O, E> for I +where + I: Iterator<Item = Result<O, E>> + Sized, +{ + fn filter_map_ok<F, O2>(self, f: F) -> FilterMapOk<Self, F> + where + F: FnMut(O) -> Option<O2>, + { + FilterMapOk { iter: self, f } + } + fn filter_map_err<F, E2>(self, f: F) -> FilterMapErr<Self, F> + where + F: FnMut(E) -> Option<E2>, + { + FilterMapErr { iter: self, f } + } +} + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct FilterMapOk<I, F> { + iter: I, + f: F, +} + +impl<I, O, E, F, O2> Iterator for FilterMapOk<I, F> +where + I: Iterator<Item = Result<O, E>>, + F: FnMut(O) -> Option<O2>, +{ + type Item = Result<O2, E>; + + fn next(&mut self) -> Option<Self::Item> { + loop { + match self.iter.next() { + Some(Ok(x)) => { + if let Some(x) = (self.f)(x) { + return Some(Ok(x)); + } + } + Some(Err(e)) => return Some(Err(e)), + None => return None, + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct FilterMapErr<I, F> { + iter: I, + f: F, +} + +impl<I, O, E, F, E2> Iterator for FilterMapErr<I, F> +where + I: Iterator<Item = Result<O, E>>, + F: FnMut(E) -> Option<E2>, +{ + type Item = Result<O, E2>; + + fn next(&mut self) -> Option<Self::Item> { + loop { + match self.iter.next() { + Some(Ok(x)) => return Some(Ok(x)), + Some(Err(e)) => { + if let Some(e) = (self.f)(e) { + return Some(Err(e)); + } + } + None => return None, + } + } + } + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +#[test] +fn test_filter_map_ok() { + use std::str::FromStr; + + let filter_mapped: Vec<_> = vec![ + Ok("1"), + Err("2"), + Ok("a"), + Err("4"), + Ok("5"), + Err("b"), + Err("8"), + ].into_iter() + .filter_map_ok(|txt| usize::from_str(txt).ok()) + .filter_map_err(|txt| usize::from_str(txt).ok().map(|i| i * 3)) + .collect(); + + assert_eq!(filter_mapped[0], Ok(1)); + assert_eq!(filter_mapped[1], Err(2 * 3)); + assert_eq!(filter_mapped[2], Err(4 * 3)); + assert_eq!(filter_mapped[3], Ok(5)); + assert_eq!(filter_mapped[4], Err(8 * 3)); +} + +#[test] +fn test_filter_map_ok_hint() { + use std::str::FromStr; + + let hint = ["1", "2", "a", "4", "5"] + .into_iter() + .map(|txt| usize::from_str(txt)) + .filter_map_ok(|i| Some(2 * i)) + .size_hint(); + + assert_eq!(hint, (5, Some(5))); +} + +#[test] +fn test_filter_map_err_hint() { + use std::str::FromStr; + + let hint = ["1", "2", "a", "4", "5"] + .into_iter() + .map(|txt| usize::from_str(txt)) + .filter_map_err(|e| Some(format!("{:?}", e))) + .size_hint(); + + assert_eq!(hint, (5, Some(5))); +} @@ -194,7 +194,9 @@ //! MPL 2.0 //! +pub mod and_then_x; pub mod errors; +pub mod filter_map_x; pub mod filter_x; pub mod flat_map_x; pub mod flatten_x; @@ -206,3 +208,17 @@ pub mod prelude; pub mod unwrap; mod util; pub mod while_ok; + +pub use and_then_x::AndThenX; +pub use errors::GetErrors; +pub use filter_map_x::FilterMapX; +pub use filter_x::FilterX; +pub use flat_map_x::FlatMapX; +pub use flatten_x::FlattenX; +pub use map_x::MapX; +pub use oks::GetOks; +pub use onerr::OnErrDo; +pub use onok::OnOkDo; +pub use unwrap::UnwrapWithExt; +pub use util::{GetErr, GetOk, Process}; +pub use while_ok::WhileOk; diff --git a/src/prelude.rs b/src/prelude.rs index 0926f24..01cfea7 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -14,4 +14,3 @@ pub use oks::*; pub use onerr::*; pub use onok::*; pub use unwrap::*; - |