use std::{fmt, path::Path};
use serde::{Deserialize, Serialize};
#[cfg(feature = "api")]
use utoipa::ToSchema;
use super::runner_error_types::RunnerErrorType;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "api", derive(ToSchema))]
pub enum LanguageName {
Python,
Cpp,
C,
Rust,
Ruby,
Javascript,
Java,
}
impl fmt::Display for LanguageName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LanguageName::Python => write!(f, "python"),
LanguageName::Cpp => write!(f, "cpp"),
LanguageName::C => write!(f, "c"),
LanguageName::Rust => write!(f, "rust"),
LanguageName::Ruby => write!(f, "ruby"),
LanguageName::Javascript => write!(f, "javascript"),
LanguageName::Java => write!(f, "java"),
}
}
}
impl TryFrom<String> for LanguageName {
type Error = String;
fn try_from(s: String) -> Result<Self, Self::Error> {
match s.to_lowercase().as_str() {
"python" => Ok(LanguageName::Python),
"cpp" => Ok(LanguageName::Cpp),
"c" => Ok(LanguageName::C),
"rust" => Ok(LanguageName::Rust),
"ruby" => Ok(LanguageName::Ruby),
"javascript" => Ok(LanguageName::Javascript),
"java" => Ok(LanguageName::Java),
other => Err(format!(
"{other} is not a supported language. Use either `python`, `cpp`, `c`, `rust`, `ruby`, `javascript` or `java`."
)),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum CompilationType {
Compiled, Interpreted, BytecodeCompiled, }
impl TryFrom<&Path> for LanguageName {
type Error = RunnerErrorType;
fn try_from(file_path: &Path) -> Result<Self, Self::Error> {
match file_path.extension().and_then(|ext| ext.to_str()) {
Some("rs") => Ok(LanguageName::Rust),
Some("py") => Ok(LanguageName::Python),
Some("c") => Ok(LanguageName::C),
Some("cpp") | Some("cxx") | Some("c++") | Some("cc") | Some("C") => {
Ok(LanguageName::Cpp)
}
Some("java") => Ok(LanguageName::Java),
Some("js") => Ok(LanguageName::Javascript),
Some("rb") => Ok(LanguageName::Ruby),
Some(_) => Err(RunnerErrorType::UnsupportedLanguage(
file_path.to_path_buf(),
)),
None => Err(RunnerErrorType::InvalidFileExtension(
file_path.to_path_buf(),
)),
}
}
}
pub(super) fn get_programming_language_name(file_path: &Path) -> Option<LanguageName> {
LanguageName::try_from(file_path).ok()
}
impl LanguageName {
pub(crate) fn file_extension(&self) -> &'static str {
match self {
LanguageName::Rust => "rs",
LanguageName::Python => "py",
LanguageName::C => "c",
LanguageName::Cpp => "cpp",
LanguageName::Java => "java",
LanguageName::Javascript => "js",
LanguageName::Ruby => "rb",
}
}
}
pub(super) fn get_file_extension(lang_name: &LanguageName) -> &'static str {
lang_name.file_extension()
}
pub(super) fn get_language_compilation_type(lang_name: &LanguageName) -> CompilationType {
match lang_name {
LanguageName::Rust | LanguageName::Cpp | LanguageName::C => CompilationType::Compiled,
LanguageName::Python | LanguageName::Ruby | LanguageName::Javascript => {
CompilationType::Interpreted
}
LanguageName::Java => CompilationType::BytecodeCompiled,
}
}