Expose Detail
- Add some accessor methods on `Context` - Wrap some variants in private structs to prevent people from depending on them - Add some #[inline]
This commit is contained in:
parent
52bcd3c17b
commit
db067003d8
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||
[features]
|
||||
default = []
|
||||
backtrace = []
|
||||
extra-backtrace = ["backtrace"]
|
||||
clone-with-caveats = []
|
||||
termination = ["dep:ansee"]
|
||||
|
||||
|
|
|
@ -20,6 +20,26 @@ impl Context {
|
|||
pub(crate) fn new(detail: Detail) -> Self {
|
||||
Self { detail, extra: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn detail(&self) -> &Detail {
|
||||
&self.detail
|
||||
}
|
||||
|
||||
pub fn extra(&self) -> &[Detail] {
|
||||
&self.extra
|
||||
}
|
||||
|
||||
pub fn detail_mut(&mut self) -> &mut Detail {
|
||||
&mut self.detail
|
||||
}
|
||||
|
||||
pub fn extra_mut(&mut self) -> &mut [Detail] {
|
||||
&mut self.extra
|
||||
}
|
||||
|
||||
pub fn pop_extra(&mut self) -> Option<Detail> {
|
||||
self.extra.pop()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Context {
|
||||
|
@ -37,15 +57,39 @@ impl fmt::Display for Context {
|
|||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "clone-with-caveats", derive(Clone))]
|
||||
pub(crate) enum Detail {
|
||||
#[non_exhaustive]
|
||||
pub enum Detail {
|
||||
Str(&'static str),
|
||||
String(String),
|
||||
Location(Location<'static>),
|
||||
#[cfg(feature = "backtrace")]
|
||||
Backtrace(Backtrace),
|
||||
Error(Arc<dyn std::error::Error + Send + Sync>),
|
||||
Backtrace(PrivateBacktrace),
|
||||
Error(PrivateError),
|
||||
}
|
||||
|
||||
impl Detail {
|
||||
#[cfg(feature = "backtrace")]
|
||||
#[track_caller]
|
||||
pub fn backtrace() -> Self {
|
||||
use std::backtrace::BacktraceStatus::*;
|
||||
let bt = std::backtrace::Backtrace::capture();
|
||||
let bt = match bt.status() {
|
||||
Disabled => Backtrace::Disabled,
|
||||
Unsupported => Backtrace::Unsupported,
|
||||
status => Backtrace::Other(status, bt.to_string()),
|
||||
};
|
||||
Self::Backtrace(PrivateBacktrace(bt))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PrivateError(pub(crate) Arc<dyn std::error::Error + Send + Sync>);
|
||||
|
||||
#[cfg(feature = "backtrace")]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "clone-with-caveats", derive(Clone))]
|
||||
pub struct PrivateBacktrace(pub(crate) Backtrace);
|
||||
|
||||
// will be replaced with std::backtrace::Backtrace if and when it is Clone
|
||||
#[cfg(feature = "backtrace")]
|
||||
#[derive(Debug)]
|
||||
|
@ -69,11 +113,11 @@ impl fmt::Display for Detail {
|
|||
Self::String(s) => f.write_str(s),
|
||||
Self::Location(l) => write!(f, "At {l}"),
|
||||
#[cfg(feature = "backtrace")]
|
||||
Self::Backtrace(Backtrace::Unsupported) => f.write_str("I'd like to show you a backtrace,\n but it's not supported on your platform"),
|
||||
Self::Backtrace(PrivateBacktrace(Backtrace::Unsupported)) => f.write_str("I'd like to show you a backtrace,\n but it's not supported on your platform"),
|
||||
#[cfg(feature = "backtrace")]
|
||||
Self::Backtrace(Backtrace::Disabled) => f.write_str("If you'd like a backtrace,\n try again with RUST_BACKTRACE=1"),
|
||||
Self::Backtrace(PrivateBacktrace(Backtrace::Disabled)) => f.write_str("If you'd like a backtrace,\n try again with RUST_BACKTRACE=1"),
|
||||
#[cfg(feature = "backtrace")]
|
||||
Self::Backtrace(Backtrace::Other(status, bt)) => {
|
||||
Self::Backtrace(PrivateBacktrace(Backtrace::Other(status, bt))) => {
|
||||
f.write_str(if *status == BacktraceStatus::Captured {
|
||||
"Here is the backtrace:\n"
|
||||
} else {
|
||||
|
@ -81,7 +125,7 @@ impl fmt::Display for Detail {
|
|||
})?;
|
||||
write!(f, "{}", bt)
|
||||
},
|
||||
Self::Error(e) => e.fmt(f),
|
||||
Self::Error(PrivateError(e)) => e.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,7 @@ use std::panic::Location;
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::{How, IntoContext, Context, Detail};
|
||||
#[cfg(feature = "backtrace")]
|
||||
use crate::context::Backtrace;
|
||||
use crate::context::PrivateError;
|
||||
|
||||
pub trait Explain {
|
||||
type Output;
|
||||
|
@ -21,23 +20,14 @@ impl Explain for How {
|
|||
fn context(mut self, context: impl IntoContext) -> Self {
|
||||
let mut context = context.into_context();
|
||||
|
||||
context.extra.reserve(if cfg!(feature = "backtrace") {
|
||||
context.extra.reserve(if cfg!(feature = "extra-backtrace") {
|
||||
2
|
||||
} else {
|
||||
1
|
||||
});
|
||||
context.extra.push(Detail::Location(*Location::caller()));
|
||||
#[cfg(feature = "backtrace")]
|
||||
context.extra.push({
|
||||
use std::backtrace::BacktraceStatus::*;
|
||||
let bt = std::backtrace::Backtrace::capture();
|
||||
let bt = match bt.status() {
|
||||
Disabled => Backtrace::Disabled,
|
||||
Unsupported => Backtrace::Unsupported,
|
||||
status => Backtrace::Other(status, bt.to_string()),
|
||||
};
|
||||
Detail::Backtrace(bt)
|
||||
});
|
||||
#[cfg(feature = "extra-backtrace")]
|
||||
context.extra.push(Detail::backtrace());
|
||||
self.push_context(context);
|
||||
self
|
||||
}
|
||||
|
@ -83,7 +73,7 @@ where
|
|||
|
||||
#[track_caller]
|
||||
fn context(self, context: impl IntoContext) -> Self::Output {
|
||||
How::new(Context::new(Detail::Error(self)))
|
||||
How::new(Context::new(Detail::Error(PrivateError(self))))
|
||||
.context(context)
|
||||
}
|
||||
}
|
||||
|
|
44
src/how.rs
44
src/how.rs
|
@ -25,17 +25,23 @@ impl How {
|
|||
#[track_caller]
|
||||
pub fn new(context: impl IntoContext) -> Self {
|
||||
let location = Location::caller();
|
||||
Self(Box::new(HowInner {
|
||||
#[allow(unused_mut)]
|
||||
let mut how = Self(Box::new(HowInner {
|
||||
location,
|
||||
context: Vec::with_capacity(4),
|
||||
}))
|
||||
.context(context)
|
||||
.context(context);
|
||||
#[cfg(all(feature = "backtrace", not(feature = "extra-backtrace")))]
|
||||
how.top_mut().extra.push(Detail::backtrace());
|
||||
how
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn location(&self) -> &'static Location {
|
||||
self.0.location
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn top(&self) -> &Context {
|
||||
// SAFETY: we only ever push values into context, and the constructor ensures that there
|
||||
// is at least 1 value in context.
|
||||
|
@ -50,6 +56,7 @@ impl How {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bottom(&self) -> &Context {
|
||||
// SAFETY: we only ever push values into context, and the constructor ensures that there
|
||||
// is at least 1 value in context.
|
||||
|
@ -64,6 +71,37 @@ impl How {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn top_mut(&mut self) -> &mut Context {
|
||||
// SAFETY: we only ever push values into context, and the constructor ensures that there
|
||||
// is at least 1 value in context.
|
||||
let o = self.0.context.iter_mut().next();
|
||||
if cfg!(debug_assertions) {
|
||||
o.unwrap()
|
||||
} else {
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
o.unwrap_unchecked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bottom_mut(&mut self) -> &mut Context {
|
||||
// SAFETY: we only ever push values into context, and the constructor ensures that there
|
||||
// is at least 1 value in context.
|
||||
let o = self.0.context.iter_mut().next_back();
|
||||
if cfg!(debug_assertions) {
|
||||
o.unwrap()
|
||||
} else {
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
o.unwrap_unchecked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_context(self) -> impl Iterator<Item = Context> {
|
||||
self.0.context.into_iter()
|
||||
}
|
||||
|
@ -75,6 +113,7 @@ impl How {
|
|||
b.finish()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn push_context(&mut self, context: Context) {
|
||||
self.0.context.push(context);
|
||||
}
|
||||
|
@ -90,6 +129,7 @@ impl Clone for HowInner {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clone_from(&mut self, source: &Self) {
|
||||
self.location = source.location;
|
||||
self.context.clone_from(&source.context);
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
#![feature(doc_auto_cfg)]
|
||||
|
||||
mod context;
|
||||
pub(crate) use context::Detail;
|
||||
pub use context::{Context, IntoContext};
|
||||
pub use context::{Context, Detail, IntoContext};
|
||||
|
||||
mod report;
|
||||
pub use report::{Report, ReportOpts};
|
||||
|
|
Loading…
Reference in New Issue