use std::error::Error;
pub trait CleanedErrors {
fn cleaned_errors<'a, 'b, 'c>(&'a self) -> CleanedErrorText<'b, 'c>
where
'a: 'b;
}
impl<T: Error + 'static> CleanedErrors for T {
fn cleaned_errors<'a, 'b, 'c>(&'a self) -> CleanedErrorText<'b, 'c>
where
'a: 'b,
{
CleanedErrorText::new(self)
}
}
pub struct CleanedErrorText<'a, 'b>(Option<CleanedErrorTextStep<'a, 'b>>);
struct CleanedErrorTextStep<'a, 'b> {
error: &'a (dyn Error + 'b),
error_text: String,
}
impl<'a, 'b> CleanedErrorTextStep<'a, 'b> {
fn new(err: &'a (dyn Error + 'b)) -> Self {
Self {
error: err,
error_text: err.to_string(),
}
}
}
impl<'a, 'b> CleanedErrorText<'a, 'b> {
pub fn new(err: &'a (dyn Error + 'b)) -> Self {
Self(Some(CleanedErrorTextStep::new(err)))
}
}
impl<'a, 'b> Iterator for CleanedErrorText<'a, 'b> {
type Item = (&'a (dyn Error + 'b), String, bool);
fn next(&mut self) -> Option<Self::Item> {
let step = self.0.take()?;
let error_text = step.error_text;
let err = step.error;
match err.source() {
Some(source) => {
let source_text = source.to_string();
let (cleaned_text, cleaned) = error_text
.strip_suffix(&source_text)
.map(|text| {
let text = text.trim_end();
(text.strip_suffix(':').unwrap_or(text).to_owned(), true)
})
.unwrap_or_else(|| (error_text, false));
self.0 = Some(CleanedErrorTextStep {
error: source,
error_text: source_text,
});
Some((err, cleaned_text, cleaned))
}
None => Some((err, error_text, false)),
}
}
}