libimagerror/iter.rs
1//
2// imag - the personal information management suite for the commandline
3// Copyright (C) 2015-2020 the imag contributors
4//
5// This library is free software; you can redistribute it and/or
6// modify it under the terms of the GNU Lesser General Public
7// License as published by the Free Software Foundation; version
8// 2.1 of the License.
9//
10// This library is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13// Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public
16// License along with this library; if not, write to the Free Software
17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18//
19
20use failure::Error;
21
22/// An iterator that unwraps the `Ok` items of `iter`, while passing the `Err` items to its
23/// closure `f`.
24///
25/// This `struct` is created by the `unwrap_with()` method on `TraceIterator`. See its
26/// documentation for more information.
27#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
28#[derive(Clone)]
29pub struct UnwrapWith<I, F>{
30 iter: I,
31 f: F
32}
33
34impl<I, F, T> Iterator for UnwrapWith<I, F>
35 where
36 I: Iterator<Item = Result<T, Error>>,
37 F: FnMut(Error)
38{
39 type Item = T;
40
41 #[inline]
42 fn next(&mut self) -> Option<Self::Item> {
43 loop {
44 match self.iter.next() {
45 Some(Err(e)) => { (self.f)(e); },
46 Some(Ok(item)) => return Some(item),
47 None => return None,
48 }
49 }
50 }
51}
52
53
54
55/// Iterator helper for Unwrap with exiting on error
56pub struct UnwrapExit<I, T>(I)
57 where I: Iterator<Item = Result<T, Error>>;
58
59impl<I, T> Iterator for UnwrapExit<I, T>
60 where I: Iterator<Item = Result<T, Error>>,
61{
62 type Item = T;
63
64 fn next(&mut self) -> Option<Self::Item> {
65 use crate::trace::MapErrTrace;
66 self.0.next().map(|e| e.map_err_trace_exit_unwrap())
67 }
68}
69
70impl<I, T> DoubleEndedIterator for UnwrapExit<I, T>
71 where I: DoubleEndedIterator<Item = Result<T, Error>>,
72{
73 fn next_back(&mut self) -> Option<Self::Item> {
74 use crate::trace::MapErrTrace;
75 self.0.next_back().map(|e| e.map_err_trace_exit_unwrap())
76 }
77}
78
79/// This trait provides methods that make it easier to work with iterators that yield a `Result`.
80pub trait TraceIterator<T> : Iterator<Item = Result<T, Error>> + Sized {
81 /// Creates an iterator that yields the item in each `Ok` item, while filtering out the
82 /// `Err`
83 /// items. Each filtered `Err` will be trace-logged with [`::trace::trace_error`].
84 ///
85 /// As with all iterators, the processing is lazy. If you do not use the result of this method,
86 /// nothing will be passed to `::trace::trace_error`, no matter how many `Err` items might
87 /// be present.
88 #[inline]
89 fn trace_unwrap(self) -> UnwrapWith<Self, fn(Error)> {
90 #[inline]
91 fn trace_error(err: Error) {
92 err.iter_chain().for_each(|cause| {
93 eprintln!("{}", cause);
94 });
95 }
96
97 self.unwrap_with(trace_error)
98 }
99
100 /// Creates an iterator that yields the item in each `Ok` item.
101 ///
102 /// The first `Err(_)` element is traced using `::trace::trace_error_exit`.
103 ///
104 /// As with all iterators, the processing is lazy. If you do not use the result of this method,
105 /// nothing will be passed to `::trace::trace_error_exit`, no matter how many `Err` items might
106 /// be present.
107 #[inline]
108 fn trace_unwrap_exit(self) -> UnwrapExit<Self, T> {
109 UnwrapExit(self)
110 }
111
112
113 /// Takes a closure and creates an iterator that will yield the items inside all `Ok` items
114 /// yielded by the original iterator. All `Err` items will be filtered out, and the contents
115 /// of each `Err` will be passed to the closure.
116 ///
117 /// As with all iterators, the processing is lazy. The result of this method must be evaluated
118 /// for the closure to be called.
119 #[inline]
120 fn unwrap_with<F>(self, f: F) -> UnwrapWith<Self, F>
121 where F: FnMut(Error)
122 {
123 UnwrapWith { iter: self, f }
124 }
125}
126
127impl<I, T> TraceIterator<T> for I where
128 I: Iterator<Item = Result<T, Error>>
129{}
130