diff options
-rw-r--r-- | src/filter_x.rs | 150 | ||||
-rw-r--r-- | src/lib.rs | 90 | ||||
-rw-r--r-- | src/map_x.rs | 131 | ||||
-rw-r--r-- | src/while_ok.rs | 57 |
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))); +} @@ -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()); +} |