Skip to main content

redevplugin_worker_sdk/
error.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::fmt;
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
7pub enum ErrorCode {
8    InvalidArgument,
9    PermissionDenied,
10    NotFound,
11    AlreadyExists,
12    ResourceClosed,
13    Canceled,
14    Timeout,
15    WouldBlock,
16    IoError,
17    MountUnavailable,
18    NetworkError,
19    ResourceLimit,
20    Internal,
21    RuntimeUnavailable,
22    RedirectRequiresReplay,
23    #[serde(other)]
24    Unknown,
25}
26
27#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
28pub struct Error {
29    pub code: ErrorCode,
30    pub message: String,
31    #[serde(default)]
32    pub retryable: bool,
33    #[serde(default)]
34    pub details: Value,
35}
36
37impl Error {
38    pub(crate) fn internal(message: impl Into<String>) -> Self {
39        Self {
40            code: ErrorCode::Internal,
41            message: message.into(),
42            retryable: false,
43            details: Value::Null,
44        }
45    }
46
47    pub(crate) fn from_abi_status(status: i32) -> Self {
48        let code = match status {
49            -1 => ErrorCode::InvalidArgument,
50            -2 => ErrorCode::PermissionDenied,
51            -3 => ErrorCode::NotFound,
52            -4 => ErrorCode::AlreadyExists,
53            -5 => ErrorCode::ResourceClosed,
54            -6 => ErrorCode::Canceled,
55            -7 => ErrorCode::Timeout,
56            -8 => ErrorCode::WouldBlock,
57            -9 => ErrorCode::IoError,
58            -10 => ErrorCode::NetworkError,
59            -11 => ErrorCode::ResourceLimit,
60            -12 => ErrorCode::Internal,
61            -13 => ErrorCode::RuntimeUnavailable,
62            -14 => ErrorCode::RedirectRequiresReplay,
63            -15 => ErrorCode::MountUnavailable,
64            _ => ErrorCode::Unknown,
65        };
66        Self {
67            code,
68            message: format!("Worker API hostcall failed with ABI status {status}"),
69            retryable: false,
70            details: Value::Null,
71        }
72    }
73}
74
75impl fmt::Display for Error {
76    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
77        write!(formatter, "{:?}: {}", self.code, self.message)
78    }
79}
80
81impl std::error::Error for Error {}
82
83pub type Result<T> = std::result::Result<T, Error>;
84
85#[cfg(test)]
86mod tests {
87    use super::{Error, ErrorCode};
88
89    #[test]
90    fn preserves_mount_unavailable_abi_status() {
91        assert_eq!(
92            Error::from_abi_status(-15).code,
93            ErrorCode::MountUnavailable
94        );
95    }
96}