use std::error::*;

//
// Errors
//

/// Access to errors.
pub trait Errors {
    /// Iterate errors of a type.
    fn iter_errors_of_type<'this, ErrorT>(&'this self) -> impl Iterator<Item = &'this ErrorT>
    where
        ErrorT: 'static + Error;

    /// The first error of a type.
    fn error_of_type<ErrorT>(&self) -> Option<&ErrorT>
    where
        ErrorT: 'static + Error,
    {
        self.iter_errors_of_type::<ErrorT>().next()
    }

    /// Whether we have an error of a type.
    fn has_error_of_type<ErrorT>(&self) -> bool
    where
        ErrorT: 'static + Error,
    {
        self.error_of_type::<ErrorT>().is_some()
    }

    /// The first occurrence of an error.
    fn error_for<ErrorT>(&self, error: &ErrorT) -> Option<&ErrorT>
    where
        ErrorT: 'static + Error + PartialEq,
    {
        self.iter_errors_of_type()
            .filter(|source_error| *error == **source_error)
            .next()
    }

    /// Whether we have an error.
    fn has_error<ErrorT>(&self, error: &ErrorT) -> bool
    where
        ErrorT: 'static + Error + PartialEq,
    {
        self.error_for(error).is_some()
    }
}
