retry-error: Provide fmt_error_with_sources in retry-error
This code came from tor-error. So now tor-error depends on retry-error.
This commit is contained in:
parent
dd5ceed791
commit
882ce8c8ce
|
@ -3065,6 +3065,7 @@ name = "retry-error"
|
|||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4421,6 +4422,7 @@ dependencies = [
|
|||
"futures",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"retry-error",
|
||||
"static_assertions",
|
||||
"strum",
|
||||
"thiserror",
|
||||
|
|
|
@ -14,6 +14,7 @@ repository = "https://gitlab.torproject.org/tpo/core/arti.git/"
|
|||
[dev-dependencies]
|
||||
|
||||
anyhow = "1.0.23"
|
||||
thiserror = "1"
|
||||
|
||||
[dependencies]
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ADDED: fn fmt_error_with_sources
|
|
@ -41,7 +41,8 @@
|
|||
//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Error as FmtError, Formatter};
|
||||
use std::fmt::{self, Debug, Display, Error as FmtError, Formatter};
|
||||
use std::iter;
|
||||
|
||||
/// An error type for use when we're going to do something a few times,
|
||||
/// and they might all fail.
|
||||
|
@ -227,6 +228,65 @@ impl<E: Display> Display for RetryError<E> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Helper: formats a [`std::error::Error`] and its sources (as `"error: source"`)
|
||||
///
|
||||
/// Avoids duplication in messages by not printing messages which are
|
||||
/// wholly-contained (textually) within already-printed messages.
|
||||
///
|
||||
/// Offered as a `fmt` function:
|
||||
/// this is for use in more-convenient higher-level error handling functionality,
|
||||
/// rather than directly in application/functional code.
|
||||
///
|
||||
/// This is used by `RetryError`'s impl of `Display`,
|
||||
/// but will be useful for other error-handling situations.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::fmt::{self, Display};
|
||||
///
|
||||
/// #[derive(Debug, thiserror::Error)]
|
||||
/// #[error("some pernickety problem")]
|
||||
/// struct Pernickety;
|
||||
///
|
||||
/// #[derive(Debug, thiserror::Error)]
|
||||
/// enum ApplicationError {
|
||||
/// #[error("everything is terrible")]
|
||||
/// Terrible(#[source] Pernickety),
|
||||
/// }
|
||||
///
|
||||
/// struct Wrapper(Box<dyn std::error::Error>);
|
||||
/// impl Display for Wrapper {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// retry_error::fmt_error_with_sources(&*self.0, f)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let bad = Pernickety;
|
||||
/// let err = ApplicationError::Terrible(bad);
|
||||
///
|
||||
/// let printed = Wrapper(err.into()).to_string();
|
||||
/// assert_eq!(printed, "everything is terrible: some pernickety problem");
|
||||
/// ```
|
||||
pub fn fmt_error_with_sources(mut e: &dyn Error, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut last = String::new();
|
||||
let mut sep = iter::once("").chain(iter::repeat(": "));
|
||||
loop {
|
||||
let this = e.to_string();
|
||||
if !last.contains(&this) {
|
||||
write!(f, "{}{}", sep.next().expect("repeat ended"), &this)?;
|
||||
}
|
||||
last = this;
|
||||
|
||||
if let Some(ne) = e.source() {
|
||||
e = ne;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
// @@ begin test lint list maintained by maint/add_warning @@
|
||||
|
|
|
@ -30,6 +30,7 @@ derive_more = "0.99.3"
|
|||
futures = "0.3"
|
||||
once_cell = "1"
|
||||
paste = "1"
|
||||
retry-error = { path = "../retry-error", version = "0.4.2" } # WRONG should be 0.4.3
|
||||
static_assertions = { version = "1", optional = true }
|
||||
strum = { version = "0.25", features = ["derive"] }
|
||||
thiserror = "1"
|
||||
|
|
|
@ -16,22 +16,9 @@ where
|
|||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// Non-generic inner function avoids code bloat
|
||||
fn inner(mut e: &dyn StdError, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "error")?;
|
||||
let mut last = String::new();
|
||||
loop {
|
||||
let this = e.to_string();
|
||||
if !last.contains(&this) {
|
||||
write!(f, ": {}", &this)?;
|
||||
}
|
||||
last = this;
|
||||
|
||||
if let Some(ne) = e.source() {
|
||||
e = ne;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fn inner(e: &dyn StdError, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "error: ")?;
|
||||
retry_error::fmt_error_with_sources(e, f)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue