rapace_core/
error.rs

1//! Error codes and error types.
2
3use core::fmt;
4
5/// RPC error codes.
6///
7/// Codes 0-99 align with gRPC for familiarity.
8/// Codes 100+ are rapace-specific.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10#[repr(u32)]
11pub enum ErrorCode {
12    // gRPC-aligned (0-99)
13    Ok = 0,
14    Cancelled = 1,
15    DeadlineExceeded = 2,
16    InvalidArgument = 3,
17    NotFound = 4,
18    AlreadyExists = 5,
19    PermissionDenied = 6,
20    ResourceExhausted = 7,
21    FailedPrecondition = 8,
22    Aborted = 9,
23    OutOfRange = 10,
24    Unimplemented = 11,
25    Internal = 12,
26    Unavailable = 13,
27    DataLoss = 14,
28
29    // rapace-specific (100+)
30    PeerDied = 100,
31    SessionClosed = 101,
32    ValidationFailed = 102,
33    StaleGeneration = 103,
34}
35
36impl ErrorCode {
37    pub fn from_u32(value: u32) -> Option<Self> {
38        match value {
39            0 => Some(Self::Ok),
40            1 => Some(Self::Cancelled),
41            2 => Some(Self::DeadlineExceeded),
42            3 => Some(Self::InvalidArgument),
43            4 => Some(Self::NotFound),
44            5 => Some(Self::AlreadyExists),
45            6 => Some(Self::PermissionDenied),
46            7 => Some(Self::ResourceExhausted),
47            8 => Some(Self::FailedPrecondition),
48            9 => Some(Self::Aborted),
49            10 => Some(Self::OutOfRange),
50            11 => Some(Self::Unimplemented),
51            12 => Some(Self::Internal),
52            13 => Some(Self::Unavailable),
53            14 => Some(Self::DataLoss),
54            100 => Some(Self::PeerDied),
55            101 => Some(Self::SessionClosed),
56            102 => Some(Self::ValidationFailed),
57            103 => Some(Self::StaleGeneration),
58            _ => None,
59        }
60    }
61}
62
63impl fmt::Display for ErrorCode {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        match self {
66            Self::Ok => write!(f, "ok"),
67            Self::Cancelled => write!(f, "cancelled"),
68            Self::DeadlineExceeded => write!(f, "deadline exceeded"),
69            Self::InvalidArgument => write!(f, "invalid argument"),
70            Self::NotFound => write!(f, "not found"),
71            Self::AlreadyExists => write!(f, "already exists"),
72            Self::PermissionDenied => write!(f, "permission denied"),
73            Self::ResourceExhausted => write!(f, "resource exhausted"),
74            Self::FailedPrecondition => write!(f, "failed precondition"),
75            Self::Aborted => write!(f, "aborted"),
76            Self::OutOfRange => write!(f, "out of range"),
77            Self::Unimplemented => write!(f, "unimplemented"),
78            Self::Internal => write!(f, "internal error"),
79            Self::Unavailable => write!(f, "unavailable"),
80            Self::DataLoss => write!(f, "data loss"),
81            Self::PeerDied => write!(f, "peer died"),
82            Self::SessionClosed => write!(f, "session closed"),
83            Self::ValidationFailed => write!(f, "validation failed"),
84            Self::StaleGeneration => write!(f, "stale generation"),
85        }
86    }
87}
88
89/// Transport-level errors.
90#[derive(Debug)]
91pub enum TransportError {
92    Closed,
93    Io(std::io::Error),
94    Validation(ValidationError),
95    Encode(EncodeError),
96    Decode(DecodeError),
97}
98
99impl fmt::Display for TransportError {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        match self {
102            Self::Closed => write!(f, "transport closed"),
103            Self::Io(e) => write!(f, "I/O error: {e}"),
104            Self::Validation(e) => write!(f, "validation error: {e}"),
105            Self::Encode(e) => write!(f, "encode error: {e}"),
106            Self::Decode(e) => write!(f, "decode error: {e}"),
107        }
108    }
109}
110
111impl std::error::Error for TransportError {
112    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
113        match self {
114            Self::Io(e) => Some(e),
115            Self::Validation(e) => Some(e),
116            Self::Encode(e) => Some(e),
117            Self::Decode(e) => Some(e),
118            _ => None,
119        }
120    }
121}
122
123impl From<std::io::Error> for TransportError {
124    fn from(e: std::io::Error) -> Self {
125        Self::Io(e)
126    }
127}
128
129impl From<ValidationError> for TransportError {
130    fn from(e: ValidationError) -> Self {
131        Self::Validation(e)
132    }
133}
134
135impl From<EncodeError> for TransportError {
136    fn from(e: EncodeError) -> Self {
137        Self::Encode(e)
138    }
139}
140
141impl From<DecodeError> for TransportError {
142    fn from(e: DecodeError) -> Self {
143        Self::Decode(e)
144    }
145}
146
147/// Descriptor validation errors.
148#[derive(Debug, Clone, PartialEq, Eq)]
149pub enum ValidationError {
150    SlotOutOfBounds {
151        slot: u32,
152        max: u32,
153    },
154    PayloadOutOfBounds {
155        offset: u32,
156        len: u32,
157        slot_size: u32,
158    },
159    InlinePayloadTooLarge {
160        len: u32,
161        max: u32,
162    },
163    PayloadTooLarge {
164        len: u32,
165        max: u32,
166    },
167    StaleGeneration {
168        expected: u32,
169        actual: u32,
170    },
171    ChannelOutOfBounds {
172        channel: u32,
173        max: u32,
174    },
175    InvalidInlineDescriptor,
176}
177
178impl fmt::Display for ValidationError {
179    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180        match self {
181            Self::SlotOutOfBounds { slot, max } => {
182                write!(f, "slot {slot} out of bounds (max {max})")
183            }
184            Self::PayloadOutOfBounds {
185                offset,
186                len,
187                slot_size,
188            } => {
189                write!(
190                    f,
191                    "payload [{offset}..{offset}+{len}] exceeds slot size {slot_size}"
192                )
193            }
194            Self::InlinePayloadTooLarge { len, max } => {
195                write!(f, "inline payload {len} bytes exceeds max {max}")
196            }
197            Self::PayloadTooLarge { len, max } => {
198                write!(f, "payload {len} bytes exceeds max {max}")
199            }
200            Self::StaleGeneration { expected, actual } => {
201                write!(f, "stale generation: expected {expected}, got {actual}")
202            }
203            Self::ChannelOutOfBounds { channel, max } => {
204                write!(f, "channel {channel} out of bounds (max {max})")
205            }
206            Self::InvalidInlineDescriptor => {
207                write!(f, "inline descriptor has non-zero slot fields")
208            }
209        }
210    }
211}
212
213impl std::error::Error for ValidationError {}
214
215/// Encoding errors.
216#[derive(Debug)]
217pub enum EncodeError {
218    BufferTooSmall { needed: usize, available: usize },
219    EncodeFailed(String),
220    NoSlotAvailable,
221}
222
223impl fmt::Display for EncodeError {
224    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225        match self {
226            Self::BufferTooSmall { needed, available } => {
227                write!(f, "buffer too small: need {needed}, have {available}")
228            }
229            Self::EncodeFailed(msg) => write!(f, "encode failed: {msg}"),
230            Self::NoSlotAvailable => write!(f, "no slot available"),
231        }
232    }
233}
234
235impl std::error::Error for EncodeError {}
236
237/// Decoding errors.
238#[derive(Debug)]
239pub enum DecodeError {
240    UnexpectedEof,
241    InvalidData(String),
242    UnsupportedEncoding(u16),
243}
244
245impl fmt::Display for DecodeError {
246    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247        match self {
248            Self::UnexpectedEof => write!(f, "unexpected end of input"),
249            Self::InvalidData(msg) => write!(f, "invalid data: {msg}"),
250            Self::UnsupportedEncoding(enc) => write!(f, "unsupported encoding: {enc}"),
251        }
252    }
253}
254
255impl std::error::Error for DecodeError {}
256
257/// High-level RPC errors.
258#[derive(Debug)]
259pub enum RpcError {
260    Transport(TransportError),
261    Status { code: ErrorCode, message: String },
262    Cancelled,
263    DeadlineExceeded,
264}
265
266impl fmt::Display for RpcError {
267    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268        match self {
269            Self::Transport(e) => write!(f, "transport error: {e}"),
270            Self::Status { code, message } => write!(f, "{code}: {message}"),
271            Self::Cancelled => write!(f, "cancelled"),
272            Self::DeadlineExceeded => write!(f, "deadline exceeded"),
273        }
274    }
275}
276
277impl std::error::Error for RpcError {
278    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
279        match self {
280            Self::Transport(e) => Some(e),
281            _ => None,
282        }
283    }
284}
285
286impl From<TransportError> for RpcError {
287    fn from(e: TransportError) -> Self {
288        Self::Transport(e)
289    }
290}