use std::collections::HashMap;
use std::sync::Arc;
use crate::runtime::Runtime;
use crate::runtimes;
#[derive(Clone, Default)]
pub struct RuntimeRegistry {
by_lang: HashMap<String, Arc<dyn Runtime>>,
}
impl RuntimeRegistry {
pub fn new() -> Self {
Self {
by_lang: HashMap::new(),
}
}
pub fn with_builtins() -> Self {
let mut r = Self::new();
#[cfg(any(test, debug_assertions))]
r.register(runtimes::echo::EchoRuntime);
#[cfg(feature = "lang-lisp")]
r.register(runtimes::lisp::LispRuntime);
#[cfg(feature = "lang-js")]
r.register(runtimes::js::JsRuntime);
#[cfg(feature = "lang-python")]
r.register(runtimes::python::PythonRuntime);
#[cfg(feature = "lang-lua")]
r.register(runtimes::lua::LuaRuntime);
#[cfg(feature = "lang-rust")]
r.register(runtimes::rust::RustRuntime::default());
#[cfg(feature = "lang-query")]
r.register(runtimes::query::QueryRuntime);
r
}
pub fn register<R: Runtime + 'static>(&mut self, r: R) -> &mut Self {
self.by_lang
.insert(r.language().to_ascii_lowercase(), Arc::new(r));
self
}
pub fn get(&self, lang: &str) -> Option<Arc<dyn Runtime>> {
let key = outl_md::lang::canonical(lang)
.map(str::to_owned)
.unwrap_or_else(|| lang.to_ascii_lowercase());
self.by_lang.get(&key).cloned()
}
pub fn languages(&self) -> impl Iterator<Item = &str> {
self.by_lang.keys().map(String::as_str)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_registers_echo() {
let r = RuntimeRegistry::with_builtins();
assert!(r.get("echo").is_some());
}
#[cfg(feature = "lang-lisp")]
#[test]
fn registers_lisp_when_feature_on() {
let r = RuntimeRegistry::with_builtins();
assert!(r.get("lisp").is_some());
}
#[test]
fn lookup_is_case_insensitive() {
let r = RuntimeRegistry::with_builtins();
assert!(r.get("ECHO").is_some());
assert!(r.get("Echo").is_some());
}
#[test]
fn unknown_language_returns_none() {
let r = RuntimeRegistry::with_builtins();
assert!(r.get("klingon").is_none());
}
}