conch_runtime_pshaw/spawn/
and_or.rs1use crate::env::{LastStatusEnvironment, ReportErrorEnvironment};
2use crate::error::IsFatalError;
3use crate::spawn::swallow_non_fatal_errors;
4use crate::{ExitStatus, Spawn};
5use futures_core::future::BoxFuture;
6use std::iter::Peekable;
7
8#[derive(Debug, PartialEq, Eq, Clone)]
10pub enum AndOr<T> {
11 And(T),
13 Or(T),
15}
16
17pub async fn and_or_list<T, I, E>(
19 first: T,
20 rest: I,
21 env: &mut E,
22) -> Result<BoxFuture<'static, ExitStatus>, T::Error>
23where
24 T: Spawn<E>,
25 T::Error: IsFatalError,
26 I: IntoIterator<Item = AndOr<T>>,
27 E: ?Sized + LastStatusEnvironment + ReportErrorEnvironment,
28{
29 do_and_or_list(first, rest.into_iter().peekable(), env).await
30}
31
32async fn do_and_or_list<T, I, E>(
33 mut next: T,
34 mut rest: Peekable<I>,
35 env: &mut E,
36) -> Result<BoxFuture<'static, ExitStatus>, T::Error>
37where
38 T: Spawn<E>,
39 T::Error: IsFatalError,
40 I: Iterator<Item = AndOr<T>>,
41 E: ?Sized + LastStatusEnvironment + ReportErrorEnvironment,
42{
43 loop {
44 let future = swallow_non_fatal_errors(&next, env).await?;
45
46 if rest.peek().is_none() {
49 return Ok(future);
50 }
51
52 let status = future.await;
53 env.set_last_status(status);
54
55 'find_next: loop {
56 match (rest.next(), status.success()) {
57 (None, _) => return Ok(Box::pin(async move { status })),
58
59 (Some(AndOr::And(cmd)), true) | (Some(AndOr::Or(cmd)), false) => {
60 next = cmd;
61 break 'find_next;
62 }
63
64 _ => {}
66 }
67 }
68 }
69}