summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2018-10-09 19:44:31 +0200
committerGitHub <noreply@github.com>2018-10-09 19:44:31 +0200
commit99192b13f2e8be1197f2757f396d64b1b56198f9 (patch)
tree6afe73d94b78cf36d92e9d029eacbc5783ecfeb1
parent8328b849cf8523bf931a4415c10823c48654b129 (diff)
parent453ded73931017b140b1c79094636a1154b12fc8 (diff)
Merge pull request #3 from pchampin/new_traits
added map_x and while_ok
-rw-r--r--src/filter_x.rs150
-rw-r--r--src/lib.rs90
-rw-r--r--src/map_x.rs131
-rw-r--r--src/while_ok.rs57
4 files changed, 427 insertions, 1 deletions
diff --git a/src/filter_x.rs b/src/filter_x.rs
new file mode 100644
index 0000000..8634686
--- /dev/null
+++ b/src/filter_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 filter one kind of result (and leaving the other as is)
+pub trait FilterX<O, E> : Sized
+{
+ fn filter_ok<F>(self, F) -> FilterOk<Self, F>
+ where F: FnMut(&O) -> bool;
+ fn filter_err<F>(self, F) -> FilterErr<Self, F>
+ where F: FnMut(&E) -> bool;
+}
+
+impl<I, O, E> FilterX<O, E> for I
+ where I: Iterator<Item = Result<O, E>> + Sized,
+{
+ fn filter_ok<F>(self, f: F) -> FilterOk<Self, F>
+ where F: FnMut(&O) -> bool
+ {
+ FilterOk{ iter: self, f }
+ }
+ fn filter_err<F>(self, f: F) -> FilterErr<Self, F>
+ where F: FnMut(&E) -> bool
+ {
+ FilterErr{ iter: self, f }
+ }
+}
+
+
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+pub struct FilterOk<I, F> {
+ iter: I,
+ f: F,
+}
+
+impl<I, O, E, F> Iterator for FilterOk<I, F>
+ where I: Iterator<Item = Result<O, E>>,
+ F: FnMut(&O) -> bool,
+{
+ type Item = Result<O, E>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ match self.iter.next() {
+ Some(Ok(x)) => {
+ if (self.f)(&x) {
+ return Some(Ok(x));
+ }
+ }
+ other => { return other; }
+ }
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let hint_sup = self.iter.size_hint().1;
+ (0, hint_sup)
+ }
+}
+
+
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+pub struct FilterErr<I, F> {
+ iter: I,
+ f: F,
+}
+
+impl<I, O, E, F> Iterator for FilterErr<I, F>
+ where I: Iterator<Item = Result<O, E>>,
+ F: FnMut(&E) -> bool,
+{
+ type Item = Result<O, E>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ match self.iter.next() {
+ Some(Err(x)) => {
+ if (self.f)(&x) {
+ return Some(Err(x));
+ }
+ }
+ other => { return other; }
+ }
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let hint_sup = self.iter.size_hint().1;
+ (0, hint_sup)
+ }
+}
+
+
+#[test]
+fn test_filter_ok() {
+ use std::str::FromStr;
+
+ let mapped: Vec<_> = ["1", "2", "a", "4", "5"]
+ .into_iter()
+ .map(|txt| usize::from_str(txt))
+ .filter_ok(|i| i%2 == 0)
+ .collect();
+
+ assert_eq!(mapped.len(), 3);
+ assert_eq!(mapped[0], Ok(2));
+ assert_eq!(mapped[2], Ok(4));
+}
+
+#[test]
+fn test_filter_ok_hint() {
+ use std::str::FromStr;
+
+ let hint = ["1", "2", "a", "4", "5"]
+ .into_iter()
+ .map(|txt| usize::from_str(txt))
+ .filter_ok(|i| i%2 == 0)
+ .size_hint();
+
+ assert_eq!(hint, (0, Some(5)));
+}
+
+#[test]
+fn test_filter_err() {
+ use std::str::FromStr;
+
+ let mapped: Vec<_> = ["1", "2", "a", "4", "5"]
+ .into_iter()
+ .map(|txt| usize::from_str(txt))
+ .filter_err(|_| false)
+ .collect();
+
+ assert_eq!(mapped, vec![Ok(1), Ok(2), Ok(4), Ok(5)]);
+}
+
+#[test]
+fn test_filter_err_hint() {
+ use std::str::FromStr;
+
+ let hint = ["1", "2", "a", "4", "5"]
+ .into_iter()
+ .map(|txt| usize::from_str(txt))
+ .filter_err(|_| false)
+ .size_hint();
+
+ assert_eq!(hint, (0, Some(5)));
+}
diff --git a/src/lib.rs b/src/lib.rs
index f8fb768..42bab55 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -103,16 +103,104 @@
//! # }
//! ```
//!
+//! * Transforming oks
+//!
+//! ```
+//! # fn main() {
+//! use std::str::FromStr;
+//! use resiter::map_x::*;
+//!
+//! let doubles = ["1", "2", "foo", "4", "5"]
+//! .into_iter()
+//! .map(|e| usize::from_str(e))
+//! .map_ok(|i| 2*i)
+//! .collect::<Vec<_>>();
+//! assert_eq!(doubles[0], Ok(2));
+//! assert_eq!(doubles[1], Ok(4));
+//! # }
+//! ```
+//!
+//! * Transforming errors
+//!
+//! ```
+//! # fn main() {
+//! use std::str::FromStr;
+//! use resiter::map_x::*;
+//!
+//! let doubles = ["1", "2", "foo", "4", "5"]
+//! .into_iter()
+//! .map(|e| usize::from_str(e))
+//! .map_err(|e| format!("{:?}", e))
+//! .collect::<Vec<_>>();
+//! assert_eq!(doubles[2], Err("ParseIntError { kind: InvalidDigit }".to_string()));
+//! # }
+//! ```
+//!
+//! * Filtering oks (leaving errors as is)
+//!
+//! ```
+//! # fn main() {
+//! use std::str::FromStr;
+//! use resiter::filter_x::*;
+//!
+//! let doubles = ["1", "2", "foo", "4", "5"]
+//! .into_iter()
+//! .map(|e| usize::from_str(e))
+//! .filter_ok(|i| i%2 == 0)
+//! .collect::<Vec<_>>();
+//! assert_eq!(doubles.len(), 3);
+//! assert_eq!(doubles[0], Ok(2));
+//! # }
+//! ```
+//!
+//! * Filtering errors (leaving oks as is)
+//!
+//! ```
+//! # fn main() {
+//! use std::str::FromStr;
+//! use resiter::filter_x::*;
+//!
+//! let doubles = ["1", "2", "foo", "4", "5"]
+//! .into_iter()
+//! .map(|e| usize::from_str(e))
+//! .filter_err(|_| false) // filter out all errors
+//! .collect::<Vec<_>>();
+//! assert_eq!(doubles.len(), 4);
+//! assert_eq!(doubles[2], Ok(4));
+//! # }
+//! ```
+//!
+//! * Stopping the iteration on the first error
+//!
+//! ```
+//! # fn main() -> () {
+//! use std::str::FromStr;
+//! use resiter::while_ok::*;
+//!
+//! let res = ["1", "2", "foo", "4", "5"]
+//! .into_iter()
+//! .map(|e| usize::from_str(e))
+//! .while_ok(|i| {
+//! println!("{} is a usize", i);
+//! });
+//! if res.is_err() {
+//! println!("An error occured");
+//! }
+//! # }
+//! ```
+//!
//! # License
//!
//! MPL 2.0
//!
pub mod errors;
+pub mod filter_x;
+pub mod map_x;
pub mod oks;
pub mod onerr;
pub mod onok;
pub mod prelude;
pub mod unwrap;
mod util;
-
+pub mod while_ok;
diff --git a/src/map_x.rs b/src/map_x.rs
new file mode 100644
index 0000000..e6a4643
--- /dev/null
+++ b/src/map_x.rs
@@ -0,0 +1,131 @@
+//
+// 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 MapX<O, E> : Sized
+{
+ fn map_ok<F, O2>(self, F) -> MapOk<Self, F>
+ where F: FnMut(O) -> O2;
+ fn map_err<F, E2>(self, F) -> MapErr<Self, F>
+ where F: FnMut(E) -> E2;
+}
+
+impl<I, O, E> MapX<O, E> for I
+ where I: Iterator<Item = Result<O, E>> + Sized,
+{
+ fn map_ok<F, O2>(self, f: F) -> MapOk<Self, F>
+ where F: FnMut(O) -> O2
+ {
+ MapOk{ iter: self, f }
+ }
+ fn map_err<F, E2>(self, f: F) -> MapErr<Self, F>
+ where F: FnMut(E) -> E2
+ {
+ MapErr{ iter: self, f }
+ }
+}
+
+
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+pub struct MapOk<I, F> {
+ iter: I,
+ f: F,
+}
+
+impl<I, O, E, F, O2> Iterator for MapOk<I, F>
+ where I: Iterator<Item = Result<O, E>>,
+ F: FnMut(O) -> O2,
+{
+ type Item = Result<O2, E>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|r| r.map(&mut self.f))
+ }
+
+ #[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 MapErr<I, F> {
+ iter: I,
+ f: F,
+}
+
+impl<I, O, E, F, E2> Iterator for MapErr<I, F>
+ where I: Iterator<Item = Result<O, E>>,
+ F: FnMut(E) -> E2,
+{
+ type Item = Result<O, E2>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.iter.next().map(|r| r.map_err(&mut self.f))
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+
+#[test]
+fn test_map_ok() {
+ use std::str::FromStr;
+
+ let mapped: Vec<_> = ["1", "2", "a", "4", "5"]
+ .into_iter()
+ .map(|txt| usize::from_str(txt))
+ .map_ok(|i| 2*i)
+ .collect();
+
+ assert_eq!(mapped[0], Ok(2));
+ assert_eq!(mapped[1], Ok(4));
+ assert_eq!(mapped[3], Ok(8));
+ assert_eq!(mapped[4], Ok(10));
+}
+
+#[test]
+fn test_map_ok_hint() {
+ use std::str::FromStr;
+
+ let hint = ["1", "2", "a", "4", "5"]
+ .into_iter()
+ .map(|txt| usize::from_str(txt))
+ .map_ok(|i| 2*i)
+ .size_hint();
+
+ assert_eq!(hint, (5, Some(5)));
+}
+
+#[test]
+fn test_map_err() {
+ use std::str::FromStr;
+
+ let mapped: Vec<_> = ["1", "2", "a", "4", "5"]
+ .into_iter()
+ .map(|txt| usize::from_str(txt))
+ .map_err(|e| format!("{:?}", e))
+ .collect();
+
+ assert_eq!(mapped[2], Err("ParseIntError { kind: InvalidDigit }".to_string()));
+}
+
+#[test]
+fn test_map_err_hint() {
+ use std::str::FromStr;
+
+ let hint = ["1", "2", "a", "4", "5"]
+ .into_iter()
+ .map(|txt| usize::from_str(txt))
+ .map_err(|e| format!("{:?}", e))
+ .size_hint();
+
+ assert_eq!(hint, (5, Some(5)));
+}
diff --git a/src/while_ok.rs b/src/while_ok.rs
new file mode 100644
index 0000000..ef5c03f
--- /dev/null
+++ b/src/while_ok.rs
@@ -0,0 +1,57 @@
+//
+// 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 iter until an error is encountered.
+pub trait WhileOk<O, E>
+{
+ fn while_ok<F>(self, F) -> Result<(), E>
+ where F: FnMut(O) -> ();
+}
+
+impl<I, O, E> WhileOk<O, E> for I
+ where I: Iterator<Item = Result<O, E>>,
+{
+ fn while_ok<F>(self, mut f: F) -> Result<(), E>
+ where F: FnMut(O) -> ()
+ {
+ for res in self {
+ f(res?);
+ }
+ Ok(())
+ }
+}
+
+
+
+#[test]
+fn test_while_ok_ok() {
+ use std::str::FromStr;
+
+ let mut s = 0;
+
+ let res = ["1", "2", "3", "4", "5"]
+ .into_iter()
+ .map(|txt| usize::from_str(txt))
+ .while_ok(|i| s += i);
+
+ assert_eq!(s, 15);
+ assert!(res.is_ok());
+}
+
+#[test]
+fn test_while_ok_err() {
+ use std::str::FromStr;
+
+ let mut s = 0;
+
+ let res = ["1", "2", "a", "4", "5"]
+ .into_iter()
+ .map(|txt| usize::from_str(txt))
+ .while_ok(|i| s += i);
+
+ assert_eq!(s, 3);
+ assert!(res.is_err());
+}