grafos_std/
error.rs

1//! Error types for fabric resource operations.
2//!
3//! All fallible operations in grafos-std return [`Result<T>`], which is an
4//! alias for `core::result::Result<T, FabricError>`. The [`FabricError`]
5//! enum maps directly to the status codes returned by FBMU/FBBU host
6//! functions.
7
8use core::fmt;
9
10/// Errors returned by fabric resource operations.
11///
12/// Each variant corresponds to a well-defined failure mode in the fabricBIOS
13/// host API. The host functions return integer status codes which are
14/// translated into these variants by `FabricError::from_status`.
15///
16/// # Status code mapping
17///
18/// | Code | Variant |
19/// |------|---------|
20/// | 0 | Success (no error) |
21/// | -1 | [`Disconnected`](FabricError::Disconnected) |
22/// | -2 | [`LeaseExpired`](FabricError::LeaseExpired) |
23/// | -3 | [`Fenced`](FabricError::Fenced) |
24/// | -4 | [`CapacityExceeded`](FabricError::CapacityExceeded) |
25/// | -5 | [`Unsupported`](FabricError::Unsupported) |
26/// | -6 | [`Revoked`](FabricError::Revoked) |
27/// | other | [`IoError(code)`](FabricError::IoError) |
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub enum FabricError {
30    /// The lease for this resource has expired.
31    ///
32    /// Returned when an operation targets a resource whose lease has timed
33    /// out at the control-plane level. The resource may have been reclaimed
34    /// by the node.
35    LeaseExpired,
36
37    /// The lease was explicitly revoked.
38    ///
39    /// Returned when the resource's lease has been forcibly revoked by the
40    /// control plane (e.g. via REVOKE_BROADCAST, preemption, or WITHDRAW).
41    /// Unlike `LeaseExpired`, this is non-recoverable — the resource was
42    /// taken, not timed out.
43    Revoked,
44
45    /// The requested resource exceeds available capacity.
46    ///
47    /// Returned by builder `.acquire()` methods when the node cannot satisfy
48    /// the minimum capacity constraint, or by block I/O when the LBA is
49    /// out of range.
50    CapacityExceeded,
51
52    /// The resource has been fenced due to a teardown failure.
53    ///
54    /// A fenced resource cannot accept new leases. This is a terminal state
55    /// in the fabricBIOS lease model — the node detected that data-plane
56    /// teardown did not complete cleanly and has locked the resource to
57    /// prevent data corruption.
58    Fenced,
59
60    /// The connection to the remote node was lost.
61    ///
62    /// Indicates a transport-level failure (QUIC connection closed, network
63    /// timeout, or node crash). Retrying with a new connection may succeed
64    /// if the node recovers.
65    Disconnected,
66
67    /// An I/O error with a host-specific status code.
68    ///
69    /// Wraps any status code not covered by the well-known variants above.
70    /// The inner `i32` is the raw status code returned by the host function.
71    IoError(i32),
72
73    /// The requested operation is not supported.
74    ///
75    /// Returned by GPU and CPU modules whose host functions are not yet
76    /// implemented, or by nodes that do not expose the requested resource
77    /// type.
78    Unsupported,
79
80    /// A GPU session operation failed on the daemon side.
81    ///
82    /// The inner `u8` carries the raw
83    /// `fabricbios_core::gpu_session::SESSION_STATUS_*` code
84    /// (e.g. `SESSION_STATUS_INVALID_HANDLE = 3`,
85    /// `SESSION_STATUS_NO_CONTEXT = 2`). Positive, non-zero status values
86    /// returned by the `fabricbios_gpu_v1` hostcalls surface as this
87    /// variant; transport- and lease-level failures still map to the
88    /// existing [`FabricError`] variants via [`FabricError::from_status`].
89    GpuSessionFailed(u8),
90}
91
92impl fmt::Display for FabricError {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        match self {
95            FabricError::LeaseExpired => write!(f, "lease expired"),
96            FabricError::Revoked => write!(f, "lease revoked"),
97            FabricError::CapacityExceeded => write!(f, "capacity exceeded"),
98            FabricError::Fenced => write!(f, "resource fenced"),
99            FabricError::Disconnected => write!(f, "disconnected"),
100            FabricError::IoError(code) => write!(f, "I/O error (status {code})"),
101            FabricError::Unsupported => write!(f, "unsupported"),
102            FabricError::GpuSessionFailed(code) => {
103                write!(f, "GPU session op failed (SESSION_STATUS_{code})")
104            }
105        }
106    }
107}
108
109#[cfg(feature = "std")]
110impl std::error::Error for FabricError {}
111
112/// Alias for `core::result::Result<T, FabricError>`.
113///
114/// This is the return type for all fallible operations in grafos-std.
115pub type Result<T> = core::result::Result<T, FabricError>;
116
117impl FabricError {
118    /// Convert a host function status code to a `FabricError`.
119    ///
120    /// Status 0 is success and returns `None`. Negative values map to
121    /// specific error variants as documented on [`FabricError`].
122    pub(crate) fn from_status(status: i32) -> Option<FabricError> {
123        match status {
124            0 => None,
125            -1 => Some(FabricError::Disconnected),
126            -2 => Some(FabricError::LeaseExpired),
127            -3 => Some(FabricError::Fenced),
128            -4 => Some(FabricError::CapacityExceeded),
129            -5 => Some(FabricError::Unsupported),
130            -6 => Some(FabricError::Revoked),
131            other => Some(FabricError::IoError(other)),
132        }
133    }
134}