Skip to content

Instantly share code, notes, and snippets.

@thomcc
Last active May 6, 2021 18:34
Show Gist options
  • Save thomcc/1257fcf79316e236514a072a26860c30 to your computer and use it in GitHub Desktop.
Save thomcc/1257fcf79316e236514a072a26860c30 to your computer and use it in GitHub Desktop.
/// Wrapper around an `impl std::error::Error` that makes it "mostly" clonable.
pub struct ClonableError<E> {
error: Option<E>,
// tbh these are all anybody cares about for Errors anyway.
display: Box<str>,
debug: Box<str>,
}
impl<E> Clone for ClonableError<E> {
#[inline]
fn clone(&self) -> Self {
Self {
// nobody will notice, probably.
error: None,
display: self.display.clone(),
debug: self.debug.clone(),
}
}
}
impl<E: std::error::Error> ClonableError<E> {
pub fn new(e: E) -> Self {
Self {
display: e.to_string().into(),
debug: format!("{:?}", e).into(),
error: Some(e),
}
}
}
impl<E: core::fmt::Debug> core::fmt::Debug for ClonableError<E> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if let Some(e) = &self.error {
core::fmt::Debug::fmt(e, f)
} else {
f.pad(&self.debug)
}
}
}
impl<E: core::fmt::Display> core::fmt::Display for ClonableError<E> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if let Some(e) = &self.error {
core::fmt::Display::fmt(e, f)
} else {
f.pad(&self.display)
}
}
}
impl<E: std::error::Error> std::error::Error for ClonableError<E> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
if let Some(e) = &self.error {
// Return `e.source()` rather than `E` because we're pretending that
// we're `E`. This might not make sense.
e.source()
} else {
None
}
}
}
impl<E: PartialEq> PartialEq for ClonableError<E> {
fn eq(&self, other: &Self) -> bool {
if let (Some(se), Some(oe)) = (&self.error, &other.error) {
se == oe
} else {
self.display == other.display && self.debug == other.debug
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment