derail 0.3.0

An alternative to `core::error::Error`.
Documentation
//! [`ErrorExt`] and its implementation details.

use core::{iter, marker::PhantomData, ops::ControlFlow};

use crate::{Error, Visitor, VisitorExt as _, sealed::SealedError};

/// Extension trait that provides more methods for [`Error`]s.
#[expect(private_bounds)]
pub trait ErrorExt: SealedError + Error {
    /// Returns `true` if this [`Error`] has at least one child.
    fn has_children(&self) -> bool {
        /// [`Visitor`] implementation.
        struct VisitorImpl<D> {
            /// Whether any children were discovered.
            has_children: bool,

            /// The `Error::Details` type.
            details: PhantomData<D>,
        }

        impl<D> Visitor for VisitorImpl<D> {
            type Details = D;

            fn push(&mut self) -> ControlFlow<()> {
                self.has_children = true;
                ControlFlow::Break(())
            }
        }

        let mut visitor = VisitorImpl {
            has_children: false,
            details: PhantomData::<Self::Details>,
        };
        let _: ControlFlow<(), ()> = visitor.visit_many(iter::once(self));
        visitor.has_children
    }
}

impl<T> ErrorExt for T where T: Error + ?Sized {}