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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
//! [`ProcessSpawner`] trait, [`Process`] handle trait, and the
//! supporting value types every implementation produces.
//!
//! The trait pair abstracts the executor's view of the host OS's
//! process facilities so the production backend and the scriptable
//! test-double mock can share one shape. The production backend
//! [`StdProcessSpawner`](crate::std_impl::StdProcessSpawner) wraps
//! [`tokio::process::Command`]; the mock lives alongside under
//! [`crate::mock_impl`] but is gated to test builds only and is not
//! part of the crate's stable public surface. The trait associated
//! types still carry tokio types ([`tokio::io::AsyncRead`]); the
//! executor is tokio-bound by design and does not aim to be
//! runtime-neutral.
//!
//! Stream ownership is structural rather than convention. The
//! [`Spawned`] value returned from [`ProcessSpawner::spawn`] carries
//! the child's stdout and stderr as fields; callers move them into
//! reader tasks while keeping the [`Process`] value for waiting and
//! signalling. This mirrors the take-once invariant of
//! [`tokio::process::Child::stdout`] without exposing it as a runtime
//! check.
use OsString;
use Future;
use PathBuf;
use Snafu;
use AsyncRead;
/// Numeric process identifier as reported by the host OS.
///
/// Wraps [`u32`] so the type system distinguishes a process id from
/// every other numeric identifier the codebase carries.
;
/// Termination or cancellation signal the executor delivers to a
/// child process during the cancellation flow (`EXEC-013`,
/// `EXEC-014`).
///
/// The variants are intentionally limited to the signals the executor
/// actually uses; this is not a full POSIX signal vocabulary.
/// Final state of a child process as reported by [`Process::wait`].
///
/// Aliased to [`std::process::ExitStatus`] so callers can use the
/// platform-extension traits (e.g. `ExitStatusExt::signal()` on Unix)
/// without an extra conversion layer.
pub type ExitStatus = ExitStatus;
/// Description of one process the executor wants to spawn.
///
/// Carries the program, its argument vector, the working directory
/// (always absolute), and the environment variables the child should
/// see. The [`Self::env`] vector is preserved verbatim by all
/// implementations so test assertions are deterministic.
/// Failure modes shared by every [`ProcessSpawner`] and [`Process`]
/// method.
/// Handle to one spawned child process.
///
/// Implementors expose the lifecycle operations the executor needs
/// after `spawn`: identity ([`Self::id`]), signal delivery
/// ([`Self::send_signal`]), and reaping ([`Self::wait`]).
///
/// stdout and stderr are NOT exposed through this trait. The
/// [`ProcessSpawner::spawn`] call extracts them and returns them as
/// fields on a [`Spawned`] value, which is the structural enforcement
/// of the take-once invariant on those streams.
/// Triple of values produced by [`ProcessSpawner::spawn`].
///
/// The owned-at-spawn shape: stdout and stderr are taken out of the
/// child once at spawn time and exposed as fields. Callers move them
/// into reader tasks while keeping [`Self::process`] for waiting and
/// signalling.
/// Trait for spawning child processes.
///
/// The production backend
/// [`StdProcessSpawner`](crate::std_impl::StdProcessSpawner) wraps
/// [`tokio::process::Command`]; a scriptable test-double mock lives
/// alongside under [`crate::mock_impl`] but is gated to test builds
/// only.
///
/// Consumers borrow a `ProcessSpawner` implementation generically
/// rather than depending on either concrete impl, which keeps test
/// code free of the production tokio command wiring while remaining
/// on the same tokio runtime.