razeri_plugin_api/
language.rs1use crate::error::LanguageError;
11use std::collections::HashMap;
12use std::sync::Arc;
13
14pub trait LanguageRenderer: Send + Sync {
22 fn language(&self) -> &str;
24
25 fn render_design(&self, design: &serde_json::Value) -> Result<String, LanguageError>;
31}
32
33pub trait LanguageRendererFactory: Send + Sync {
37 fn language(&self) -> &str;
39
40 fn display_name(&self) -> &str;
42
43 fn create(
49 &self,
50 config: &HashMap<String, String>,
51 ) -> Result<Arc<dyn LanguageRenderer>, LanguageError>;
52}
53
54pub struct LanguageRegistry {
58 renderers: HashMap<String, Arc<dyn LanguageRendererFactory>>,
59}
60
61impl LanguageRegistry {
62 #[must_use]
64 pub fn new() -> Self {
65 Self { renderers: HashMap::new() }
66 }
67
68 pub fn register(&mut self, language: String, factory: Arc<dyn LanguageRendererFactory>) {
70 self.renderers.insert(language, factory);
71 }
72
73 #[must_use]
75 pub fn get(&self, language: &str) -> Option<&Arc<dyn LanguageRendererFactory>> {
76 self.renderers.get(language)
77 }
78
79 #[must_use]
81 pub fn list(&self) -> Vec<(&str, &str)> {
82 self.renderers.values().map(|f| (f.language(), f.display_name())).collect()
83 }
84}
85
86impl Default for LanguageRegistry {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 struct MockRenderer {
97 lang: String,
98 }
99
100 impl LanguageRenderer for MockRenderer {
101 fn language(&self) -> &str {
102 &self.lang
103 }
104
105 fn render_design(&self, _design: &serde_json::Value) -> Result<String, LanguageError> {
106 Ok(format!("// Generated {} code", self.lang))
107 }
108 }
109
110 struct MockRendererFactory {
111 lang: &'static str,
112 display: &'static str,
113 }
114
115 impl LanguageRendererFactory for MockRendererFactory {
116 fn language(&self) -> &str {
117 self.lang
118 }
119
120 fn display_name(&self) -> &str {
121 self.display
122 }
123
124 fn create(
125 &self,
126 _config: &HashMap<String, String>,
127 ) -> Result<Arc<dyn LanguageRenderer>, LanguageError> {
128 Ok(Arc::new(MockRenderer { lang: self.lang.to_string() }))
129 }
130 }
131
132 #[test]
133 fn language_registry_resolves_registered_language() {
134 let mut registry = LanguageRegistry::new();
135 registry.register(
136 "kotlin".to_string(),
137 Arc::new(MockRendererFactory { lang: "kotlin", display: "Kotlin" }),
138 );
139 assert!(registry.get("kotlin").is_some());
140 assert!(registry.get("java").is_none());
141 }
142
143 #[test]
144 fn language_registry_lists_languages() {
145 let mut registry = LanguageRegistry::new();
146 for (lang, display) in
147 [("go", "Go"), ("java", "Java"), ("python", "Python"), ("kotlin", "Kotlin")]
148 {
149 registry.register(lang.to_string(), Arc::new(MockRendererFactory { lang, display }));
150 }
151 let list = registry.list();
152 assert_eq!(list.len(), 4);
153 }
154
155 #[test]
156 fn renderer_produces_output() {
157 let factory = MockRendererFactory { lang: "kotlin", display: "Kotlin" };
158 let renderer = factory.create(&HashMap::new()).unwrap();
159 let design = serde_json::json!({"name": "test"});
160 let output = renderer.render_design(&design).unwrap();
161 assert!(output.contains("kotlin"));
162 }
163}