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