1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
//! Map retry crate provides a trait that allows to repeat mapping on failed results. //! This is useful for doing I/O such as loading webpages using iterators. //! //! `map_retry` behaves like normal map function, with exception that return type //! must be `Result` and if `Err` is returned it tries to execute mapping function //! one more time after all original items have been processed. **Order** of results is //! not guaranteed. If mapping fails also on second try the last error is returned. //! The same number of input and output items is guaranteed. //! //! ``` //! use map_retry::MapRetry; //! # static mut EVEN: bool = true; //! # //! # fn do_failable_io<T>(a: T) -> Result<T, ()> { //! # unsafe { //! # EVEN = !EVEN; //! # } //! # if unsafe { EVEN } { //! # return Err(()); //! # } //! # Ok(a) //! # } //! fn retry() { //! let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; //! # // Uses closure on purpose //! let res: Vec<_> = a.iter().map_retry(|a| do_failable_io(a)).collect(); //! assert_eq!(a.len(), res.len()); //! } //! ``` /// Return type used for chaining with iterators #[derive(Debug, Clone)] pub struct MapIter<Iter: Iterator, F> { iter: Iter, failed: Vec<Iter::Item>, f: F, } impl<Iter: Iterator, F> MapIter<Iter, F> { fn new(iter: Iter, f: F) -> Self { MapIter { iter, failed: vec![], f, } } } /// Trait defining retry signatures pub trait MapRetry: Iterator + Sized { /// Works the same as map function, but retries failures. /// Return type of provided closure must of type `Result` if result is error /// iterator retries to apply function agian. /// /// **Order** of elements is not guaranteed. /// All elements in original iterator are returned. fn map_retry<F>(self, f: F) -> MapIter<Self, F>; // fn map_retry<F>(self, f: F) -> MapIter<Self, F> where MapIter<Self, F>: Iterator; } impl<T: Iterator> MapRetry for T { /// Runs map function which retries results that return error. /// /// Errors are retried only after all elements have been mapped. /// Maping function must return `Result` type. /// Items are cloned when error is returned. fn map_retry<F>(self, f: F) -> MapIter<Self, F> { MapIter::new(self, f) } } impl<Iter: Iterator, F: FnMut(Iter::Item) -> Result<Out, E>, Out, E> Iterator for MapIter<Iter, F> where Iter::Item: Clone, { type Item = Result<Out, E>; fn next(&mut self) -> Option<Self::Item> { for res in self.iter.by_ref() { let m = (self.f)(res.clone()); if m.is_ok() { return Some(m); } else { self.failed.push(res); } } Some((self.f)(self.failed.pop()?)) } }