2016-10-18 23:20:51 +00:00
|
|
|
//
|
|
|
|
// imag - the personal information management suite for the commandline
|
2019-01-03 01:32:07 +00:00
|
|
|
// Copyright (C) 2015-2019 the imag contributors
|
2016-10-18 23:20:51 +00:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//
|
|
|
|
|
2018-10-30 17:40:50 +00:00
|
|
|
use failure::Error;
|
2016-10-18 23:20:51 +00:00
|
|
|
|
|
|
|
/// 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
|
|
|
|
}
|
|
|
|
|
2018-10-30 17:40:50 +00:00
|
|
|
impl<I, F, T> Iterator for UnwrapWith<I, F>
|
|
|
|
where
|
|
|
|
I: Iterator<Item = Result<T, Error>>,
|
|
|
|
F: FnMut(Error)
|
2016-10-18 23:20:51 +00:00
|
|
|
{
|
|
|
|
type Item = T;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
loop {
|
|
|
|
match self.iter.next() {
|
2018-10-30 17:40:50 +00:00
|
|
|
Some(Err(e)) => { (self.f)(e); },
|
2016-10-18 23:20:51 +00:00
|
|
|
Some(Ok(item)) => return Some(item),
|
2018-10-30 17:40:50 +00:00
|
|
|
None => return None,
|
2016-10-18 23:20:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-30 17:40:50 +00:00
|
|
|
|
2016-10-18 23:20:51 +00:00
|
|
|
|
2018-02-06 19:17:20 +00:00
|
|
|
/// Iterator helper for Unwrap with exiting on error
|
2019-02-05 00:37:32 +00:00
|
|
|
pub struct UnwrapExit<I, T>(I)
|
2018-10-30 17:40:50 +00:00
|
|
|
where I: Iterator<Item = Result<T, Error>>;
|
2018-02-06 19:17:20 +00:00
|
|
|
|
2018-10-30 17:40:50 +00:00
|
|
|
impl<I, T> Iterator for UnwrapExit<I, T>
|
|
|
|
where I: Iterator<Item = Result<T, Error>>,
|
2018-02-06 19:17:20 +00:00
|
|
|
{
|
|
|
|
type Item = T;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
use trace::MapErrTrace;
|
2019-02-05 00:37:32 +00:00
|
|
|
self.0.next().map(|e| e.map_err_trace_exit_unwrap())
|
2018-02-06 19:17:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-30 17:40:50 +00:00
|
|
|
impl<I, T> DoubleEndedIterator for UnwrapExit<I, T>
|
|
|
|
where I: DoubleEndedIterator<Item = Result<T, Error>>,
|
2018-02-06 19:17:20 +00:00
|
|
|
{
|
|
|
|
fn next_back(&mut self) -> Option<Self::Item> {
|
|
|
|
use trace::MapErrTrace;
|
2019-02-05 00:37:32 +00:00
|
|
|
self.0.next_back().map(|e| e.map_err_trace_exit_unwrap())
|
2018-02-06 19:17:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-18 23:20:51 +00:00
|
|
|
/// This trait provides methods that make it easier to work with iterators that yield a `Result`.
|
2018-10-30 17:40:50 +00:00
|
|
|
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`
|
2016-10-18 23:20:51 +00:00
|
|
|
/// 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]
|
2018-10-30 17:40:50 +00:00
|
|
|
fn trace_unwrap(self) -> UnwrapWith<Self, fn(Error)> {
|
2016-10-18 23:20:51 +00:00
|
|
|
#[inline]
|
2018-10-30 17:40:50 +00:00
|
|
|
fn trace_error(err: Error) {
|
|
|
|
err.iter_chain().for_each(|cause| {
|
|
|
|
eprintln!("{}", cause);
|
|
|
|
});
|
2016-10-18 23:20:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self.unwrap_with(trace_error)
|
|
|
|
}
|
|
|
|
|
2018-02-06 19:17:20 +00:00
|
|
|
/// 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]
|
2019-02-05 00:37:32 +00:00
|
|
|
fn trace_unwrap_exit(self) -> UnwrapExit<Self, T> {
|
|
|
|
UnwrapExit(self)
|
2018-02-06 19:17:20 +00:00
|
|
|
}
|
|
|
|
|
2018-10-30 17:40:50 +00:00
|
|
|
|
2016-10-18 23:20:51 +00:00
|
|
|
/// 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>
|
2018-10-30 17:40:50 +00:00
|
|
|
where F: FnMut(Error)
|
2016-10-18 23:20:51 +00:00
|
|
|
{
|
2018-04-24 19:02:34 +00:00
|
|
|
UnwrapWith { iter: self, f }
|
2016-10-18 23:20:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-30 17:40:50 +00:00
|
|
|
impl<I, T> TraceIterator<T> for I where
|
|
|
|
I: Iterator<Item = Result<T, Error>>
|
2016-10-18 23:20:51 +00:00
|
|
|
{}
|
|
|
|
|