use crate::write_location;
use std::fmt::{Debug, Display, Formatter};
use std::panic::Location;
use std::sync::Arc;
pub struct ChainedError {
pub(crate) err: ErrorHandle,
pub(crate) location: &'static Location<'static>,
#[cfg_attr(
not(all(feature = "auto-chain-error", not(feature = "tree-error"))),
expect(dead_code, reason = "used only by the auto-chain Error representation")
)]
pub(crate) is_probable_cause: bool,
#[cfg_attr(
not(all(feature = "auto-chain-error", not(feature = "tree-error"))),
expect(dead_code, reason = "used only by the auto-chain Error representation")
)]
pub(crate) logical_parent: Option<usize>,
pub(crate) source: Option<Box<ChainedError>>,
}
impl Debug for ChainedError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self.err.error(), f)
}
}
impl Display for ChainedError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(self.err.error(), f)?;
if !f.alternate() {
write_location(f, self.location)?;
}
Ok(())
}
}
impl std::error::Error for ChainedError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.source
.as_deref()
.map(|err| err as &(dyn std::error::Error + 'static))
.or_else(|| self.err.error().source())
}
}
pub(crate) struct ErrorHandle {
owner: Arc<dyn std::error::Error + Send + Sync + 'static>,
source_depth: usize,
}
impl ErrorHandle {
pub(crate) fn new(error: Box<dyn std::error::Error + Send + Sync + 'static>) -> Self {
ErrorHandle {
owner: error.into(),
source_depth: 0,
}
}
pub(crate) fn error(&self) -> &(dyn std::error::Error + 'static) {
let mut error: &(dyn std::error::Error + 'static) = self.owner.as_ref();
for _ in 0..self.source_depth {
error = error
.source()
.expect("a captured source path remains stable while its owning error is alive");
}
error
}
pub(crate) fn source(&self) -> Option<Self> {
self.error().source()?;
Some(ErrorHandle {
owner: Arc::clone(&self.owner),
source_depth: self.source_depth + 1,
})
}
#[cfg(all(feature = "auto-chain-error", not(feature = "tree-error")))]
pub(crate) fn is_native_source(&self) -> bool {
self.source_depth > 0
}
}