xtalforge_modules/
registry.rs1use std::collections::BTreeMap;
4
5use serde::{Deserialize, Serialize};
6use xtalforge_core::Error;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub struct ModuleInfo {
11 pub name: String,
13 pub description: String,
15 pub version: String,
17 pub parameters: Vec<String>,
19}
20
21pub trait Module: std::fmt::Debug + Send + Sync {
23 fn info(&self) -> ModuleInfo;
25
26 fn available(&self) -> bool {
31 true
32 }
33
34 fn run(&self, _parameters: &serde_json::Value) -> Result<serde_json::Value, Error> {
41 Err(Error::InvalidInput(format!(
42 "module {} has no run implementation",
43 self.info().name
44 )))
45 }
46}
47
48#[derive(Debug, Default)]
50pub struct ModuleRegistry {
51 modules: BTreeMap<String, Box<dyn Module>>,
52}
53
54impl ModuleRegistry {
55 #[must_use]
57 pub fn new() -> Self {
58 Self::default()
59 }
60
61 pub fn register(&mut self, module: Box<dyn Module>) -> Result<(), Error> {
67 let info = module.info();
68 if info.name.trim().is_empty() {
69 return Err(Error::InvalidInput(
70 "a module needs a non-empty name".to_owned(),
71 ));
72 }
73 if self.modules.contains_key(&info.name) {
74 return Err(Error::InvalidInput(format!(
75 "module {} is already registered",
76 info.name
77 )));
78 }
79 self.modules.insert(info.name, module);
80 Ok(())
81 }
82
83 pub fn unregister(&mut self, name: &str) -> bool {
85 self.modules.remove(name).is_some()
86 }
87
88 #[must_use]
90 pub fn get(&self, name: &str) -> Option<&dyn Module> {
91 self.modules.get(name).map(Box::as_ref)
92 }
93
94 #[must_use]
96 pub fn list(&self) -> Vec<ModuleInfo> {
97 self.modules.values().map(|module| module.info()).collect()
98 }
99}