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"
|
version = "0.4.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4421,6 +4422,7 @@ dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"paste",
|
"paste",
|
||||||
|
"retry-error",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"strum",
|
"strum",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|
|
@ -14,6 +14,7 @@ repository = "https://gitlab.torproject.org/tpo/core/arti.git/"
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
||||||
anyhow = "1.0.23"
|
anyhow = "1.0.23"
|
||||||
|
thiserror = "1"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
ADDED: fn fmt_error_with_sources
|
|
@ -41,7 +41,8 @@
|
||||||
//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
|
//! <!-- @@ end lint list maintained by maint/add_warning @@ -->
|
||||||
|
|
||||||
use std::error::Error;
|
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,
|
/// An error type for use when we're going to do something a few times,
|
||||||
/// and they might all fail.
|
/// 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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
// @@ begin test lint list maintained by maint/add_warning @@
|
// @@ begin test lint list maintained by maint/add_warning @@
|
||||||
|
|
|
@ -30,6 +30,7 @@ derive_more = "0.99.3"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
once_cell = "1"
|
once_cell = "1"
|
||||||
paste = "1"
|
paste = "1"
|
||||||
|
retry-error = { path = "../retry-error", version = "0.4.2" } # WRONG should be 0.4.3
|
||||||
static_assertions = { version = "1", optional = true }
|
static_assertions = { version = "1", optional = true }
|
||||||
strum = { version = "0.25", features = ["derive"] }
|
strum = { version = "0.25", features = ["derive"] }
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
|
|
|
@ -16,22 +16,9 @@ where
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
/// Non-generic inner function avoids code bloat
|
/// Non-generic inner function avoids code bloat
|
||||||
fn inner(mut e: &dyn StdError, f: &mut fmt::Formatter) -> fmt::Result {
|
fn inner(e: &dyn StdError, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "error")?;
|
write!(f, "error: ")?;
|
||||||
let mut last = String::new();
|
retry_error::fmt_error_with_sources(e, f)?;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue