forge_runtime/workflow/
registry.rs1use std::collections::HashMap;
2use std::future::Future;
3use std::pin::Pin;
4use std::sync::Arc;
5
6use forge_core::workflow::{ForgeWorkflow, WorkflowContext, WorkflowInfo};
7
8pub type BoxedWorkflowHandler = Arc<
10 dyn Fn(
11 &WorkflowContext,
12 serde_json::Value,
13 )
14 -> Pin<Box<dyn Future<Output = forge_core::Result<serde_json::Value>> + Send + '_>>
15 + Send
16 + Sync,
17>;
18
19pub struct WorkflowEntry {
21 pub info: WorkflowInfo,
23 pub handler: BoxedWorkflowHandler,
25}
26
27impl WorkflowEntry {
28 pub fn new<W: ForgeWorkflow>() -> Self
30 where
31 W::Input: serde::de::DeserializeOwned,
32 W::Output: serde::Serialize,
33 {
34 Self {
35 info: W::info(),
36 handler: Arc::new(|ctx, input| {
37 Box::pin(async move {
38 let typed_input: W::Input = serde_json::from_value(input)
39 .map_err(|e| forge_core::ForgeError::Validation(e.to_string()))?;
40 let result = W::execute(ctx, typed_input).await?;
41 serde_json::to_value(result).map_err(forge_core::ForgeError::from)
42 })
43 }),
44 }
45 }
46}
47
48#[derive(Default)]
50pub struct WorkflowRegistry {
51 workflows: HashMap<String, WorkflowEntry>,
52}
53
54impl WorkflowRegistry {
55 pub fn new() -> Self {
57 Self {
58 workflows: HashMap::new(),
59 }
60 }
61
62 pub fn register<W: ForgeWorkflow>(&mut self)
64 where
65 W::Input: serde::de::DeserializeOwned,
66 W::Output: serde::Serialize,
67 {
68 let entry = WorkflowEntry::new::<W>();
69 self.workflows.insert(entry.info.name.to_string(), entry);
70 }
71
72 pub fn get(&self, name: &str) -> Option<&WorkflowEntry> {
74 self.workflows.get(name)
75 }
76
77 pub fn get_version(&self, name: &str, version: u32) -> Option<&WorkflowEntry> {
79 self.workflows
80 .get(name)
81 .filter(|e| e.info.version == version)
82 }
83
84 pub fn list(&self) -> Vec<&WorkflowEntry> {
86 self.workflows.values().collect()
87 }
88
89 pub fn len(&self) -> usize {
91 self.workflows.len()
92 }
93
94 pub fn is_empty(&self) -> bool {
96 self.workflows.is_empty()
97 }
98
99 pub fn names(&self) -> Vec<&str> {
101 self.workflows.keys().map(|s| s.as_str()).collect()
102 }
103}
104
105impl Clone for WorkflowRegistry {
106 fn clone(&self) -> Self {
107 Self {
108 workflows: self
109 .workflows
110 .iter()
111 .map(|(k, v)| {
112 (
113 k.clone(),
114 WorkflowEntry {
115 info: v.info.clone(),
116 handler: v.handler.clone(),
117 },
118 )
119 })
120 .collect(),
121 }
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn test_empty_registry() {
131 let registry = WorkflowRegistry::new();
132 assert!(registry.is_empty());
133 assert_eq!(registry.len(), 0);
134 }
135}