use std::{error::Error, io}; use super::Id; pub fn format(out: &mut W, error: E) -> Result<(), io::Error> where W: io::Write, E: Error, { writeln!(out, "{error}")?; format_sources(out, error)?; Ok(()) } pub fn format_with_id(out: &mut W, id: &Id, error: E) -> Result<(), io::Error> where W: io::Write, E: Error, { writeln!(out, "[{id}] {error}")?; format_sources(out, error)?; Ok(()) } fn format_sources(out: &mut W, error: E) -> Result<(), io::Error> where W: io::Write, E: Error, { let mut sources = Sources::from(&error); if let Some(source) = sources.next() { writeln!(out)?; writeln!(out, "Caused by:")?; writeln!(out, " {source}")?; for source in sources { writeln!(out, " {source}")?; } writeln!(out)?; } Ok(()) } struct Sources<'e> { next: Option<&'e dyn Error>, } impl<'e, E> From<&'e E> for Sources<'e> where E: Error, { fn from(error: &'e E) -> Self { Self { next: error.source(), } } } // See also: However, we only // want to iterate the sources, and not the error itself. Personally, I find the `skip(1)` // suggestion untidy, since the error itself is non-optional while the sources are optional. impl<'a> Iterator for Sources<'a> { type Item = &'a dyn Error; fn next(&mut self) -> Option { let source = self.next; self.next = self.next.and_then(|err| err.source()); source } }