Skip to main content

vox_types/
vox_error.rs

1use facet::Facet;
2use std::fmt;
3
4// r[rpc.fallible.vox-error]
5/// Protocol-level error wrapper distinguishing application errors from vox infrastructure errors.
6///
7/// On the caller side, all return types are wrapped as `Result<T, VoxError<E>>`:
8///   * Infallible `fn foo() -> T` becomes `Result<T, VoxError>`
9///   * Fallible `fn foo() -> Result<T, E>` becomes `Result<T, VoxError<E>>`
10#[derive(Debug, Clone, Facet)]
11#[repr(u8)]
12pub enum VoxError<E = ::core::convert::Infallible> {
13    /// The handler ran and returned an application error.
14    User(E),
15
16    /// No handler recognized the method ID.
17    UnknownMethod,
18
19    /// The arguments could not be deserialized.
20    InvalidPayload(String),
21
22    /// The call was cancelled before completion (e.g. handler dropped without replying).
23    Cancelled,
24
25    /// The underlying connection closed while the call was in flight.
26    ConnectionClosed,
27
28    /// The session shut down while the call was in flight.
29    SessionShutdown,
30
31    /// The call could not be sent because the transport is dead.
32    SendFailed,
33
34    /// The runtime refused to guess after recovery.
35    Indeterminate,
36}
37
38impl<E> VoxError<E> {
39    // r[impl rpc.fallible.vox-error.retryable]
40    // r[impl schema.errors.non-retryable]
41    /// Returns `true` if retrying the same operation on a fresh connection may succeed.
42    ///
43    /// `InvalidPayload`, `UnknownMethod`, `User`, `Cancelled`, and `Indeterminate`
44    /// are permanent failures — retrying them against the same peer will reproduce
45    /// the same outcome.
46    pub fn is_retryable(&self) -> bool {
47        matches!(
48            self,
49            Self::ConnectionClosed | Self::SessionShutdown | Self::SendFailed
50        )
51    }
52}
53
54impl<E: fmt::Display> fmt::Display for VoxError<E> {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        match self {
57            Self::User(error) => write!(f, "{error}"),
58            Self::UnknownMethod => f.write_str("unknown vox method call"),
59            Self::InvalidPayload(message) => write!(f, "invalid vox payload: {message}"),
60            Self::Cancelled => f.write_str("vox request cancelled"),
61            Self::ConnectionClosed => f.write_str("vox connection closed"),
62            Self::SessionShutdown => f.write_str("vox session shutdown"),
63            Self::SendFailed => f.write_str("vox send failed"),
64            Self::Indeterminate => f.write_str("indeterminate vox error"),
65        }
66    }
67}
68
69impl<E: fmt::Debug + fmt::Display> std::error::Error for VoxError<E> {}