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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use env::{ArgumentsEnvironment, AsyncIoEnvironment, ExecutableEnvironment,
          ExportedVariableEnvironment, FileDescEnvironment, FunctionEnvironment,
          IsInteractiveEnvironment, LastStatusEnvironment, ReportErrorEnvironment,
          SetArgumentsEnvironment, StringWrapper, SubEnvironment, UnsetVariableEnvironment,
          WorkingDirectoryEnvironment};
use error::RuntimeError;
use eval::{Fields, WordEval, WordEvalConfig};
use future::EnvFuture;
use io::FileDescWrapper;
use spawn::{BoxSpawnEnvFuture, BoxStatusFuture, Spawn, SpawnBoxed};
use std::fmt::Display;
use std::rc::Rc;
use std::sync::Arc;
use conch_parser::ast::{AtomicTopLevelCommand, AtomicTopLevelWord, TopLevelCommand, TopLevelWord};

macro_rules! impl_top_level_cmd {
    ($type: ident, $Rc:ident, $($extra_bounds:tt)*) => {
        impl<T, E: ?Sized> Spawn<E> for $type<T>
            where T: 'static + StringWrapper + Display $($extra_bounds)*,
                  E: 'static + AsyncIoEnvironment
                    + ArgumentsEnvironment<Arg = T>
                    + ExecutableEnvironment
                    + ExportedVariableEnvironment<VarName = T, Var = T>
                    + FileDescEnvironment
                    + FunctionEnvironment
                    + IsInteractiveEnvironment
                    + LastStatusEnvironment
                    + ReportErrorEnvironment
                    + SetArgumentsEnvironment
                    + SubEnvironment
                    + UnsetVariableEnvironment
                    + WorkingDirectoryEnvironment,
                  E::Args: From<Vec<E::Arg>>,
                  E::FileHandle: FileDescWrapper,
                  E::FnName: From<T>,
                  E::Fn: Clone
                    + From<$Rc<'static + SpawnBoxed<E, Error = RuntimeError> $($extra_bounds)*>>
                    + Spawn<E, Error = RuntimeError>,
        {
            type EnvFuture = BoxSpawnEnvFuture<'static, E, Self::Error>;
            type Future = BoxStatusFuture<'static, Self::Error>;
            type Error = RuntimeError;

            fn spawn(self, env: &E) -> Self::EnvFuture {
                Box::new(self.0.spawn(env).boxed_result())
            }
        }

        impl<'a, T: 'a, E: ?Sized> Spawn<E> for &'a $type<T>
            where T: 'static + StringWrapper + Display $($extra_bounds)*,
                  E: 'static + AsyncIoEnvironment
                    + ArgumentsEnvironment<Arg = T>
                    + ExecutableEnvironment
                    + ExportedVariableEnvironment<VarName = T, Var = T>
                    + FileDescEnvironment
                    + FunctionEnvironment
                    + IsInteractiveEnvironment
                    + LastStatusEnvironment
                    + ReportErrorEnvironment
                    + SetArgumentsEnvironment
                    + SubEnvironment
                    + UnsetVariableEnvironment
                    + WorkingDirectoryEnvironment,
                  E::Args: From<Vec<E::Arg>>,
                  E::FileHandle: FileDescWrapper,
                  E::FnName: From<T>,
                  E::Fn: Clone
                    + From<$Rc<'static + SpawnBoxed<E, Error = RuntimeError> $($extra_bounds)*>>
                    + Spawn<E, Error = RuntimeError>,
        {
            type EnvFuture = BoxSpawnEnvFuture<'a, E, Self::Error>;
            type Future = BoxStatusFuture<'a, Self::Error>;
            type Error = RuntimeError;

            fn spawn(self, env: &E) -> Self::EnvFuture {
                Box::new(Spawn::spawn(&self.0, env).boxed_result())
            }
        }
    };
}

macro_rules! impl_top_level_word {
    ($type:ident, $Rc:ident, $($extra_bounds:tt)*) => {
        impl<T, E: ?Sized> WordEval<E> for $type<T>
            where T: 'static + StringWrapper + Display $($extra_bounds)*,
                  E: 'static + AsyncIoEnvironment
                    + ArgumentsEnvironment<Arg = T>
                    + ExecutableEnvironment
                    + ExportedVariableEnvironment<VarName = T, Var = T>
                    + FileDescEnvironment
                    + FunctionEnvironment
                    + IsInteractiveEnvironment
                    + LastStatusEnvironment
                    + ReportErrorEnvironment
                    + SetArgumentsEnvironment
                    + SubEnvironment
                    + UnsetVariableEnvironment
                    + WorkingDirectoryEnvironment,
                  E::Args: From<Vec<E::Arg>>,
                  E::FileHandle: FileDescWrapper,
                  E::FnName: From<T>,
                  E::Fn: Clone
                    + From<$Rc<'static + SpawnBoxed<E, Error = RuntimeError> $($extra_bounds)*>>
                    + Spawn<E, Error = RuntimeError>,
        {
            type EvalResult = T;
            type EvalFuture = Box<'static + EnvFuture<E, Item = Fields<T>, Error = Self::Error>>;
            type Error = RuntimeError;

            fn eval_with_config(self, env: &E, cfg: WordEvalConfig) -> Self::EvalFuture {
                Box::new(self.0.eval_with_config(env, cfg))
            }
        }

        impl<'a, T, E: ?Sized> WordEval<E> for &'a $type<T>
            where T: 'static + StringWrapper + Display $($extra_bounds)*,
                  E: 'static + AsyncIoEnvironment
                    + ArgumentsEnvironment<Arg = T>
                    + ExecutableEnvironment
                    + ExportedVariableEnvironment<VarName = T, Var = T>
                    + FileDescEnvironment
                    + FunctionEnvironment
                    + IsInteractiveEnvironment
                    + LastStatusEnvironment
                    + ReportErrorEnvironment
                    + SetArgumentsEnvironment
                    + SubEnvironment
                    + UnsetVariableEnvironment
                    + WorkingDirectoryEnvironment,
                  E::Args: From<Vec<E::Arg>>,
                  E::FileHandle: FileDescWrapper,
                  E::FnName: From<T>,
                  E::Fn: Clone
                    + From<$Rc<'static + SpawnBoxed<E, Error = RuntimeError> $($extra_bounds)*>>
                    + Spawn<E, Error = RuntimeError>,
        {
            type EvalResult = T;
            type EvalFuture = Box<'a + EnvFuture<E, Item = Fields<T>, Error = Self::Error>>;
            type Error = RuntimeError;

            fn eval_with_config(self, env: &E, cfg: WordEvalConfig) -> Self::EvalFuture {
                Box::new(WordEval::eval_with_config(&self.0, env, cfg))
            }
        }
    };
}

impl_top_level_cmd!(TopLevelCommand, Rc,);
impl_top_level_cmd!(AtomicTopLevelCommand, Arc, + Send + Sync);
impl_top_level_word!(TopLevelWord, Rc,);
impl_top_level_word!(AtomicTopLevelWord, Arc, + Send + Sync);