use crate::error::LanguageError;
use std::collections::HashMap;
use std::sync::Arc;
pub trait LanguageRenderer: Send + Sync {
fn language(&self) -> &str;
fn render_design(&self, design: &serde_json::Value) -> Result<String, LanguageError>;
}
pub trait LanguageRendererFactory: Send + Sync {
fn language(&self) -> &str;
fn display_name(&self) -> &str;
fn create(
&self,
config: &HashMap<String, String>,
) -> Result<Arc<dyn LanguageRenderer>, LanguageError>;
}
pub struct LanguageRegistry {
renderers: HashMap<String, Arc<dyn LanguageRendererFactory>>,
}
impl LanguageRegistry {
#[must_use]
pub fn new() -> Self {
Self { renderers: HashMap::new() }
}
pub fn register(&mut self, language: String, factory: Arc<dyn LanguageRendererFactory>) {
self.renderers.insert(language, factory);
}
#[must_use]
pub fn get(&self, language: &str) -> Option<&Arc<dyn LanguageRendererFactory>> {
self.renderers.get(language)
}
#[must_use]
pub fn list(&self) -> Vec<(&str, &str)> {
self.renderers.values().map(|f| (f.language(), f.display_name())).collect()
}
}
impl Default for LanguageRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct MockRenderer {
lang: String,
}
impl LanguageRenderer for MockRenderer {
fn language(&self) -> &str {
&self.lang
}
fn render_design(&self, _design: &serde_json::Value) -> Result<String, LanguageError> {
Ok(format!("// Generated {} code", self.lang))
}
}
struct MockRendererFactory {
lang: &'static str,
display: &'static str,
}
impl LanguageRendererFactory for MockRendererFactory {
fn language(&self) -> &str {
self.lang
}
fn display_name(&self) -> &str {
self.display
}
fn create(
&self,
_config: &HashMap<String, String>,
) -> Result<Arc<dyn LanguageRenderer>, LanguageError> {
Ok(Arc::new(MockRenderer { lang: self.lang.to_string() }))
}
}
#[test]
fn language_registry_resolves_registered_language() {
let mut registry = LanguageRegistry::new();
registry.register(
"kotlin".to_string(),
Arc::new(MockRendererFactory { lang: "kotlin", display: "Kotlin" }),
);
assert!(registry.get("kotlin").is_some());
assert!(registry.get("java").is_none());
}
#[test]
fn language_registry_lists_languages() {
let mut registry = LanguageRegistry::new();
for (lang, display) in
[("go", "Go"), ("java", "Java"), ("python", "Python"), ("kotlin", "Kotlin")]
{
registry.register(lang.to_string(), Arc::new(MockRendererFactory { lang, display }));
}
let list = registry.list();
assert_eq!(list.len(), 4);
}
#[test]
fn renderer_produces_output() {
let factory = MockRendererFactory { lang: "kotlin", display: "Kotlin" };
let renderer = factory.create(&HashMap::new()).unwrap();
let design = serde_json::json!({"name": "test"});
let output = renderer.render_design(&design).unwrap();
assert!(output.contains("kotlin"));
}
}