use super::cause::*;

use std::{cmp::*, error::*};

//
// CauseEquality
//

/// Cause equality attachment.
pub struct CauseEquality(pub Box<dyn Fn(&Cause, &Cause) -> bool + Send + Sync>);

impl CauseEquality {
    /// Constructor.
    ///
    /// The cause's error type must implement [PartialEq].
    pub fn new<ErrorT>() -> Self
    where
        ErrorT: 'static + Error + PartialEq,
    {
        Self(Box::new(Self::eq_::<ErrorT>))
    }

    /// Compare causes.
    pub fn eq(&self, left: &Cause, right: &Cause) -> bool {
        self.0(left, right)
    }

    fn eq_<ErrorT>(left: &Cause, right: &Cause) -> bool
    where
        ErrorT: 'static + Error + PartialEq,
    {
        if let Some(left) = left.error.downcast_ref::<ErrorT>()
            && let Some(right) = right.error.downcast_ref::<ErrorT>()
        {
            left.eq(right)
        } else {
            false
        }
    }
}
