1use std::error::Error;
2use std::fmt::{self, Display, Formatter};
3use std::sync::atomic::{AtomicBool, Ordering};
4
5#[derive(Debug)]
7pub struct AsyncError<E: Error + 'static> {
8 error: E,
9 context: Option<String>,
10 hooks_invoked: AtomicBool,
11}
12
13impl<E: Error + 'static> AsyncError<E> {
14 pub fn new(error: E) -> Self {
16 Self {
17 error,
18 context: None,
19 hooks_invoked: AtomicBool::new(false),
20 }
21 }
22
23 pub fn with_context(mut self, context: String) -> Self {
27 self.context = Some(context);
28 #[cfg(feature = "hooks")]
29 {
30 crate::hooks::invoke_hooks(&self);
31 }
32 self
33 }
34
35 pub fn inner_error(&self) -> &E {
37 &self.error
38 }
39
40 pub fn context(&self) -> Option<&str> {
42 self.context.as_deref()
43 }
44
45 pub fn invoke_hooks_once(&self) -> bool {
47 self.hooks_invoked
48 .compare_exchange(false, true, Ordering::SeqCst, Ordering::Relaxed)
49 .is_ok()
50 }
51}
52
53impl<E: Error + 'static> Display for AsyncError<E> {
54 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
55 match &self.context {
56 Some(ctx) if !ctx.trim().is_empty() => write!(f, "{}: {}", ctx, self.error),
57 _ => write!(f, "{}", self.error),
58 }
59 }
60}
61
62impl<E: Error + 'static> Error for AsyncError<E> {
63 fn source(&self) -> Option<&(dyn Error + 'static)> {
64 Some(&self.error)
65 }
66}