1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
use conch_parser::ast;
use env::{AsyncIoEnvironment, ExecutableEnvironment, ExportedVariableEnvironment,
          FileDescEnvironment, FunctionEnvironment, SetArgumentsEnvironment,
          UnsetVariableEnvironment, WorkingDirectoryEnvironment};
use error::{CommandError, RedirectionError};
use eval::{RedirectEval, RedirectOrCmdWord, RedirectOrVarAssig, WordEval};
use io::FileDescWrapper;
use spawn::{ExitResult, Spawn, SimpleCommand, simple_command, SpawnedSimpleCommand};
use std::borrow::Borrow;
use std::hash::Hash;
use std::vec::IntoIter;

/// A type alias for the `EnvFuture` implementation returned when spawning
/// a `SimpleCommand` AST node.
pub type SimpleCommandEnvFuture<R, V, W, E> = SimpleCommand<
    R, V, W,
    IntoIter<RedirectOrVarAssig<R, V, W>>,
    IntoIter<RedirectOrCmdWord<R, W>>,
    E
>;

impl<V, W, R, S, E: ?Sized> Spawn<E> for ast::SimpleCommand<V, W, R>
    where R: RedirectEval<E, Handle = E::FileHandle>,
          R::Error: From<RedirectionError>,
          V: Hash + Eq + Borrow<String>,
          W: WordEval<E>,
          S: Clone + Spawn<E>,
          S::Error: From<CommandError> + From<RedirectionError> + From<R::Error> + From<W::Error>,
          E: AsyncIoEnvironment
              + ExecutableEnvironment
              + ExportedVariableEnvironment
              + FileDescEnvironment
              + FunctionEnvironment<Fn = S>
              + SetArgumentsEnvironment
              + UnsetVariableEnvironment
              + WorkingDirectoryEnvironment,
          E::Arg: From<W::EvalResult>,
          E::Args: From<Vec<E::Arg>>,
          E::FileHandle: FileDescWrapper,
          E::FnName: From<W::EvalResult>,
          E::VarName: Borrow<String> + Clone + From<V>,
          E::Var: Borrow<String> + Clone + From<W::EvalResult>,
{
    type EnvFuture = SimpleCommandEnvFuture<R, V, W, E>;
    type Future = ExitResult<SpawnedSimpleCommand<E::Future, S::Future>>;
    type Error = S::Error;

    fn spawn(self, env: &E) -> Self::EnvFuture {
        let vars: Vec<_> = self.redirects_or_env_vars.into_iter().map(Into::into).collect();
        let words: Vec<_> = self.redirects_or_cmd_words.into_iter().map(Into::into).collect();

        simple_command(vars, words, env)
    }
}

impl<'a, V, W, R, S, E: ?Sized> Spawn<E> for &'a ast::SimpleCommand<V, W, R>
    where &'a R: RedirectEval<E, Handle = E::FileHandle>,
          <&'a R as RedirectEval<E>>::Error: From<RedirectionError>,
          V: Hash + Eq + Borrow<String> + Clone,
          &'a W: WordEval<E>,
          S: Clone + Spawn<E>,
          S::Error: From<CommandError>
              + From<RedirectionError>
              + From<<&'a R as RedirectEval<E>>::Error>
              + From<<&'a W as WordEval<E>>::Error>,
          E: AsyncIoEnvironment
              + ExecutableEnvironment
              + ExportedVariableEnvironment
              + FileDescEnvironment
              + FunctionEnvironment<Fn = S>
              + SetArgumentsEnvironment
              + UnsetVariableEnvironment
              + WorkingDirectoryEnvironment,
          E::Arg: From<<&'a W as WordEval<E>>::EvalResult>,
          E::Args: From<Vec<E::Arg>>,
          E::FileHandle: FileDescWrapper,
          E::FnName: From<<&'a W as WordEval<E>>::EvalResult>,
          E::VarName: Borrow<String> + Clone + From<V>,
          E::Var: Borrow<String> + Clone + From<<&'a W as WordEval<E>>::EvalResult>,
{
    type EnvFuture = SimpleCommandEnvFuture<&'a R, V, &'a W, E>;
    type Future = ExitResult<SpawnedSimpleCommand<E::Future, S::Future>>;
    type Error = S::Error;

    fn spawn(self, env: &E) -> Self::EnvFuture {
        let vars: Vec<_> = self.redirects_or_env_vars.iter()
            .map(|v| {
                use self::ast::RedirectOrEnvVar::*;
                match *v {
                    Redirect(ref r) => RedirectOrVarAssig::Redirect(r),
                    EnvVar(ref v, ref w) => RedirectOrVarAssig::VarAssig(v.clone(), w.as_ref()),
                }
            })
            .collect();
        let words: Vec<_> = self.redirects_or_cmd_words.iter()
            .map(|w| match *w {
                ast::RedirectOrCmdWord::Redirect(ref r) => RedirectOrCmdWord::Redirect(r),
                ast::RedirectOrCmdWord::CmdWord(ref w) => RedirectOrCmdWord::CmdWord(w),
            })
            .collect();

        simple_command(vars, words, env)
    }
}