1use serde::{Deserialize, Serialize};
4use std::fmt;
5
6#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub enum RuntimeKind {
10 Python,
12 #[serde(rename = "javascript")]
14 JavaScript,
15 Wasm,
17 Other(String),
19}
20
21impl RuntimeKind {
22 pub fn as_str(&self) -> &str {
24 match self {
25 Self::Python => "python",
26 Self::JavaScript => "javascript",
27 Self::Wasm => "wasm",
28 Self::Other(name) => name.as_str(),
29 }
30 }
31
32 pub fn parse(s: &str) -> Option<Self> {
34 match s.to_ascii_lowercase().as_str() {
35 "python" | "py" | "cpython" => Some(Self::Python),
36 "javascript" | "js" | "node" | "nodejs" => Some(Self::JavaScript),
37 "wasm" | "webassembly" | "wat" => Some(Self::Wasm),
38 other if !other.is_empty() => Some(Self::Other(other.to_string())),
39 _ => None,
40 }
41 }
42
43 pub fn extensions(&self) -> &'static [&'static str] {
45 match self {
46 Self::Python => &["py"],
47 Self::JavaScript => &["js", "mjs", "cjs"],
48 Self::Wasm => &["wasm", "wat"],
49 Self::Other(_) => &[],
50 }
51 }
52
53 pub fn from_path(path: &std::path::Path) -> Option<Self> {
58 let ext = path.extension()?.to_str()?.to_ascii_lowercase();
59 match ext.as_str() {
60 "py" => Some(Self::Python),
61 "js" | "mjs" | "cjs" | "jsx" => Some(Self::JavaScript),
62 "wasm" | "wat" => Some(Self::Wasm),
63 "ts" | "tsx" => Some(Self::Other("typescript".into())),
65 "go" => Some(Self::Other("go".into())),
66 "rs" => Some(Self::Other("rust".into())),
67 "java" => Some(Self::Other("java".into())),
68 "kt" | "kts" => Some(Self::Other("kotlin".into())),
69 "scala" | "sc" => Some(Self::Other("scala".into())),
70 "cs" | "csx" => Some(Self::Other("csharp".into())),
71 "fs" | "fsx" => Some(Self::Other("fsharp".into())),
72 "rb" => Some(Self::Other("ruby".into())),
73 "php" => Some(Self::Other("php".into())),
74 "pl" | "pm" => Some(Self::Other("perl".into())),
75 "lua" => Some(Self::Other("lua".into())),
76 "r" => Some(Self::Other("r".into())),
77 "jl" => Some(Self::Other("julia".into())),
78 "swift" => Some(Self::Other("swift".into())),
79 "dart" => Some(Self::Other("dart".into())),
80 "ex" | "exs" => Some(Self::Other("elixir".into())),
81 "erl" | "hrl" => Some(Self::Other("erlang".into())),
82 "hs" | "lhs" => Some(Self::Other("haskell".into())),
83 "ml" | "mli" => Some(Self::Other("ocaml".into())),
84 "clj" | "cljs" | "cljc" => Some(Self::Other("clojure".into())),
85 "c" | "h" => Some(Self::Other("c".into())),
86 "cpp" | "cc" | "cxx" | "hpp" | "hh" => Some(Self::Other("cpp".into())),
87 "zig" => Some(Self::Other("zig".into())),
88 "nim" => Some(Self::Other("nim".into())),
89 "cr" => Some(Self::Other("crystal".into())),
90 "sol" => Some(Self::Other("solidity".into())),
91 "ps1" | "psm1" => Some(Self::Other("powershell".into())),
92 "sh" | "bash" | "zsh" => Some(Self::Other("shell".into())),
93 "sql" => Some(Self::Other("sql".into())),
94 _ => None,
95 }
96 }
97}
98
99impl fmt::Display for RuntimeKind {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 write!(f, "{}", self.as_str())
102 }
103}
104
105#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
107#[serde(rename_all = "snake_case")]
108pub enum RuntimeStatus {
109 Ready,
111 Degraded {
113 reason: String,
115 },
116 Unavailable {
118 reason: String,
120 },
121}
122
123#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
125pub struct RuntimeMetadata {
126 pub kind: RuntimeKind,
128 pub name: String,
130 pub adapter_version: String,
132 pub host_version: Option<String>,
134 pub interface_version: u32,
136 pub description: String,
138}
139
140impl RuntimeMetadata {
141 pub fn builtin(
143 kind: RuntimeKind,
144 name: impl Into<String>,
145 description: impl Into<String>,
146 ) -> Self {
147 Self {
148 kind,
149 name: name.into(),
150 adapter_version: crate::PARALLAX_VERSION.to_string(),
151 host_version: None,
152 interface_version: crate::ADAPTER_INTERFACE_VERSION,
153 description: description.into(),
154 }
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn parse_aliases() {
164 assert_eq!(RuntimeKind::parse("py"), Some(RuntimeKind::Python));
165 assert_eq!(RuntimeKind::parse("node"), Some(RuntimeKind::JavaScript));
166 assert_eq!(RuntimeKind::parse("wat"), Some(RuntimeKind::Wasm));
167 }
168
169 #[test]
170 fn from_path() {
171 assert_eq!(
172 RuntimeKind::from_path(std::path::Path::new("demo.py")),
173 Some(RuntimeKind::Python)
174 );
175 }
176}