eventbus_core/error.rs
1use thiserror::Error;
2
3/// Errors returned by the event bus.
4///
5/// The enum is marked `#[non_exhaustive]` so new variants can be added in a
6/// non-breaking way; external crates must include a `_ => ...` arm when
7/// matching exhaustively.
8///
9/// Prefer [`EventBusError::source`] when wrapping an underlying error from a
10/// backend or codec — it preserves the causal chain via [`std::error::Error::source`],
11/// allowing tracing/observability stacks to render the full chain without
12/// losing typed information to stringification.
13#[derive(Debug, Error)]
14#[non_exhaustive]
15pub enum EventBusError {
16 #[error("internal error: {0}")]
17 Internal(String),
18
19 #[error("validation error: {0}")]
20 Validation(String),
21
22 #[error("serialization error: {0}")]
23 Serialization(String),
24
25 #[error("invalid state transition: {from} -> {to}")]
26 InvalidTransition { from: String, to: String },
27
28 #[error("connection error: {0}")]
29 Connection(String),
30
31 #[error("timeout: {0}")]
32 Timeout(String),
33
34 /// An underlying error from a backend, codec, or dependency, with its
35 /// source chain preserved. Construct via [`EventBusError::source`].
36 #[error("{context}")]
37 Source {
38 context: String,
39 #[source]
40 source: Box<dyn std::error::Error + Send + Sync + 'static>,
41 },
42}
43
44impl EventBusError {
45 /// Wrap an underlying error with a human-readable context string while
46 /// preserving the source chain for `error.source()` traversal.
47 ///
48 /// # Example
49 ///
50 /// ```no_run
51 /// use eventbus_core::EventBusError;
52 ///
53 /// fn parse_int(s: &str) -> Result<u32, EventBusError> {
54 /// s.parse::<u32>()
55 /// .map_err(|e| EventBusError::source("parsing retry attempt", e))
56 /// }
57 /// ```
58 pub fn source<E>(context: impl Into<String>, err: E) -> Self
59 where
60 E: std::error::Error + Send + Sync + 'static,
61 {
62 Self::Source {
63 context: context.into(),
64 source: Box::new(err),
65 }
66 }
67}