libimagerror: Move from error-chain to failure

Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
Matthias Beyer 2018-10-30 18:40:50 +01:00
parent c160a967ec
commit c2f674cc29
4 changed files with 53 additions and 102 deletions

View file

@ -20,6 +20,7 @@ is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" }
maintenance = { status = "actively-developed" }
[dependencies]
log = "0.4"
ansi_term = "0.11"
error-chain = "0.12"
log = "0.4"
ansi_term = "0.11"
failure = "0.1"
failure_derive = "0.1"

View file

@ -17,7 +17,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
use error_chain::ChainedError;
use failure::Error;
/// An iterator that unwraps the `Ok` items of `iter`, while passing the `Err` items to its
/// closure `f`.
@ -31,9 +31,10 @@ pub struct UnwrapWith<I, F>{
f: F
}
impl<I, F, T, E> Iterator for UnwrapWith<I, F> where
I: Iterator<Item = Result<T, E>>,
F: FnMut(E)
impl<I, F, T> Iterator for UnwrapWith<I, F>
where
I: Iterator<Item = Result<T, Error>>,
F: FnMut(Error)
{
type Item = T;
@ -41,14 +42,13 @@ impl<I, F, T, E> Iterator for UnwrapWith<I, F> where
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.iter.next() {
Some(Err(e)) => {
(self.f)(e);
},
Some(Err(e)) => { (self.f)(e); },
Some(Ok(item)) => return Some(item),
None => return None,
None => return None,
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
@ -56,32 +56,14 @@ impl<I, F, T, E> Iterator for UnwrapWith<I, F> where
}
}
impl<I, F, T, E> DoubleEndedIterator for UnwrapWith<I, F> where
I: DoubleEndedIterator<Item = Result<T, E>>,
F: FnMut(E)
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
loop {
match self.iter.next_back() {
Some(Err(e)) => {
(self.f)(e);
},
Some(Ok(item)) => return Some(item),
None => return None,
}
}
}
}
/// Iterator helper for Unwrap with exiting on error
pub struct UnwrapExit<I, T, E>(I, i32)
where I: Iterator<Item = Result<T, E>>,
E: ChainedError;
pub struct UnwrapExit<I, T>(I, i32)
where I: Iterator<Item = Result<T, Error>>;
impl<I, T, E> Iterator for UnwrapExit<I, T, E>
where I: Iterator<Item = Result<T, E>>,
E: ChainedError
impl<I, T> Iterator for UnwrapExit<I, T>
where I: Iterator<Item = Result<T, Error>>,
{
type Item = T;
@ -91,9 +73,8 @@ impl<I, T, E> Iterator for UnwrapExit<I, T, E>
}
}
impl<I, T, E> DoubleEndedIterator for UnwrapExit<I, T, E>
where I: DoubleEndedIterator<Item = Result<T, E>>,
E: ChainedError
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;
@ -102,18 +83,21 @@ impl<I, T, E> DoubleEndedIterator for UnwrapExit<I, T, E>
}
/// This trait provides methods that make it easier to work with iterators that yield a `Result`.
pub trait TraceIterator<T, E> : Iterator<Item = Result<T, E>> + Sized {
/// Creates an iterator that yields the item in each `Ok` item, while filtering out the `Err`
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<K>(self) -> UnwrapWith<Self, fn(E)> where E: ChainedError<ErrorKind = K> {
fn trace_unwrap(self) -> UnwrapWith<Self, fn(Error)> {
#[inline]
fn trace_error<K, E: ChainedError<ErrorKind = K>>(err: E) {
eprintln!("{}", err.display_chain());
fn trace_error(err: Error) {
err.iter_chain().for_each(|cause| {
eprintln!("{}", cause);
});
}
self.unwrap_with(trace_error)
@ -127,12 +111,11 @@ pub trait TraceIterator<T, E> : Iterator<Item = Result<T, E>> + Sized {
/// 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, E>
where E: ChainedError
{
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.
@ -141,50 +124,13 @@ pub trait TraceIterator<T, E> : Iterator<Item = Result<T, E>> + Sized {
/// for the closure to be called.
#[inline]
fn unwrap_with<F>(self, f: F) -> UnwrapWith<Self, F>
where F: FnMut(E)
where F: FnMut(Error)
{
UnwrapWith { iter: self, f }
}
}
impl<I, T, E> TraceIterator<T, E> for I where
I: Iterator<Item = Result<T, E>>
impl<I, T> TraceIterator<T> for I where
I: Iterator<Item = Result<T, Error>>
{}
#[cfg(test)]
mod test {
use super::TraceIterator;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
struct TestError(i32);
#[test]
fn test_unwrap_with() {
let original = vec![Ok(1), Err(TestError(2)), Ok(3), Err(TestError(4))];
let mut errs = vec![];
let oks = original
.into_iter()
.unwrap_with(|e|errs.push(e))
.collect::<Vec<_>>();
assert_eq!(&oks, &[1, 3]);
assert_eq!(&errs, &[TestError(2), TestError(4)]);
}
#[test]
fn test_unwrap_with_backward() {
let original = vec![Ok(1), Err(TestError(2)), Ok(3), Err(TestError(4))];
let mut errs = vec![];
let oks = original
.into_iter()
.rev()
.unwrap_with(|e|errs.push(e))
.collect::<Vec<_>>();
assert_eq!(&oks, &[3, 1]);
assert_eq!(&errs, &[TestError(4), TestError(2)]);
}
}

View file

@ -35,11 +35,13 @@
#[macro_use] extern crate log;
extern crate ansi_term;
extern crate error_chain;
extern crate failure;
#[macro_use] extern crate failure_derive;
pub mod io;
pub mod errors;
pub mod exit;
pub mod trace;
pub mod io;
pub mod iter;
pub mod str;
pub mod trace;

View file

@ -21,7 +21,7 @@ use std::process::exit;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FmtResult;
use error_chain::ChainedError;
use failure::Error;
use ansi_term::Colour::Red;
struct ImagTrace<'a, T: 'a + ?Sized>(&'a T);
@ -32,32 +32,34 @@ impl<'a, T: 'a + ?Sized> ImagTrace<'a, T> {
}
}
impl<'a, T> Display for ImagTrace<'a, T>
where T: ChainedError
impl<'a> Display for ImagTrace<'a, Error>
{
fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
try!(writeln!(fmt, "{}: {}", Red.blink().paint("ERROR[ 0]"), self.0));
let _ = writeln!(fmt, "{}: {}", Red.blink().paint("ERROR[ 0]"), self.0)?;
for (i, e) in self.0.iter().enumerate().skip(1) {
try!(writeln!(fmt, "{}: {}", Red.blink().paint(format!("ERROR[{:>4}]", i)), e));
{
for (i, cause) in self.0.iter_causes().enumerate() {
let _ = writeln!(fmt,
"{prefix}: {error}",
prefix = Red.blink().paint(format!("ERROR[{:>4}]", i)),
error = cause)?;
}
}
if let Some(backtrace) = self.0.backtrace() {
try!(writeln!(fmt, "{}", Red.paint("--- BACKTRACE ---")));
try!(writeln!(fmt, "{:?}", backtrace));
}
let _ = writeln!(fmt, "{}", Red.paint("--- BACKTRACE ---"))?;
let _ = writeln!(fmt, "{:?}", self.0.backtrace())?;
Ok(())
}
}
pub fn trace_error<K, C: ChainedError<ErrorKind = K>>(e: &C) {
pub fn trace_error(e: &Error) {
eprintln!("{}", ImagTrace::new(e));
}
pub fn trace_error_dbg<K, C: ChainedError<ErrorKind = K>>(e: &C) {
debug!("{}", e.display_chain());
pub fn trace_error_dbg(e: &Error) {
debug!("{}", ImagTrace::new(e));
}
/// Helper functions for `Result<T, E>` types to reduce overhead in the following situations:
@ -74,7 +76,7 @@ pub trait MapErrTrace {
fn map_err_trace_exit_unwrap(self, code: i32) -> Self::Output;
}
impl<U, K, E: ChainedError<ErrorKind = K>> MapErrTrace for Result<U, E> {
impl<U> MapErrTrace for Result<U, Error> {
type Output = U;
/// Simply call `trace_error()` on the Err (if there is one) and return the error.