diff options
author | Dawid Ciężarkiewicz <dpc@dpc.pw> | 2018-11-30 10:19:56 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-30 10:19:56 -0800 |
commit | 647f699ce8bd1a0f4c853b492b017a196e89c7ca (patch) | |
tree | 578166891eab576c7e85f51fe586a2529a1bf076 | |
parent | ece8776398d9e6a43069c5fa1cfe1b4137c84109 (diff) | |
parent | e02a1d3319762350eb984eaaf545e96413ad4957 (diff) |
Merge pull request #12 from dpc/reexport
Reexport
-rw-r--r-- | src/and_then_x.rs | 106 | ||||
-rw-r--r-- | src/filter_map_x.rs | 148 | ||||
-rw-r--r-- | src/flat_map_x.rs | 150 | ||||
-rw-r--r-- | src/flatten_x.rs | 144 | ||||
-rw-r--r-- | src/lib.rs | 18 | ||||
-rw-r--r-- | src/prelude.rs | 1 |
6 files changed, 566 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))); +} diff --git a/src/flat_map_x.rs b/src/flat_map_x.rs new file mode 100644 index 0000000..d6cf4a8 --- /dev/null +++ b/src/flat_map_x.rs @@ -0,0 +1,150 @@ +// +// 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 FlatMapX<O, E>: Sized { + fn flat_map_ok<U, F, O2>(self, F) -> FlatMapOk<Self, U, F> + where + F: FnMut(O) -> U, + U: IntoIterator<Item = O2>; + fn flat_map_err<U, F, E2>(self, F) -> FlatMapErr<Self, U, F> + where + F: FnMut(E) -> U, + U: IntoIterator<Item = E2>; +} + +impl<I, O, E> FlatMapX<O, E> for I +where + I: Iterator<Item = Result<O, E>> + Sized, +{ + fn flat_map_ok<U, F, O2>(self, f: F) -> FlatMapOk<Self, U, F> + where + F: FnMut(O) -> U, + U: IntoIterator<Item = O2>, + { + FlatMapOk { + frontiter: None, + iter: self, + f, + } + } + fn flat_map_err<U, F, E2>(self, f: F) -> FlatMapErr<Self, U, F> + where + F: FnMut(E) -> U, + U: IntoIterator<Item = E2>, + { + FlatMapErr { + frontiter: None, + iter: self, + f, + } + } +} + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct FlatMapOk<I, U, F> +where + U: IntoIterator, +{ + frontiter: Option<<U as IntoIterator>::IntoIter>, + iter: I, + f: F, +} + +impl<I, O, E, F, O2, U> Iterator for FlatMapOk<I, U, F> +where + I: Iterator<Item = Result<O, E>>, + F: FnMut(O) -> U, + U: IntoIterator<Item = O2>, +{ + type Item = Result<O2, E>; + + fn next(&mut self) -> Option<Self::Item> { + loop { + if let Some(ref mut inner) = self.frontiter { + if let elt @ Some(_) = inner.next() { + return elt.map(Ok); + } + } + match self.iter.next() { + None => return None, + Some(Ok(x)) => { + self.frontiter = Some((self.f)(x).into_iter()); + } + Some(Err(e)) => return Some(Err(e)), + } + } + } + + #[inline] + // TODO: Oh dear, this hint could be much better + // https://doc.rust-lang.org/src/core/iter/mod.rs.html#2694 + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct FlatMapErr<I, U: IntoIterator, F> { + frontiter: Option<<U as IntoIterator>::IntoIter>, + iter: I, + f: F, +} + +impl<I, O, E, F, E2, U> Iterator for FlatMapErr<I, U, F> +where + I: Iterator<Item = Result<O, E>>, + F: FnMut(E) -> U, + U: IntoIterator<Item = E2>, +{ + type Item = Result<O, E2>; + + fn next(&mut self) -> Option<Self::Item> { + loop { + if let Some(ref mut inner) = self.frontiter { + if let elt @ Some(_) = inner.next() { + return elt.map(Err); + } + } + match self.iter.next() { + None => return None, + Some(Err(e)) => { + self.frontiter = Some((self.f)(e).into_iter()); + } + Some(Ok(o)) => return Some(Ok(o)), + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +#[test] +fn test_flat_map_ok() { + let mapped: Vec<_> = vec![Ok(1), Ok(2), Err(2), Err(0), Ok(2)] + .into_iter() + .flat_map_ok(|i| (0..i)) + .flat_map_err(|i| 0..(i * 2)) + .collect(); + + assert_eq!( + mapped, + [ + Ok(0), + Ok(0), + Ok(1), + Err(0), + Err(1), + Err(2), + Err(3), + Ok(0), + Ok(1) + ] + ); +} diff --git a/src/flatten_x.rs b/src/flatten_x.rs new file mode 100644 index 0000000..db8dbd8 --- /dev/null +++ b/src/flatten_x.rs @@ -0,0 +1,144 @@ +// +// 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 FlattenX<O, E>: Sized { + fn flatten_ok<U, O2>(self) -> FlattenOk<Self, U> + where + U: IntoIterator<Item = O2>; + fn flatten_err<U, E2>(self) -> FlattenErr<Self, U> + where + U: IntoIterator<Item = E2>; +} + +impl<I, O, E> FlattenX<O, E> for I +where + I: Iterator<Item = Result<O, E>> + Sized, +{ + fn flatten_ok<U, O2>(self) -> FlattenOk<Self, U> + where + U: IntoIterator<Item = O2>, + { + FlattenOk { + frontiter: None, + iter: self, + } + } + fn flatten_err<U, E2>(self) -> FlattenErr<Self, U> + where + U: IntoIterator<Item = E2>, + { + FlattenErr { + frontiter: None, + iter: self, + } + } +} + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct FlattenOk<I, U> +where + U: IntoIterator, +{ + frontiter: Option<<U as IntoIterator>::IntoIter>, + iter: I, +} + +impl<I, E, O2, U> Iterator for FlattenOk<I, U> +where + I: Iterator<Item = Result<U, E>>, + U: IntoIterator<Item = O2>, +{ + type Item = Result<O2, E>; + + fn next(&mut self) -> Option<Self::Item> { + loop { + if let Some(ref mut inner) = self.frontiter { + if let elt @ Some(_) = inner.next() { + return elt.map(Ok); + } + } + match self.iter.next() { + None => return None, + Some(Ok(x)) => { + self.frontiter = Some(x.into_iter()); + } + Some(Err(e)) => return Some(Err(e)), + } + } + } + + #[inline] + // TODO: Oh dear, this hint could be much better + // https://doc.rust-lang.org/src/core/iter/mod.rs.html#2694 + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct FlattenErr<I, U: IntoIterator> { + frontiter: Option<<U as IntoIterator>::IntoIter>, + iter: I, +} + +impl<I, O, E2, U> Iterator for FlattenErr<I, U> +where + I: Iterator<Item = Result<O, U>>, + U: IntoIterator<Item = E2>, +{ + type Item = Result<O, E2>; + + fn next(&mut self) -> Option<Self::Item> { + loop { + if let Some(ref mut inner) = self.frontiter { + if let elt @ Some(_) = inner.next() { + return elt.map(Err); + } + } + match self.iter.next() { + None => return None, + Some(Err(e)) => { + self.frontiter = Some(e.into_iter()); + } + Some(Ok(o)) => return Some(Ok(o)), + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +#[test] +fn test_flatten_ok() { + use map_x::MapX; + + let mapped: Vec<_> = vec![Ok(1), Ok(2), Err(2), Err(0), Ok(2)] + .into_iter() + .map_ok(|i| (0..i)) + .map_err(|i| 0..(i * 2)) + .flatten_ok() + .flatten_err() + .collect(); + + assert_eq!( + mapped, + [ + Ok(0), + Ok(0), + Ok(1), + Err(0), + Err(1), + Err(2), + Err(3), + Ok(0), + Ok(1) + ] + ); +} @@ -194,8 +194,12 @@ //! 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; pub mod map_x; pub mod oks; pub mod onerr; @@ -204,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::*; - |