conch_runtime_pshaw/spawn/
for_cmd.rs

1use crate::env::{ArgumentsEnvironment, LastStatusEnvironment, VariableEnvironment};
2use crate::eval::WordEval;
3use crate::spawn::{ExitStatus, Spawn};
4use crate::EXIT_SUCCESS;
5use futures_core::future::BoxFuture;
6
7/// Spawns a `for` loop with all the fields when `words` are evaluated.
8///
9/// For each element in the environment's arguments, `name` will be assigned
10/// with its value and `body` will be executed.
11pub async fn for_loop<W, I, S, E>(
12    name: E::VarName,
13    words: I,
14    body: S,
15    env: &mut E,
16) -> Result<BoxFuture<'static, ExitStatus>, S::Error>
17where
18    I: IntoIterator<Item = W>,
19    W: WordEval<E>,
20    S: Spawn<E>,
21    S::Error: From<W::Error>,
22    E: ?Sized + LastStatusEnvironment + VariableEnvironment,
23    E::VarName: Clone,
24    E::Var: From<W::EvalResult>,
25{
26    do_for_loop(name, words.into_iter(), body, env).await
27}
28
29async fn do_for_loop<W, I, S, E>(
30    name: E::VarName,
31    words: I,
32    body: S,
33    env: &mut E,
34) -> Result<BoxFuture<'static, ExitStatus>, S::Error>
35where
36    I: Iterator<Item = W>,
37    W: WordEval<E>,
38    S: Spawn<E>,
39    S::Error: From<W::Error>,
40    E: ?Sized + LastStatusEnvironment + VariableEnvironment,
41    E::VarName: Clone,
42    E::Var: From<W::EvalResult>,
43{
44    let (lo, hi) = words.size_hint();
45    let mut values = Vec::with_capacity(hi.unwrap_or(lo));
46
47    for word in words {
48        let fields = word
49            .eval(env)
50            .await
51            .map_err(S::Error::from)?
52            .await
53            .into_iter()
54            .map(E::Var::from);
55
56        values.extend(fields);
57    }
58
59    do_for_with_args(name, values.into_iter(), body, env).await
60}
61
62/// Spawns a `for` loop with the environment's currently set arguments.
63///
64/// For each element in the environment's arguments, `name` will be assigned
65/// with its value and `body` will be executed.
66pub async fn for_args<S, E>(
67    name: E::VarName,
68    body: S,
69    env: &mut E,
70) -> Result<BoxFuture<'static, ExitStatus>, S::Error>
71where
72    S: Spawn<E>,
73    E: ?Sized + ArgumentsEnvironment + LastStatusEnvironment + VariableEnvironment,
74    E::VarName: Clone,
75    E::Var: From<E::Arg>,
76{
77    let args = env
78        .args()
79        .iter()
80        .cloned()
81        .map(E::Var::from)
82        .collect::<Vec<_>>();
83
84    for_with_args(name, args, body, env).await
85}
86
87/// Spawns a `for` loop with the specified arguments.
88///
89/// For each element in `args`, `name` will be assigned with its value and
90/// `body` will be executed.
91pub async fn for_with_args<I, S, E>(
92    name: E::VarName,
93    args: I,
94    body: S,
95    env: &mut E,
96) -> Result<BoxFuture<'static, ExitStatus>, S::Error>
97where
98    I: IntoIterator<Item = E::Var>,
99    S: Spawn<E>,
100    E: ?Sized + LastStatusEnvironment + VariableEnvironment,
101    E::VarName: Clone,
102{
103    do_for_with_args(name, args.into_iter(), body, env).await
104}
105
106async fn do_for_with_args<I, S, E>(
107    name: E::VarName,
108    mut args: I,
109    body: S,
110    env: &mut E,
111) -> Result<BoxFuture<'static, ExitStatus>, S::Error>
112where
113    I: Iterator<Item = E::Var>,
114    S: Spawn<E>,
115    E: ?Sized + LastStatusEnvironment + VariableEnvironment,
116    E::VarName: Clone,
117{
118    let mut cur_arg = match args.next() {
119        Some(a) => a,
120        None => return Ok(Box::pin(async { EXIT_SUCCESS })),
121    };
122
123    for next in args {
124        env.set_var(name.clone(), cur_arg);
125        let status = body.spawn(env).await?.await;
126        env.set_last_status(status);
127        cur_arg = next;
128    }
129
130    env.set_var(name, cur_arg);
131    body.spawn(env).await
132}