From d4eb9928f18e9c4e96b0c47b8452ac3d373feb0b Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Champin Date: Mon, 8 Oct 2018 13:35:16 +0200 Subject: added map_x and while_ok --- src/lib.rs | 2 + src/map_x.rs | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/while_ok.rs | 57 ++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 src/map_x.rs create mode 100644 src/while_ok.rs diff --git a/src/lib.rs b/src/lib.rs index f8fb768..d949faa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -109,10 +109,12 @@ //! pub mod errors; +pub mod map_x; pub mod oks; pub mod onerr; pub mod onok; pub mod prelude; pub mod unwrap; +pub mod while_ok; mod util; diff --git a/src/map_x.rs b/src/map_x.rs new file mode 100644 index 0000000..a328dd1 --- /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>` to iter until an error is encountered. +pub trait MapX : Sized +{ + fn map_ok(self, F) -> MapOk + where F: FnMut(O) -> O2; + fn map_err(self, F) -> MapErr + where F: FnMut(E) -> E2; +} + +impl MapX for I + where I: Iterator> + Sized, +{ + fn map_ok(self, f: F) -> MapOk + where F: FnMut(O) -> O2 + { + MapOk{ iter: self, f } + } + fn map_err(self, f: F) -> MapErr + where F: FnMut(E) -> E2 + { + MapErr{ iter: self, f } + } +} + + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct MapOk { + iter: I, + f: F, +} + +impl Iterator for MapOk + where I: Iterator>, + F: FnMut(O) -> O2, +{ + type Item = Result; + + fn next(&mut self) -> Option { + self.iter.next().map(|r| r.map(&mut self.f)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct MapErr { + iter: I, + f: F, +} + +impl Iterator for MapErr + where I: Iterator>, + F: FnMut(E) -> E2, +{ + type Item = Result; + + fn next(&mut self) -> Option { + self.iter.next().map(|r| r.map_err(&mut self.f)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + 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>` to iter until an error is encountered. +pub trait WhileOk +{ + fn while_ok(self, F) -> Result<(), E> + where F: FnMut(O) -> (); +} + +impl WhileOk for I + where I: Iterator>, +{ + fn while_ok(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()); +} -- cgit v1.2.3 From 0200e5d4de79a667e1ad401a681aab9acbca2d9a Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Champin Date: Mon, 8 Oct 2018 14:32:15 +0200 Subject: fixed erroneous comment --- src/map_x.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map_x.rs b/src/map_x.rs index a328dd1..e6a4643 100644 --- a/src/map_x.rs +++ b/src/map_x.rs @@ -4,7 +4,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. // -/// Extension trait for `Iterator>` to iter until an error is encountered. +/// Extension trait for `Iterator>` to selectively transform Oks and Errors. pub trait MapX : Sized { fn map_ok(self, F) -> MapOk -- cgit v1.2.3 From 9d0a152addeaabab1a2e4bff4fd35522dc4a4e5b Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Champin Date: Mon, 8 Oct 2018 17:12:35 +0200 Subject: added examples in the doc --- src/lib.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d949faa..a4ad147 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,6 +103,58 @@ //! # } //! ``` //! +//! * 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::>(); +//! 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::>(); +//! assert_eq!(doubles[2], Err("ParseIntError { kind: InvalidDigit }".to_string())); +//! # } +//! ``` +//! +//! * 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 @@ -115,6 +167,5 @@ pub mod onerr; pub mod onok; pub mod prelude; pub mod unwrap; -pub mod while_ok; mod util; - +pub mod while_ok; -- cgit v1.2.3 From 453ded73931017b140b1c79094636a1154b12fc8 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Champin Date: Tue, 9 Oct 2018 10:41:27 +0200 Subject: added filter_x --- src/filter_x.rs | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 35 +++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 src/filter_x.rs 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>` to filter one kind of result (and leaving the other as is) +pub trait FilterX : Sized +{ + fn filter_ok(self, F) -> FilterOk + where F: FnMut(&O) -> bool; + fn filter_err(self, F) -> FilterErr + where F: FnMut(&E) -> bool; +} + +impl FilterX for I + where I: Iterator> + Sized, +{ + fn filter_ok(self, f: F) -> FilterOk + where F: FnMut(&O) -> bool + { + FilterOk{ iter: self, f } + } + fn filter_err(self, f: F) -> FilterErr + where F: FnMut(&E) -> bool + { + FilterErr{ iter: self, f } + } +} + + +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct FilterOk { + iter: I, + f: F, +} + +impl Iterator for FilterOk + where I: Iterator>, + F: FnMut(&O) -> bool, +{ + type Item = Result; + + fn next(&mut self) -> Option { + 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) { + 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 { + iter: I, + f: F, +} + +impl Iterator for FilterErr + where I: Iterator>, + F: FnMut(&E) -> bool, +{ + type Item = Result; + + fn next(&mut self) -> Option { + 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) { + 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 a4ad147..42bab55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -136,6 +136,40 @@ //! # } //! ``` //! +//! * 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::>(); +//! 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::>(); +//! assert_eq!(doubles.len(), 4); +//! assert_eq!(doubles[2], Ok(4)); +//! # } +//! ``` +//! //! * Stopping the iteration on the first error //! //! ``` @@ -161,6 +195,7 @@ //! pub mod errors; +pub mod filter_x; pub mod map_x; pub mod oks; pub mod onerr; -- cgit v1.2.3