redevplugin_worker_sdk/
error.rs1use 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
27impl ErrorCode {
28 pub fn as_str(&self) -> &'static str {
29 match self {
30 Self::InvalidArgument => "INVALID_ARGUMENT",
31 Self::PermissionDenied => "PERMISSION_DENIED",
32 Self::NotFound => "NOT_FOUND",
33 Self::AlreadyExists => "ALREADY_EXISTS",
34 Self::ResourceClosed => "RESOURCE_CLOSED",
35 Self::Canceled => "CANCELED",
36 Self::Timeout => "TIMEOUT",
37 Self::WouldBlock => "WOULD_BLOCK",
38 Self::IoError => "IO_ERROR",
39 Self::MountUnavailable => "MOUNT_UNAVAILABLE",
40 Self::NetworkError => "NETWORK_ERROR",
41 Self::ResourceLimit => "RESOURCE_LIMIT",
42 Self::Internal => "INTERNAL",
43 Self::RuntimeUnavailable => "RUNTIME_UNAVAILABLE",
44 Self::RedirectRequiresReplay => "REDIRECT_REQUIRES_REPLAY",
45 Self::Unknown => "UNKNOWN",
46 }
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
51pub struct Error {
52 pub code: ErrorCode,
53 pub message: String,
54 #[serde(default)]
55 pub retryable: bool,
56 #[serde(default)]
57 pub details: Value,
58}
59
60impl Error {
61 pub(crate) fn internal(message: impl Into<String>) -> Self {
62 Self {
63 code: ErrorCode::Internal,
64 message: message.into(),
65 retryable: false,
66 details: Value::Null,
67 }
68 }
69
70 pub(crate) fn from_abi_status(status: i32) -> Self {
71 let code = match status {
72 -1 => ErrorCode::InvalidArgument,
73 -2 => ErrorCode::PermissionDenied,
74 -3 => ErrorCode::NotFound,
75 -4 => ErrorCode::AlreadyExists,
76 -5 => ErrorCode::ResourceClosed,
77 -6 => ErrorCode::Canceled,
78 -7 => ErrorCode::Timeout,
79 -8 => ErrorCode::WouldBlock,
80 -9 => ErrorCode::IoError,
81 -10 => ErrorCode::NetworkError,
82 -11 => ErrorCode::ResourceLimit,
83 -12 => ErrorCode::Internal,
84 -13 => ErrorCode::RuntimeUnavailable,
85 -14 => ErrorCode::RedirectRequiresReplay,
86 -15 => ErrorCode::MountUnavailable,
87 _ => ErrorCode::Unknown,
88 };
89 Self {
90 code,
91 message: format!("Worker API hostcall failed with ABI status {status}"),
92 retryable: false,
93 details: Value::Null,
94 }
95 }
96}
97
98impl fmt::Display for Error {
99 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
100 write!(formatter, "{:?}: {}", self.code, self.message)
101 }
102}
103
104impl std::error::Error for Error {}
105
106pub type Result<T> = std::result::Result<T, Error>;
107
108#[cfg(test)]
109mod tests {
110 use super::{Error, ErrorCode};
111
112 #[test]
113 fn preserves_mount_unavailable_abi_status() {
114 assert_eq!(
115 Error::from_abi_status(-15).code,
116 ErrorCode::MountUnavailable
117 );
118 }
119}