conch_runtime_pshaw/spawn/
sequence.rs1use crate::env::{IsInteractiveEnvironment, LastStatusEnvironment, ReportErrorEnvironment};
2use crate::error::IsFatalError;
3use crate::spawn::swallow_non_fatal_errors;
4use crate::{ExitStatus, Spawn, EXIT_SUCCESS};
5use futures_core::future::BoxFuture;
6
7pub async fn sequence<I, E: ?Sized>(
13 iter: I,
14 env: &mut E,
15) -> Result<BoxFuture<'static, ExitStatus>, <I::Item as Spawn<E>>::Error>
16where
17 E: IsInteractiveEnvironment + LastStatusEnvironment + ReportErrorEnvironment,
18 I: IntoIterator,
19 I::Item: Spawn<E>,
20 <I::Item as Spawn<E>>::Error: IsFatalError,
21{
22 do_sequence(iter.into_iter().peekable(), env, |env, iter| {
26 env.is_interactive() || iter.peek().is_some()
27 })
28 .await
29}
30
31pub async fn sequence_exact<I, E>(
37 cmds: I,
38 env: &mut E,
39) -> Result<BoxFuture<'static, ExitStatus>, <I::Item as Spawn<E>>::Error>
40where
41 I: IntoIterator,
42 I::IntoIter: ExactSizeIterator,
43 I::Item: Spawn<E>,
44 <I::Item as Spawn<E>>::Error: IsFatalError,
45 E: ?Sized + LastStatusEnvironment + ReportErrorEnvironment,
46{
47 do_sequence(cmds.into_iter(), env, |_, iter| iter.len() != 0).await
48}
49
50pub fn sequence_slice<S>(cmds: &'_ [S]) -> SequenceSlice<'_, S> {
54 SequenceSlice { cmds }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
61pub struct SequenceSlice<'a, S> {
62 cmds: &'a [S],
63}
64
65impl<'a, S, E> Spawn<E> for SequenceSlice<'a, S>
66where
67 S: Send + Sync + Spawn<E>,
68 S::Error: IsFatalError,
69 E: ?Sized + Send + LastStatusEnvironment + ReportErrorEnvironment,
70{
71 type Error = S::Error;
72
73 fn spawn<'life0, 'life1, 'async_trait>(
74 &'life0 self,
75 env: &'life1 mut E,
76 ) -> BoxFuture<'async_trait, Result<BoxFuture<'static, ExitStatus>, Self::Error>>
77 where
78 'life0: 'async_trait,
79 'life1: 'async_trait,
80 Self: 'async_trait,
81 {
82 Box::pin(sequence_exact(self.cmds, env))
83 }
84}
85
86async fn do_sequence<I, E>(
87 mut iter: I,
88 env: &mut E,
89 has_more: impl Fn(&E, &mut I) -> bool,
90) -> Result<BoxFuture<'static, ExitStatus>, <I::Item as Spawn<E>>::Error>
91where
92 E: ?Sized + LastStatusEnvironment + ReportErrorEnvironment,
93 I: Iterator,
94 I::Item: Spawn<E>,
95 <I::Item as Spawn<E>>::Error: IsFatalError,
96{
97 let mut last_status = EXIT_SUCCESS; while let Some(cmd) = iter.next() {
99 let cmd = swallow_non_fatal_errors(&cmd, env).await?;
100
101 if has_more(env, &mut iter) {
102 last_status = cmd.await;
105 env.set_last_status(last_status);
106 } else {
107 return Ok(cmd);
110 }
111 }
112
113 Ok(Box::pin(async move { last_status }))
114}