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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
// // imag - the personal information management suite for the commandline // Copyright (C) 2015-2019 the imag contributors // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; version // 2.1 of the License. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // use failure::Error; /// An iterator that unwraps the `Ok` items of `iter`, while passing the `Err` items to its /// closure `f`. /// /// This `struct` is created by the `unwrap_with()` method on `TraceIterator`. See its /// documentation for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[derive(Clone)] pub struct UnwrapWith<I, F>{ iter: I, f: F } impl<I, F, T> Iterator for UnwrapWith<I, F> where I: Iterator<Item = Result<T, Error>>, F: FnMut(Error) { type Item = T; #[inline] fn next(&mut self) -> Option<Self::Item> { loop { match self.iter.next() { Some(Err(e)) => { (self.f)(e); }, Some(Ok(item)) => return Some(item), None => return None, } } } #[inline] fn size_hint(&self) -> (usize, Option<usize>) { let (_, upper) = self.iter.size_hint(); (0, upper) } } /// Iterator helper for Unwrap with exiting on error pub struct UnwrapExit<I, T>(I, i32) where I: Iterator<Item = Result<T, Error>>; impl<I, T> Iterator for UnwrapExit<I, T> where I: Iterator<Item = Result<T, Error>>, { type Item = T; fn next(&mut self) -> Option<Self::Item> { use trace::MapErrTrace; self.0.next().map(|e| e.map_err_trace_exit_unwrap(self.1)) } } impl<I, T> DoubleEndedIterator for UnwrapExit<I, T> where I: DoubleEndedIterator<Item = Result<T, Error>>, { fn next_back(&mut self) -> Option<Self::Item> { use trace::MapErrTrace; self.0.next_back().map(|e| e.map_err_trace_exit_unwrap(self.1)) } } /// This trait provides methods that make it easier to work with iterators that yield a `Result`. pub trait TraceIterator<T> : Iterator<Item = Result<T, Error>> + Sized { /// Creates an iterator that yields the item in each `Ok` item, while filtering out the /// `Err` /// items. Each filtered `Err` will be trace-logged with [`::trace::trace_error`]. /// /// As with all iterators, the processing is lazy. If you do not use the result of this method, /// nothing will be passed to `::trace::trace_error`, no matter how many `Err` items might /// be present. #[inline] fn trace_unwrap(self) -> UnwrapWith<Self, fn(Error)> { #[inline] fn trace_error(err: Error) { err.iter_chain().for_each(|cause| { eprintln!("{}", cause); }); } self.unwrap_with(trace_error) } /// Creates an iterator that yields the item in each `Ok` item. /// /// The first `Err(_)` element is traced using `::trace::trace_error_exit`. /// /// As with all iterators, the processing is lazy. If you do not use the result of this method, /// nothing will be passed to `::trace::trace_error_exit`, no matter how many `Err` items might /// be present. #[inline] fn trace_unwrap_exit(self, exitcode: i32) -> UnwrapExit<Self, T> { UnwrapExit(self, exitcode) } /// Takes a closure and creates an iterator that will yield the items inside all `Ok` items /// yielded by the original iterator. All `Err` items will be filtered out, and the contents /// of each `Err` will be passed to the closure. /// /// As with all iterators, the processing is lazy. The result of this method must be evaluated /// for the closure to be called. #[inline] fn unwrap_with<F>(self, f: F) -> UnwrapWith<Self, F> where F: FnMut(Error) { UnwrapWith { iter: self, f } } } impl<I, T> TraceIterator<T> for I where I: Iterator<Item = Result<T, Error>> {}