gr/
exec.rs

1use crate::Cmd;
2use crate::Result;
3use std::sync::mpsc::channel;
4use std::sync::mpsc::Receiver;
5
6/// Executes a sequence of commands in parallel
7pub fn parallel_stream<T>(cmds: impl IntoIterator<Item = Cmd<T>>) -> Receiver<Result<T>>
8where
9    T: Send + 'static,
10{
11    let (sender, receiver) = channel();
12    let mut cmd_handles = Vec::new();
13    for cmd in cmds.into_iter() {
14        let sender = sender.clone();
15        let handle = std::thread::spawn(move || {
16            let cmd_info = cmd();
17            sender.send(cmd_info).unwrap_or_default();
18        });
19        cmd_handles.push(handle);
20    }
21    drop(sender);
22    receiver
23}
24
25#[cfg(test)]
26mod test {
27    use super::*;
28
29    #[test]
30    fn test_exec_one_single_cmd_ok() {
31        let first_op_cmd = || -> Result<String> { Ok("1st op".to_string()) };
32        let cmds: Vec<Cmd<String>> = vec![Box::new(first_op_cmd)];
33        let repo_data_stream = parallel_stream(cmds);
34        let results = repo_data_stream.iter().collect::<Vec<_>>();
35        assert_eq!(1, results.len());
36        assert_eq!("1st op", results[0].as_ref().unwrap());
37    }
38
39    #[test]
40    fn test_exec_several_cmds_ok() {
41        let first_op_cmd = || -> Result<String> { Ok("1st op".to_string()) };
42        let second_op_cmd = || -> Result<String> { Ok("2nd op".to_string()) };
43        let cmds: Vec<Cmd<String>> = vec![Box::new(first_op_cmd), Box::new(second_op_cmd)];
44        let repo_data_stream = parallel_stream(cmds);
45        let results = repo_data_stream.iter().collect::<Vec<_>>();
46        assert_eq!(2, results.len());
47    }
48}