use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeKind {
Python,
#[serde(rename = "javascript")]
JavaScript,
Wasm,
Other(String),
}
impl RuntimeKind {
pub fn as_str(&self) -> &str {
match self {
Self::Python => "python",
Self::JavaScript => "javascript",
Self::Wasm => "wasm",
Self::Other(name) => name.as_str(),
}
}
pub fn parse(s: &str) -> Option<Self> {
match s.to_ascii_lowercase().as_str() {
"python" | "py" | "cpython" => Some(Self::Python),
"javascript" | "js" | "node" | "nodejs" => Some(Self::JavaScript),
"wasm" | "webassembly" | "wat" => Some(Self::Wasm),
other if !other.is_empty() => Some(Self::Other(other.to_string())),
_ => None,
}
}
pub fn extensions(&self) -> &'static [&'static str] {
match self {
Self::Python => &["py"],
Self::JavaScript => &["js", "mjs", "cjs"],
Self::Wasm => &["wasm", "wat"],
Self::Other(_) => &[],
}
}
pub fn from_path(path: &std::path::Path) -> Option<Self> {
let ext = path.extension()?.to_str()?.to_ascii_lowercase();
match ext.as_str() {
"py" => Some(Self::Python),
"js" | "mjs" | "cjs" | "jsx" => Some(Self::JavaScript),
"wasm" | "wat" => Some(Self::Wasm),
"ts" | "tsx" => Some(Self::Other("typescript".into())),
"go" => Some(Self::Other("go".into())),
"rs" => Some(Self::Other("rust".into())),
"java" => Some(Self::Other("java".into())),
"kt" | "kts" => Some(Self::Other("kotlin".into())),
"scala" | "sc" => Some(Self::Other("scala".into())),
"cs" | "csx" => Some(Self::Other("csharp".into())),
"fs" | "fsx" => Some(Self::Other("fsharp".into())),
"rb" => Some(Self::Other("ruby".into())),
"php" => Some(Self::Other("php".into())),
"pl" | "pm" => Some(Self::Other("perl".into())),
"lua" => Some(Self::Other("lua".into())),
"r" => Some(Self::Other("r".into())),
"jl" => Some(Self::Other("julia".into())),
"swift" => Some(Self::Other("swift".into())),
"dart" => Some(Self::Other("dart".into())),
"ex" | "exs" => Some(Self::Other("elixir".into())),
"erl" | "hrl" => Some(Self::Other("erlang".into())),
"hs" | "lhs" => Some(Self::Other("haskell".into())),
"ml" | "mli" => Some(Self::Other("ocaml".into())),
"clj" | "cljs" | "cljc" => Some(Self::Other("clojure".into())),
"c" | "h" => Some(Self::Other("c".into())),
"cpp" | "cc" | "cxx" | "hpp" | "hh" => Some(Self::Other("cpp".into())),
"zig" => Some(Self::Other("zig".into())),
"nim" => Some(Self::Other("nim".into())),
"cr" => Some(Self::Other("crystal".into())),
"sol" => Some(Self::Other("solidity".into())),
"ps1" | "psm1" => Some(Self::Other("powershell".into())),
"sh" | "bash" | "zsh" => Some(Self::Other("shell".into())),
"sql" => Some(Self::Other("sql".into())),
_ => None,
}
}
}
impl fmt::Display for RuntimeKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RuntimeStatus {
Ready,
Degraded {
reason: String,
},
Unavailable {
reason: String,
},
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeMetadata {
pub kind: RuntimeKind,
pub name: String,
pub adapter_version: String,
pub host_version: Option<String>,
pub interface_version: u32,
pub description: String,
}
impl RuntimeMetadata {
pub fn builtin(
kind: RuntimeKind,
name: impl Into<String>,
description: impl Into<String>,
) -> Self {
Self {
kind,
name: name.into(),
adapter_version: crate::PARALLAX_VERSION.to_string(),
host_version: None,
interface_version: crate::ADAPTER_INTERFACE_VERSION,
description: description.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_aliases() {
assert_eq!(RuntimeKind::parse("py"), Some(RuntimeKind::Python));
assert_eq!(RuntimeKind::parse("node"), Some(RuntimeKind::JavaScript));
assert_eq!(RuntimeKind::parse("wat"), Some(RuntimeKind::Wasm));
}
#[test]
fn from_path() {
assert_eq!(
RuntimeKind::from_path(std::path::Path::new("demo.py")),
Some(RuntimeKind::Python)
);
}
}