Skip to main content

reliar_inbox/
error.rs

1//! [`crate::InboxStore::process`]'s error.
2
3use core::fmt;
4
5use reliar_core::{Classify, FailureKind};
6
7/// Whose fault it was. Split so the caller can tell "my handler failed" (record it, `nak`) from
8/// "the inbox could not be read or written" (record nothing, `nak`).
9///
10/// ```
11/// use reliar_inbox::InboxProcessError;
12///
13/// #[derive(Debug)]
14/// struct StoreError;
15/// impl std::fmt::Display for StoreError {
16///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17///         f.write_str("store unavailable")
18///     }
19/// }
20/// impl std::error::Error for StoreError {}
21///
22/// let err: InboxProcessError<StoreError, std::convert::Infallible> =
23///     InboxProcessError::Store(StoreError);
24/// assert_eq!(err.to_string(), "inbox store failed: store unavailable");
25/// ```
26#[derive(Debug)]
27#[non_exhaustive]
28pub enum InboxProcessError<S, H> {
29    /// [`crate::InboxStore::claim`] or [`crate::InboxStore::complete`] failed.
30    Store(S),
31
32    /// The [`crate::InboxHandler`] failed.
33    Handler(H),
34}
35
36impl<S, H> fmt::Display for InboxProcessError<S, H>
37where
38    S: std::error::Error,
39    H: std::error::Error,
40{
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        match self {
43            Self::Store(err) => write!(f, "inbox store failed: {err}"),
44            Self::Handler(err) => write!(f, "inbox handler failed: {err}"),
45        }
46    }
47}
48
49impl<S, H> std::error::Error for InboxProcessError<S, H>
50where
51    S: std::error::Error + 'static,
52    H: std::error::Error + 'static,
53{
54    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
55        match self {
56            Self::Store(err) => Some(err),
57            Self::Handler(err) => Some(err),
58        }
59    }
60}
61
62/// Maps [`Self::Store`] to the store error's own [`FailureKind`] and [`Self::Handler`] to
63/// **[`FailureKind::Transient`]** — a handler failure is retried by the broker's redelivery, and
64/// the inbox has no authority to call a message permanently dead (ADR 0042 §4).
65///
66/// ```
67/// use reliar_core::{Classify, FailureKind};
68/// use reliar_inbox::InboxProcessError;
69///
70/// #[derive(Debug)]
71/// struct StoreError;
72/// impl Classify for StoreError {
73///     fn kind(&self) -> FailureKind {
74///         FailureKind::Permanent
75///     }
76/// }
77///
78/// #[derive(Debug)]
79/// struct HandlerError;
80///
81/// // A handler failure is always `Transient`, regardless of the store error's own kind.
82/// let err: InboxProcessError<StoreError, HandlerError> = InboxProcessError::Handler(HandlerError);
83/// assert_eq!(err.kind(), FailureKind::Transient);
84/// ```
85impl<S, H> Classify for InboxProcessError<S, H>
86where
87    S: Classify,
88{
89    fn kind(&self) -> FailureKind {
90        match self {
91            Self::Store(err) => err.kind(),
92            Self::Handler(_) => FailureKind::Transient,
93        }
94    }
95}