Refactored Context
This commit is contained in:
parent
55054597d1
commit
8f1c7d9765
|
@ -8,22 +8,28 @@ use std::sync::Arc;
|
||||||
/// Provides context furthering the explanation of *how* you got to an error.
|
/// Provides context furthering the explanation of *how* you got to an error.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "clone-with-caveats", derive(Clone))]
|
#[cfg_attr(feature = "clone-with-caveats", derive(Clone))]
|
||||||
pub struct Context(pub(crate) ContextInner);
|
pub struct Context {
|
||||||
|
pub(crate) detail: Detail,
|
||||||
|
pub(crate) extra: Vec<Detail>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
pub(crate) fn new(detail: Detail) -> Self {
|
||||||
|
Self { detail, extra: Vec::new() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Context {
|
impl fmt::Display for Context {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::Display::fmt(&self.0, f)
|
self.detail.fmt(f)?;
|
||||||
|
for detail in &self.extra {
|
||||||
|
write!(f, "\n- {detail}")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[cfg_attr(feature = "clone-with-caveats", derive(Clone))]
|
|
||||||
pub(crate) enum ContextInner {
|
|
||||||
Elem(Detail),
|
|
||||||
Compound(Vec<Detail>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "clone-with-caveats", derive(Clone))]
|
#[cfg_attr(feature = "clone-with-caveats", derive(Clone))]
|
||||||
pub(crate) enum Detail {
|
pub(crate) enum Detail {
|
||||||
|
@ -51,24 +57,6 @@ impl Clone for Backtrace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ContextInner {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Elem(elem) => fmt::Display::fmt(elem, f),
|
|
||||||
Self::Compound(elems) => {
|
|
||||||
let mut elems = elems.iter();
|
|
||||||
if let Some(elem) = elems.next() {
|
|
||||||
fmt::Display::fmt(elem, f)?;
|
|
||||||
for elem in elems {
|
|
||||||
write!(f, "\n- {elem}")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Detail {
|
impl fmt::Display for Detail {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
@ -117,38 +105,26 @@ impl IntoContext for Context {
|
||||||
/// Chains another piece of context that is a child from a hierarchical perspective.
|
/// Chains another piece of context that is a child from a hierarchical perspective.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with(self, other: impl IntoContext) -> Self {
|
fn with(mut self, other: impl IntoContext) -> Self {
|
||||||
let other = other.into_context().0;
|
let mut other = other.into_context();
|
||||||
Context(ContextInner::Compound(match self.0 {
|
self.extra.reserve(1 + other.extra.len());
|
||||||
ContextInner::Compound(mut elems) => {
|
self.extra.push(other.detail);
|
||||||
match other {
|
self.extra.append(&mut other.extra);
|
||||||
ContextInner::Elem(elem) => elems.push(elem),
|
self
|
||||||
ContextInner::Compound(mut elems1) => elems.append(&mut elems1),
|
|
||||||
};
|
|
||||||
elems
|
|
||||||
}
|
|
||||||
ContextInner::Elem(elem) => match other {
|
|
||||||
ContextInner::Elem(elem1) => vec![elem, elem1],
|
|
||||||
ContextInner::Compound(mut elems) => {
|
|
||||||
elems.insert(0, elem);
|
|
||||||
elems
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoContext for String {
|
impl IntoContext for String {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn into_context(self) -> Context {
|
fn into_context(self) -> Context {
|
||||||
Context(ContextInner::Elem(Detail::String(self)))
|
Context::new(Detail::String(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoContext for &'static str {
|
impl IntoContext for &'static str {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn into_context(self) -> Context {
|
fn into_context(self) -> Context {
|
||||||
Context(ContextInner::Elem(Detail::Str(self)))
|
Context::new(Detail::Str(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +148,7 @@ impl<'a> IntoContext for &'a Location<'static> {
|
||||||
impl IntoContext for Location<'static> {
|
impl IntoContext for Location<'static> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_context(self) -> Context {
|
fn into_context(self) -> Context {
|
||||||
Context(ContextInner::Elem(Detail::Location(self)))
|
Context::new(Detail::Location(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::panic::Location;
|
use std::panic::Location;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{How, IntoContext, Context, ContextInner, Detail};
|
use crate::{How, IntoContext, Context, Detail};
|
||||||
#[cfg(feature = "backtrace")]
|
#[cfg(feature = "backtrace")]
|
||||||
use crate::context::Backtrace;
|
use crate::context::Backtrace;
|
||||||
|
|
||||||
|
@ -20,9 +20,15 @@ impl Explain for How {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn context(mut self, context: impl IntoContext) -> Self {
|
fn context(mut self, context: impl IntoContext) -> Self {
|
||||||
let mut context = context.into_context();
|
let mut context = context.into_context();
|
||||||
let loc = Detail::Location(*Location::caller());
|
|
||||||
|
context.extra.reserve(if cfg!(feature = "backtrace") {
|
||||||
|
2
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
});
|
||||||
|
context.extra.push(Detail::Location(*Location::caller()));
|
||||||
#[cfg(feature = "backtrace")]
|
#[cfg(feature = "backtrace")]
|
||||||
let bt = {
|
context.extra.push({
|
||||||
use std::backtrace::BacktraceStatus::*;
|
use std::backtrace::BacktraceStatus::*;
|
||||||
let bt = std::backtrace::Backtrace::capture();
|
let bt = std::backtrace::Backtrace::capture();
|
||||||
let bt = match bt.status() {
|
let bt = match bt.status() {
|
||||||
|
@ -31,19 +37,7 @@ impl Explain for How {
|
||||||
status => Backtrace::Other(status, bt.to_string()),
|
status => Backtrace::Other(status, bt.to_string()),
|
||||||
};
|
};
|
||||||
Detail::Backtrace(bt)
|
Detail::Backtrace(bt)
|
||||||
};
|
});
|
||||||
match context.0 {
|
|
||||||
ContextInner::Elem(elem) => {
|
|
||||||
#[cfg(not(feature = "backtrace"))]
|
|
||||||
let vec = vec![elem, loc];
|
|
||||||
#[cfg(feature = "backtrace")]
|
|
||||||
let vec = vec![elem, loc, bt];
|
|
||||||
context.0 = ContextInner::Compound(vec);
|
|
||||||
}
|
|
||||||
ContextInner::Compound(ref mut vec) => {
|
|
||||||
vec.insert(1, loc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.push_context(context);
|
self.push_context(context);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -89,7 +83,7 @@ where
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn context(self, context: impl IntoContext) -> Self::Output {
|
fn context(self, context: impl IntoContext) -> Self::Output {
|
||||||
How::new(Context(ContextInner::Elem(Detail::Error(self))))
|
How::new(Context::new(Detail::Error(self)))
|
||||||
.context(context)
|
.context(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#![feature(doc_auto_cfg)]
|
#![feature(doc_auto_cfg)]
|
||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
pub(crate) use context::{ContextInner, Detail};
|
pub(crate) use context::Detail;
|
||||||
pub use context::{Context, IntoContext};
|
pub use context::{Context, IntoContext};
|
||||||
|
|
||||||
mod report;
|
mod report;
|
||||||
|
|
Loading…
Reference in New Issue