Skip to main content

forge_runtime/daemon/
registry.rs

1//! Registry for daemon handlers.
2
3use 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
11/// Type alias for boxed daemon handler functions.
12pub type BoxedDaemonHandler = Arc<
13    dyn Fn(&DaemonContext) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>> + Send + Sync,
14>;
15
16/// Entry in the daemon registry.
17pub struct DaemonEntry {
18    /// Daemon metadata.
19    pub info: DaemonInfo,
20    /// Daemon handler function.
21    pub handler: BoxedDaemonHandler,
22}
23
24/// Registry for storing and retrieving daemon handlers.
25#[derive(Clone, Default)]
26pub struct DaemonRegistry {
27    daemons: HashMap<String, Arc<DaemonEntry>>,
28}
29
30impl DaemonRegistry {
31    /// Create a new empty registry.
32    pub fn new() -> Self {
33        Self::default()
34    }
35
36    /// Register a daemon handler.
37    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    /// Get a daemon entry by name.
48    pub fn get(&self, name: &str) -> Option<Arc<DaemonEntry>> {
49        self.daemons.get(name).cloned()
50    }
51
52    /// Get daemon info by name.
53    pub fn info(&self, name: &str) -> Option<&DaemonInfo> {
54        self.daemons.get(name).map(|e| &e.info)
55    }
56
57    /// Check if a daemon exists.
58    pub fn exists(&self, name: &str) -> bool {
59        self.daemons.contains_key(name)
60    }
61
62    /// Get all daemon names.
63    pub fn daemon_names(&self) -> impl Iterator<Item = &str> {
64        self.daemons.keys().map(|s| s.as_str())
65    }
66
67    /// Get all daemons.
68    pub fn daemons(&self) -> impl Iterator<Item = (&str, &Arc<DaemonEntry>)> {
69        self.daemons.iter().map(|(k, v)| (k.as_str(), v))
70    }
71
72    /// Get the number of registered daemons.
73    pub fn len(&self) -> usize {
74        self.daemons.len()
75    }
76
77    /// Check if registry is empty.
78    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}