From 8f1c7d9765a80403903e4314bca8ebc39325834e Mon Sep 17 00:00:00 2001 From: Michael Pfaff Date: Sat, 1 Jul 2023 11:41:21 -0400 Subject: [PATCH] Refactored Context --- src/context.rs | 72 +++++++++++++++++--------------------------------- src/explain.rs | 28 ++++++++------------ src/lib.rs | 2 +- 3 files changed, 36 insertions(+), 66 deletions(-) diff --git a/src/context.rs b/src/context.rs index fedc31b..c02cc4a 100644 --- a/src/context.rs +++ b/src/context.rs @@ -8,22 +8,28 @@ use std::sync::Arc; /// Provides context furthering the explanation of *how* you got to an error. #[derive(Debug)] #[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, +} + +impl Context { + pub(crate) fn new(detail: Detail) -> Self { + Self { detail, extra: Vec::new() } + } +} impl fmt::Display for Context { #[inline(always)] 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), -} - #[derive(Debug)] #[cfg_attr(feature = "clone-with-caveats", derive(Clone))] 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 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -117,38 +105,26 @@ impl IntoContext for Context { /// Chains another piece of context that is a child from a hierarchical perspective. #[track_caller] #[inline] - fn with(self, other: impl IntoContext) -> Self { - let other = other.into_context().0; - Context(ContextInner::Compound(match self.0 { - ContextInner::Compound(mut elems) => { - match other { - ContextInner::Elem(elem) => elems.push(elem), - 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 - } - }, - })) + fn with(mut self, other: impl IntoContext) -> Self { + let mut other = other.into_context(); + self.extra.reserve(1 + other.extra.len()); + self.extra.push(other.detail); + self.extra.append(&mut other.extra); + self } } impl IntoContext for String { #[inline(always)] fn into_context(self) -> Context { - Context(ContextInner::Elem(Detail::String(self))) + Context::new(Detail::String(self)) } } impl IntoContext for &'static str { #[inline(always)] 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> { #[inline] fn into_context(self) -> Context { - Context(ContextInner::Elem(Detail::Location(self))) + Context::new(Detail::Location(self)) } } diff --git a/src/explain.rs b/src/explain.rs index 9853c70..3acdeab 100644 --- a/src/explain.rs +++ b/src/explain.rs @@ -1,7 +1,7 @@ use std::panic::Location; use std::sync::Arc; -use crate::{How, IntoContext, Context, ContextInner, Detail}; +use crate::{How, IntoContext, Context, Detail}; #[cfg(feature = "backtrace")] use crate::context::Backtrace; @@ -20,9 +20,15 @@ impl Explain for How { #[inline] fn context(mut self, context: impl IntoContext) -> Self { 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")] - let bt = { + context.extra.push({ use std::backtrace::BacktraceStatus::*; let bt = std::backtrace::Backtrace::capture(); let bt = match bt.status() { @@ -31,19 +37,7 @@ impl Explain for How { status => Backtrace::Other(status, bt.to_string()), }; 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 } @@ -89,7 +83,7 @@ where #[track_caller] 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) } } diff --git a/src/lib.rs b/src/lib.rs index 40351ce..bdc4cfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ #![feature(doc_auto_cfg)] mod context; -pub(crate) use context::{ContextInner, Detail}; +pub(crate) use context::Detail; pub use context::{Context, IntoContext}; mod report;