/*! Iterate over error `.diagnostic_source()` chains. */ use crate::protocol::Diagnostic; /// Iterator of a chain of cause errors. #[derive(Clone, Default)] #[allow(missing_debug_implementations)] pub(crate) struct DiagnosticChain<'a> { state: Option>, } impl<'a> DiagnosticChain<'a> { pub(crate) fn from_diagnostic(head: &'a dyn Diagnostic) -> Self { DiagnosticChain { state: Some(ErrorKind::Diagnostic(head)), } } pub(crate) fn from_stderror(head: &'a (dyn std::error::Error + 'static)) -> Self { DiagnosticChain { state: Some(ErrorKind::StdError(head)), } } } impl<'a> Iterator for DiagnosticChain<'a> { type Item = ErrorKind<'a>; fn next(&mut self) -> Option { if let Some(err) = self.state.take() { self.state = err.get_nested(); Some(err) } else { None } } fn size_hint(&self) -> (usize, Option) { let len = self.len(); (len, Some(len)) } } impl ExactSizeIterator for DiagnosticChain<'_> { fn len(&self) -> usize { fn depth(d: Option<&ErrorKind<'_>>) -> usize { match d { Some(d) => 1 + depth(d.get_nested().as_ref()), None => 0, } } depth(self.state.as_ref()) } } #[derive(Clone)] pub(crate) enum ErrorKind<'a> { Diagnostic(&'a dyn Diagnostic), StdError(&'a (dyn std::error::Error + 'static)), } impl<'a> ErrorKind<'a> { fn get_nested(&self) -> Option> { match self { ErrorKind::Diagnostic(d) => d .diagnostic_source() .map(ErrorKind::Diagnostic) .or_else(|| d.source().map(ErrorKind::StdError)), ErrorKind::StdError(e) => e.source().map(ErrorKind::StdError), } } } impl<'a> std::fmt::Debug for ErrorKind<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { ErrorKind::Diagnostic(d) => d.fmt(f), ErrorKind::StdError(e) => e.fmt(f), } } } impl<'a> std::fmt::Display for ErrorKind<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { ErrorKind::Diagnostic(d) => d.fmt(f), ErrorKind::StdError(e) => e.fmt(f), } } }