Skip to main content

pocketflow_async/
lib.rs

1use pocketflow_core::*;
2use std::collections::HashMap;
3use std::sync::Arc;
4
5type AsyncNodeFunc = Arc<
6    dyn Fn(&mut (dyn std::any::Any + Send), &Params) -> Result<Option<String>> + Send + Sync,
7>;
8
9#[derive(Clone)]
10pub struct AsyncNode {
11    name: String,
12    params: Params,
13    successors: HashMap<String, AsyncNode>,
14    func: AsyncNodeFunc,
15}
16
17impl AsyncNode {
18    pub fn new<F>(name: impl Into<String>, func: F) -> Self
19    where
20        F: Fn(&mut (dyn std::any::Any + Send), &Params) -> Result<Option<String>>
21            + Send
22            + Sync
23            + 'static,
24    {
25        Self {
26            name: name.into(),
27            params: Params::new(),
28            successors: HashMap::new(),
29            func: Arc::new(func),
30        }
31    }
32
33    pub fn add_successor(&mut self, action: impl Into<String>, node: AsyncNode) -> &mut Self {
34        self.successors.insert(action.into(), node);
35        self
36    }
37
38    pub fn next(&mut self, node: AsyncNode) -> &mut Self {
39        self.add_successor("default", node)
40    }
41
42    pub fn set_params(&mut self, params: Params) {
43        self.params = params;
44    }
45
46    pub fn get_params(&self) -> &Params {
47        &self.params
48    }
49
50    pub fn get_successor(&self, action: &str) -> Option<&AsyncNode> {
51        self.successors.get(action)
52    }
53
54    pub fn has_successors(&self) -> bool {
55        !self.successors.is_empty()
56    }
57
58    pub async fn run(&self, shared: &mut (dyn std::any::Any + Send)) -> Result<()> {
59        if self.has_successors() {
60            eprintln!("Warning: AsyncNode won't run successors. Use AsyncFlow.");
61        }
62        
63        (self.func)(shared, &self.params)?;
64        Ok(())
65    }
66
67    pub async fn run_recursive(&self, shared: &mut (dyn std::any::Any + Send)) -> Result<()> {
68        let action = (self.func)(shared, &self.params)?;
69        
70        if let Some(next_node) = action
71            .as_ref()
72            .and_then(|a| self.successors.get(a))
73            .or_else(|| self.successors.get("default")) {
74            Box::pin(next_node.run_recursive(shared)).await?;
75        }
76        
77        Ok(())
78    }
79}
80
81#[derive(Clone)]
82pub struct AsyncFlow {
83    start_node: Option<AsyncNode>,
84    params: Params,
85}
86
87impl AsyncFlow {
88    pub fn new() -> Self {
89        Self {
90            start_node: None,
91            params: Params::new(),
92        }
93    }
94
95    pub fn start(mut self, node: AsyncNode) -> Self {
96        self.start_node = Some(node);
97        self
98    }
99
100    pub fn set_params(&mut self, params: Params) {
101        self.params = params;
102    }
103
104    pub async fn run(&self, shared: &mut (dyn std::any::Any + Send)) -> Result<()> {
105        if let Some(ref node) = self.start_node {
106            let mut node = node.clone();
107            node.set_params(self.params.clone());
108            node.run_recursive(shared).await?;
109        }
110        Ok(())
111    }
112
113    pub async fn run_with_params(&self, shared: &mut (dyn std::any::Any + Send), params: Params) -> Result<()> {
114        if let Some(ref node) = self.start_node {
115            let mut node = node.clone();
116            let mut merged_params = self.params.clone();
117            merged_params.merge(&params);
118            node.set_params(merged_params);
119            node.run_recursive(shared).await?;
120        }
121        Ok(())
122    }
123}
124
125impl Default for AsyncFlow {
126    fn default() -> Self {
127        Self::new()
128    }
129}
130
131#[derive(Clone)]
132pub struct AsyncBatchFlow {
133    start_node: Option<AsyncNode>,
134    params: Params,
135}
136
137impl AsyncBatchFlow {
138    pub fn new() -> Self {
139        Self {
140            start_node: None,
141            params: Params::new(),
142        }
143    }
144
145    pub fn start(mut self, node: AsyncNode) -> Self {
146        self.start_node = Some(node);
147        self
148    }
149
150    pub fn set_params(&mut self, params: Params) {
151        self.params = params;
152    }
153
154    pub async fn run_batch(&self, shared: &mut (dyn std::any::Any + Send), batch_params: Vec<Params>) -> Result<Vec<()>> {
155        let mut results = Vec::with_capacity(batch_params.len());
156        for params in batch_params {
157            let flow = AsyncFlow {
158                start_node: self.start_node.clone(),
159                params: self.params.clone(),
160            };
161            flow.run_with_params(shared, params).await?;
162            results.push(());
163        }
164        Ok(results)
165    }
166}
167
168impl Default for AsyncBatchFlow {
169    fn default() -> Self {
170        Self::new()
171    }
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177    use std::sync::{Arc, Mutex};
178
179    #[derive(Default, Clone)]
180    struct TestShared {
181        pub counter: Arc<Mutex<i32>>,
182    }
183
184    #[tokio::test]
185    async fn test_async_flow_execution() {
186        let mut shared = TestShared::default();
187        
188        let node = AsyncNode::new("test", |shared, _params| {
189            if let Some(shared) = shared.downcast_mut::<TestShared>() {
190                let mut counter = shared.counter.lock().unwrap();
191                *counter += 1;
192            }
193            Ok(None)
194        });
195        
196        let flow = AsyncFlow::new().start(node);
197        
198        flow.run(&mut shared).await.unwrap();
199        
200        let counter = shared.counter.lock().unwrap();
201        assert_eq!(*counter, 1);
202    }
203
204    #[tokio::test]
205    async fn test_async_chained_flow() {
206        let mut shared = TestShared::default();
207        
208        let mut node1 = AsyncNode::new("node1", |shared, _params| {
209            if let Some(shared) = shared.downcast_mut::<TestShared>() {
210                let mut counter = shared.counter.lock().unwrap();
211                *counter += 1;
212            }
213            Ok(None)
214        });
215        
216        let node2 = AsyncNode::new("node2", |shared, _params| {
217            if let Some(shared) = shared.downcast_mut::<TestShared>() {
218                let mut counter = shared.counter.lock().unwrap();
219                *counter += 10;
220            }
221            Ok(None)
222        });
223        
224        node1.next(node2);
225        let flow = AsyncFlow::new().start(node1);
226        
227        flow.run(&mut shared).await.unwrap();
228        
229        let counter = shared.counter.lock().unwrap();
230        assert_eq!(*counter, 11);
231    }
232}