ferridriver_script/
error.rs1use std::fmt;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
7#[serde(rename_all = "snake_case")]
8pub enum ScriptErrorKind {
9 Syntax,
11 Runtime,
13 Timeout,
15 MemoryLimit,
17 SandboxViolation,
19 Internal,
21}
22
23impl fmt::Display for ScriptErrorKind {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 Self::Syntax => write!(f, "syntax_error"),
27 Self::Runtime => write!(f, "runtime_error"),
28 Self::Timeout => write!(f, "timeout"),
29 Self::MemoryLimit => write!(f, "memory_limit"),
30 Self::SandboxViolation => write!(f, "sandbox_violation"),
31 Self::Internal => write!(f, "internal_error"),
32 }
33 }
34}
35
36#[derive(Debug, Clone, serde::Serialize)]
42pub struct ScriptError {
43 pub kind: ScriptErrorKind,
44 pub message: String,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub stack: Option<String>,
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub line: Option<u32>,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub column: Option<u32>,
51 #[serde(skip_serializing_if = "Option::is_none")]
52 pub source_snippet: Option<String>,
53}
54
55impl ScriptError {
56 #[must_use]
57 pub fn internal(message: impl Into<String>) -> Self {
58 Self {
59 kind: ScriptErrorKind::Internal,
60 message: message.into(),
61 stack: None,
62 line: None,
63 column: None,
64 source_snippet: None,
65 }
66 }
67
68 #[must_use]
69 pub fn timeout(elapsed_ms: u64, limit_ms: u64) -> Self {
70 Self {
71 kind: ScriptErrorKind::Timeout,
72 message: format!("script exceeded timeout: {elapsed_ms}ms > {limit_ms}ms"),
73 stack: None,
74 line: None,
75 column: None,
76 source_snippet: None,
77 }
78 }
79
80 #[must_use]
81 pub fn memory_limit(limit_bytes: usize) -> Self {
82 Self {
83 kind: ScriptErrorKind::MemoryLimit,
84 message: format!("script exceeded memory limit of {limit_bytes} bytes"),
85 stack: None,
86 line: None,
87 column: None,
88 source_snippet: None,
89 }
90 }
91
92 #[must_use]
93 pub fn sandbox(message: impl Into<String>) -> Self {
94 Self {
95 kind: ScriptErrorKind::SandboxViolation,
96 message: message.into(),
97 stack: None,
98 line: None,
99 column: None,
100 source_snippet: None,
101 }
102 }
103}
104
105impl fmt::Display for ScriptError {
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 write!(f, "[{}] {}", self.kind, self.message)?;
108 if let (Some(l), Some(c)) = (self.line, self.column) {
109 write!(f, " (at {l}:{c})")?;
110 }
111 Ok(())
112 }
113}
114
115impl std::error::Error for ScriptError {}