#![doc = include_str!("../README.md")] #![forbid(unsafe_code)] #![cfg_attr(feature = "backtrace", feature(backtrace))] mod sealed; pub(crate) use sealed::seal; mod context; pub use context::{Context, IntoContext}; mod report; use report::report_write; pub use report::{Report, ReportOpts}; mod into; pub(crate) use into::IntoResultHow; mod explain; pub use explain::Explain; #[cfg(feature = "termination")] mod termination; #[cfg(feature = "termination")] pub use termination::TerminationResult; pub type Result = std::result::Result; /// Does not implement [`std::error::Error`] to allow a [`From`] implementation for all other error types. pub struct How(Box); struct HowInner { /// When true, the error will cause branchers to abort. classified: bool, // TODO: consider storing this vec inline (sharing the allocation with rest of the struct. // Probably move after `backtrace`) context: Vec, #[cfg(feature = "backtrace")] backtrace: std::backtrace::Backtrace, } impl std::fmt::Debug for How { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut b = f.debug_struct(std::any::type_name::()); let b = b .field("classified", &self.0.classified) .field("context", &self.0.context); #[cfg(feature = "backtrace")] let b = b.field("backtrace", &self.0.backtrace); b.finish() } } impl How { #[must_use] pub fn new(context: impl IntoContext) -> Self { Self(Box::new(HowInner { classified: false, context: { let mut vec = Vec::with_capacity(2); vec.push(context.into_context()); vec }, #[cfg(feature = "backtrace")] backtrace: std::backtrace::Backtrace::capture(), })) } #[must_use] pub fn clone_without_backtrace(&self) -> Self { Self(Box::new(HowInner { classified: self.0.classified, context: self.0.context.clone(), #[cfg(feature = "backtrace")] backtrace: std::backtrace::Backtrace::disabled(), })) } #[inline] #[must_use] pub fn classified(mut self) -> Self { self.0.classified = true; self } #[inline] #[must_use] pub const fn is_classified(&self) -> bool { self.0.classified } } impl explain::Sealed for How {} impl Explain for How { type Output = Self; #[inline] #[must_use] fn context(mut self, context: impl IntoContext) -> Self { self.0.context.push(context.into_context()); self } } impl std::fmt::Display for How { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut opts = ReportOpts::default(); let mut ctxs = self.0.context.iter().rev(); let ctx = ctxs.next().expect("`How` created with no context."); report_write!(f, &opts, "{ctx}")?; for ctx in ctxs { report_write!(f, &opts, "\n└ ")?; report_write!(f, &opts.indent().next(), "{ctx}")?; opts = opts.indent(); } #[cfg(feature = "backtrace")] { opts = opts.indent(); report_write!(f, &opts, "\n{}", self.0.backtrace)?; } Ok(()) } }