how.rs/src/lib.rs

88 lines
2.2 KiB
Rust

#![doc = include_str!("README.md")]
#![cfg_attr(feature = "backtrace", feature(backtrace))]
mod context;
pub use context::{Context, IntoContext, ToContext};
mod report;
pub use report::{Report, ReportFmt};
use report::{report_write, Indentation};
mod explain;
pub use explain::Explain;
pub type Result<T, E = How> = std::result::Result<T, E>;
/// Does not implement [`std::error::Error`] to allow a [`From`] implementation for all other error types.
#[derive(Debug)]
pub struct How {
/// When true, the error will cause branchers to abort.
classified: bool,
context: Vec<Context>,
#[cfg(feature = "backtrace")]
backtrace: std::backtrace::Backtrace,
}
impl How {
pub fn new(context: impl IntoContext) -> Self {
Self {
classified: false,
context: vec![context.into_context()],
#[cfg(feature = "backtrace")]
backtrace: std::backtrace::Backtrace::capture(),
}
}
pub fn clone_without_backtrace(&self) -> Self {
Self {
classified: self.classified,
context: self.context.clone(),
#[cfg(feature = "backtrace")]
backtrace: std::backtrace::Backtrace::disabled(),
}
}
#[inline]
pub const fn classified(mut self) -> Self {
self.classified = true;
self
}
pub fn context(mut self, context: impl IntoContext) -> Self {
self.context.push(context.into_context());
self
}
#[inline]
pub const fn is_classified(&self) -> bool {
self.classified
}
}
impl std::fmt::Display for How {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut opts = ReportFmt::default().indent_first(false);
report_write!(f, &opts, "Parsing failed")?;
for context in self.context.iter().rev() {
write!(f, "\n{}└ ", Indentation(opts.indentation()))?;
context.fmt(f, &opts)?;
opts = opts.indent();
}
#[cfg(feature = "backtrace")]
{
write!(f, "\n{}", self.backtrace)?;
};
Ok(())
}
}
impl<E> From<E> for How
where
E: std::error::Error,
{
fn from(value: E) -> Self {
Self::new(value.to_string())
}
}