While [`core::error::Error`]s are only capable of having zero or one cause (via
[`core::error::Error::source`]), [`derail::Error`]s are capable of having zero
or *many* causes (via [`derail::Error::accept`]). In graph theory terms, this
means a single [`core::error::Error`] can represent a [path graph] of causes
with itself as the root, and a single [`derail::Error`] can represent a [tree]
of causes with itself as the root.
The typical entrypoint for traversing [`derail::Error`]s and their causes
is [`VisitorExt::visit_many`]. This method accepts an [`IntoIterator`]
of [`derail::Error`]s, which means that [forests] of errors and their
causes are also supported. In practical terms, this means it's reasonable
and well-supported for a fallible function to return either a single
[`derail::Error`] or a collection of them.
Because a path graph is a special case of a tree, [`CoreCompat`] is provided
to allow converting a [`core::error::Error`] into a [`derail::Error`]. No
convenient mechanism is provided for the reverse conversion, as it would
necessarily be lossy.
Additionally, while [`core::error::Error`] does not (yet) have a mechanism for
accessing arbitrary data stored in an error in a generic context, [`derail`]
provides the [`derail::Error::details`](crate::Error::details) function which
returns the [`derail::Error::Details`](crate::Error::Details) associated
type to allow for this. It is also possible to write [`derail::Error`]s that
are caused by other [`derail::Error`]s with mismatched concrete types for
[`derail::Error::Details`](crate::Error::Details).
[`VisitorExt::visit_many`]: crate::VisitorExt::visit_many
[`derail::Error::accept`]: crate::Error::accept
[`derail::Error`]: crate::Error
[`derail`]: crate
[forests]: https://en.wikipedia.org/wiki/Tree_(graph_theory)
[path graph]: https://en.wikipedia.org/wiki/Path_graph
[tree]: https://en.wikipedia.org/wiki/Tree_(graph_theory)