summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDawid Ciężarkiewicz <dpc@dpc.pw>2018-11-30 10:19:56 -0800
committerGitHub <noreply@github.com>2018-11-30 10:19:56 -0800
commit647f699ce8bd1a0f4c853b492b017a196e89c7ca (patch)
tree578166891eab576c7e85f51fe586a2529a1bf076
parentece8776398d9e6a43069c5fa1cfe1b4137c84109 (diff)
parente02a1d3319762350eb984eaaf545e96413ad4957 (diff)
Merge pull request #12 from dpc/reexport
Reexport
-rw-r--r--src/and_then_x.rs106
-rw-r--r--src/filter_map_x.rs148
-rw-r--r--src/flat_map_x.rs150
-rw-r--r--src/flatten_x.rs144
-rw-r--r--src/lib.rs18
-rw-r--r--src/prelude.rs1
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)
+ ]
+ );
+}
diff --git a/src/lib.rs b/src/lib.rs
index 42bab55..ab7f16e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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::*;
-