eros 0.6.0

Error handling that is precise, no boilerplate, ergonomic, context aware, and performant.
Documentation
use crate::{ContextSource, ErrorUnion, type_set::TypeSet};

impl<E> ErrorUnion<E>
where
    E: TypeSet,
{
    pub fn user_contexts(&self) -> impl Iterator<Item = &ContextSource> {
        self.inner
            .context
            .iter()
            .filter(|e| e.is_user_facing)
            .map(|e| &e.context)
    }
}

#[cfg(test)]
mod tests {
    use crate::SendSyncError;

    use super::*;

    #[derive(Debug)]
    struct SystemDiskError;
    impl std::fmt::Display for SystemDiskError {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            write!(f, "Critial IO failure at block 0x7FA3")
        }
    }
    impl std::error::Error for SystemDiskError {}

    #[derive(Debug)]
    struct InvalidPasswordError;
    impl std::fmt::Display for InvalidPasswordError {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            write!(f, "Your password must be at least 8 characters long.")
        }
    }
    impl std::error::Error for InvalidPasswordError {}

    fn create_user_error_message(error: &dyn SendSyncError) -> Option<String> {
        if let Some(user_error) = error.as_any().downcast_ref::<InvalidPasswordError>() {
            Some(user_error.to_string())
        } else {
            None
        }
    }

    #[test]
    fn test_use_case() {
        let system_err = SystemDiskError;
        let union_a: ErrorUnion<(SystemDiskError,)> = ErrorUnion::new(system_err);
        let union_a = union_a.context("Normal context");
        let union_a = union_a.user_context("User context");

        let user_context = union_a.user_contexts().collect::<Vec<_>>();

        assert_eq!(user_context.len(), 1);
        assert_eq!(user_context[0].to_string(), "User context");

        let user_error_message = create_user_error_message(union_a.inner_ref());
        assert_eq!(user_error_message, None);

        let user_err = InvalidPasswordError;
        let union_b: ErrorUnion<(InvalidPasswordError,)> = ErrorUnion::new(user_err);
        let union_b = union_b.context("Normal context");
        let union_b = union_b.user_context("User context");

        let user_contexts = union_b.user_contexts().collect::<Vec<_>>();

        assert_eq!(user_context.len(), 1);
        assert_eq!(user_context[0].to_string(), "User context");

        let user_error_message = create_user_error_message(union_b.inner_ref());
        assert_eq!(
            user_error_message.as_deref(),
            Some("Your password must be at least 8 characters long.")
        );
    }
}