use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::sync::atomic::{AtomicBool, Ordering};
#[derive(Debug)]
pub struct AsyncError<E: Error + 'static> {
error: E,
context: Option<String>,
hooks_invoked: AtomicBool,
}
impl<E: Error + 'static> AsyncError<E> {
pub fn new(error: E) -> Self {
Self {
error,
context: None,
hooks_invoked: AtomicBool::new(false),
}
}
pub fn with_context(mut self, context: String) -> Self {
self.context = Some(context);
#[cfg(feature = "hooks")]
{
crate::hooks::invoke_hooks(&self);
}
self
}
pub fn inner_error(&self) -> &E {
&self.error
}
pub fn context(&self) -> Option<&str> {
self.context.as_deref()
}
pub fn invoke_hooks_once(&self) -> bool {
self.hooks_invoked
.compare_exchange(false, true, Ordering::SeqCst, Ordering::Relaxed)
.is_ok()
}
}
impl<E: Error + 'static> Display for AsyncError<E> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match &self.context {
Some(ctx) if !ctx.trim().is_empty() => write!(f, "{}: {}", ctx, self.error),
_ => write!(f, "{}", self.error),
}
}
}
impl<E: Error + 'static> Error for AsyncError<E> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.error)
}
}