Add support for Option and move How definition into its own file
This commit is contained in:
parent
d3bd38ba13
commit
cbb80c9d3f
|
@ -10,6 +10,7 @@ pub trait Explain: Sealed {
|
|||
}
|
||||
|
||||
impl<T, E> Sealed for Result<T, E> where Result<T, E>: IntoResultHow {}
|
||||
impl<T> Sealed for Option<T> where Option<T>: IntoResultHow {}
|
||||
|
||||
impl<T, E> Explain for Result<T, E>
|
||||
where
|
||||
|
@ -19,6 +20,18 @@ where
|
|||
|
||||
#[inline(always)]
|
||||
fn context(self, context: impl IntoContext) -> Self::Output {
|
||||
self.into_result_how().map_err(|e| e.context(context))
|
||||
self.into_result_how().map_err(#[inline(never)] move |e| e.context(context))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Explain for Option<T>
|
||||
where
|
||||
Option<T>: IntoResultHow,
|
||||
{
|
||||
type Output = Result<<Self as IntoResultHow>::T, How>;
|
||||
|
||||
#[inline(always)]
|
||||
fn context(self, context: impl IntoContext) -> Self::Output {
|
||||
self.into_result_how().map_err(#[inline(never)] move |e| e.context(context))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
use crate::*;
|
||||
|
||||
use crate::report::report_write;
|
||||
|
||||
/// Does not implement [`std::error::Error`] to allow a [`From`] implementation for all other error types.
|
||||
pub struct How(Box<HowInner>);
|
||||
|
||||
struct HowInner {
|
||||
/// When true, the error will cause branchers to abort.
|
||||
classified: bool,
|
||||
#[cfg(feature = "backtrace")]
|
||||
backtrace: std::backtrace::Backtrace,
|
||||
// TODO: consider storing this vec inline (sharing the allocation with rest of the struct.
|
||||
// Probably move after `backtrace`)
|
||||
context: Vec<Context>,
|
||||
}
|
||||
|
||||
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::<Self>());
|
||||
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]
|
||||
#[inline(never)]
|
||||
pub fn new(context: impl IntoContext) -> Self {
|
||||
Self(Box::new(HowInner {
|
||||
classified: false,
|
||||
context: {
|
||||
let mut vec = Vec::with_capacity(4);
|
||||
vec[0] = 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(always)]
|
||||
#[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(())
|
||||
}
|
||||
}
|
21
src/into.rs
21
src/into.rs
|
@ -19,9 +19,13 @@ where
|
|||
{
|
||||
type T = T;
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
fn into_result_how(self) -> Result<Self::T, How> {
|
||||
self.map_err(|e| How::new(e.to_string()))
|
||||
#[inline(never)]
|
||||
fn into<E: std::error::Error>(e: E) -> How {
|
||||
How::new(e.to_string())
|
||||
}
|
||||
self.map_err(into)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,3 +37,16 @@ impl<T> IntoResultHow for Result<T, How> {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoResultHow for Option<T> {
|
||||
type T = T;
|
||||
|
||||
#[inline(always)]
|
||||
fn into_result_how(self) -> Result<Self::T, How> {
|
||||
#[inline(never)]
|
||||
fn into() -> How {
|
||||
How::new("None")
|
||||
}
|
||||
self.ok_or_else(into)
|
||||
}
|
||||
}
|
||||
|
|
101
src/lib.rs
101
src/lib.rs
|
@ -8,7 +8,6 @@ mod context;
|
|||
pub use context::{Context, IntoContext};
|
||||
|
||||
mod report;
|
||||
use report::report_write;
|
||||
pub use report::{Report, ReportOpts};
|
||||
|
||||
mod into;
|
||||
|
@ -22,101 +21,7 @@ mod termination;
|
|||
#[cfg(feature = "termination")]
|
||||
pub use termination::TerminationResult;
|
||||
|
||||
mod how;
|
||||
pub use how::How;
|
||||
|
||||
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.
|
||||
pub struct How(Box<HowInner>);
|
||||
|
||||
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<Context>,
|
||||
#[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::<Self>());
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue