Refactoring, improve output
This commit is contained in:
parent
41e071bccf
commit
bbc7df28d8
|
@ -1,19 +1,40 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
/// 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, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Context(ContextInner);
|
pub struct Context(ContextInner);
|
||||||
|
|
||||||
impl std::fmt::Display for Context {
|
impl fmt::Display for Context {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
#[inline(always)]
|
||||||
match self.0 {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
ContextInner::String(ref s) => f.write_str(s),
|
fmt::Display::fmt(&self.0, f)
|
||||||
ContextInner::Compound(ref ctxs) => {
|
}
|
||||||
let mut ctxs = ctxs.iter();
|
}
|
||||||
if let Some(ctx) = ctxs.next() {
|
|
||||||
write!(f, "{ctx}")?;
|
#[derive(Debug, Clone)]
|
||||||
for ctx in ctxs {
|
enum ContextInner {
|
||||||
write!(f, "\n{ctx}")?;
|
Elem(ContextElem),
|
||||||
|
Compound(Vec<ContextElem>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum ContextElem {
|
||||||
|
Str(&'static str),
|
||||||
|
String(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
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(())
|
Ok(())
|
||||||
|
@ -22,10 +43,13 @@ impl std::fmt::Display for Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
impl fmt::Display for ContextElem {
|
||||||
enum ContextInner {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
String(Cow<'static, str>),
|
match self {
|
||||||
Compound(Vec<Context>),
|
Self::Str(s) => f.write_str(s),
|
||||||
|
Self::String(s) => f.write_str(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IntoContext {
|
pub trait IntoContext {
|
||||||
|
@ -49,34 +73,48 @@ impl IntoContext for Context {
|
||||||
/// Chains another piece of context that is equal from a hierarchical perspective.
|
/// Chains another piece of context that is equal from a hierarchical perspective.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn chain(self, other: impl IntoContext) -> Self {
|
fn chain(self, other: impl IntoContext) -> Self {
|
||||||
Context(ContextInner::Compound(match self {
|
Context(ContextInner::Compound(match self.0 {
|
||||||
Context(ContextInner::Compound(mut items)) => {
|
ContextInner::Compound(mut elems) => {
|
||||||
items.push(other.into_context());
|
match other.into_context().0 {
|
||||||
items
|
ContextInner::Elem(elem) => elems.push(elem),
|
||||||
|
ContextInner::Compound(mut elems1) => elems.append(&mut elems1),
|
||||||
|
};
|
||||||
|
elems
|
||||||
}
|
}
|
||||||
_ => vec![self, other.into_context()],
|
ContextInner::Elem(elem) => {
|
||||||
|
match other.into_context().0 {
|
||||||
|
ContextInner::Elem(elem1) => vec![elem, elem1],
|
||||||
|
ContextInner::Compound(mut elems) => {
|
||||||
|
elems.insert(0, elem);
|
||||||
|
elems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoContext for String {
|
impl IntoContext for String {
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn into_context(self) -> Context {
|
fn into_context(self) -> Context {
|
||||||
Context(ContextInner::String(self.into()))
|
Context(ContextInner::Elem(ContextElem::String(self)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoContext for &'static str {
|
impl IntoContext for &'static str {
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn into_context(self) -> Context {
|
fn into_context(self) -> Context {
|
||||||
Context(ContextInner::String(self.into()))
|
Context(ContextInner::Elem(ContextElem::Str(self)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoContext for Cow<'static, str> {
|
impl IntoContext for Cow<'static, str> {
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn into_context(self) -> Context {
|
fn into_context(self) -> Context {
|
||||||
Context(ContextInner::String(self))
|
match self {
|
||||||
|
Cow::Borrowed(s) => s.into_context(),
|
||||||
|
Cow::Owned(s) => s.into_context(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ where
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn context(self, context: impl IntoContext) -> Self::Output {
|
fn context(self, context: impl IntoContext) -> Self::Output {
|
||||||
|
// TODO: maybe add a toggle for the extra "Option::None" context
|
||||||
|
//Err(How::new(context))
|
||||||
self.into_result_how().map_err(#[inline(never)] move |e| e.context(context))
|
self.into_result_how().map_err(#[inline(never)] move |e| e.context(context))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
33
src/how.rs
33
src/how.rs
|
@ -15,18 +15,6 @@ struct HowInner {
|
||||||
context: Vec<Context>,
|
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 {
|
impl How {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
|
@ -65,6 +53,16 @@ impl How {
|
||||||
pub const fn is_classified(&self) -> bool {
|
pub const fn is_classified(&self) -> bool {
|
||||||
self.0.classified
|
self.0.classified
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fmt_debug_alternate(&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 explain::Sealed for How {}
|
impl explain::Sealed for How {}
|
||||||
|
@ -99,3 +97,14 @@ impl std::fmt::Display for How {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for How {
|
||||||
|
#[inline(always)]
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if f.alternate() {
|
||||||
|
self.fmt_debug_alternate(f)
|
||||||
|
} else {
|
||||||
|
std::fmt::Display::fmt(self, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ impl<T> IntoResultHow for Option<T> {
|
||||||
fn into_result_how(self) -> Result<Self::T, How> {
|
fn into_result_how(self) -> Result<Self::T, How> {
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn into() -> How {
|
fn into() -> How {
|
||||||
How::new("None")
|
How::new("Option::None")
|
||||||
}
|
}
|
||||||
self.ok_or_else(into)
|
self.ok_or_else(into)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
#![feature(backtrace)]
|
||||||
|
|
||||||
mod sealed;
|
mod sealed;
|
||||||
pub(crate) use sealed::seal;
|
pub(crate) use sealed::seal;
|
||||||
|
|
Loading…
Reference in New Issue