forge_runtime/daemon/
registry.rs1use std::collections::HashMap;
4use std::future::Future;
5use std::pin::Pin;
6use std::sync::Arc;
7
8use forge_core::Result;
9use forge_core::daemon::{DaemonContext, DaemonInfo, ForgeDaemon};
10
11pub type BoxedDaemonHandler = Arc<
13 dyn Fn(&DaemonContext) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>> + Send + Sync,
14>;
15
16pub struct DaemonEntry {
18 pub info: DaemonInfo,
20 pub handler: BoxedDaemonHandler,
22}
23
24#[derive(Clone, Default)]
26pub struct DaemonRegistry {
27 daemons: HashMap<String, Arc<DaemonEntry>>,
28}
29
30impl DaemonRegistry {
31 pub fn new() -> Self {
33 Self::default()
34 }
35
36 pub fn register<D: ForgeDaemon>(&mut self) {
38 let info = D::info();
39 let name = info.name.to_string();
40
41 let handler: BoxedDaemonHandler = Arc::new(move |ctx| D::execute(ctx));
42
43 self.daemons
44 .insert(name, Arc::new(DaemonEntry { info, handler }));
45 }
46
47 pub fn get(&self, name: &str) -> Option<Arc<DaemonEntry>> {
49 self.daemons.get(name).cloned()
50 }
51
52 pub fn info(&self, name: &str) -> Option<&DaemonInfo> {
54 self.daemons.get(name).map(|e| &e.info)
55 }
56
57 pub fn exists(&self, name: &str) -> bool {
59 self.daemons.contains_key(name)
60 }
61
62 pub fn daemon_names(&self) -> impl Iterator<Item = &str> {
64 self.daemons.keys().map(|s| s.as_str())
65 }
66
67 pub fn daemons(&self) -> impl Iterator<Item = (&str, &Arc<DaemonEntry>)> {
69 self.daemons.iter().map(|(k, v)| (k.as_str(), v))
70 }
71
72 pub fn len(&self) -> usize {
74 self.daemons.len()
75 }
76
77 pub fn is_empty(&self) -> bool {
79 self.daemons.is_empty()
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn test_registry_new() {
89 let registry = DaemonRegistry::new();
90 assert!(registry.is_empty());
91 }
92}