1use crate::CoreError;
16use crate::fd::{Fd, Token};
17use crate::io::buffer::{BufferState, ChunkSink, ReadState};
18use crate::io::writer::WriterState;
19
20pub(crate) struct FdSlot {
22 pub token: Option<Token>,
25 pub fd: Fd,
27}
28
29#[repr(align(64))]
51pub struct DrainState<F>
52where
53 F: FnMut(&[u8]) -> bool,
54{
55 pub(crate) stdout_slot: Option<FdSlot>,
56 pub(crate) stderr_slot: Option<FdSlot>,
57 pub(crate) stdin_slot: Option<FdSlot>,
58
59 pub(crate) buffer: BufferState,
60 pub(crate) writer: WriterState,
61
62 pub(crate) early_exit: Option<F>,
63}
64
65impl<F> DrainState<F>
66where
67 F: FnMut(&[u8]) -> bool,
68{
69 pub fn new(
79 stdin_fd: Option<Fd>,
80 stdin_buf: Option<Box<[u8]>>,
81 stdout_fd: Option<Fd>,
82 stderr_fd: Option<Fd>,
83 limit: usize,
84 early_exit: Option<F>,
85 chunk_sink: Option<ChunkSink>,
86 ) -> Result<Self, CoreError> {
87 let stdin_slot = if stdin_buf.is_some() {
88 if let Some(fd) = stdin_fd {
89 fd.set_nonblock()?;
90 Some(FdSlot { token: None, fd })
91 } else {
92 None
93 }
94 } else {
95 None
96 };
97
98 let stdout_slot = if let Some(fd) = stdout_fd {
99 fd.set_nonblock()?;
100 Some(FdSlot { token: None, fd })
101 } else {
102 None
103 };
104
105 let stderr_slot = if let Some(fd) = stderr_fd {
106 fd.set_nonblock()?;
107 Some(FdSlot { token: None, fd })
108 } else {
109 None
110 };
111
112 Ok(Self {
113 stdin_slot,
114 stdout_slot,
115 stderr_slot,
116 buffer: BufferState::new(limit, chunk_sink),
117 writer: WriterState::new(stdin_buf),
118 early_exit,
119 })
120 }
121
122 #[inline(always)]
124 pub fn is_done(&self) -> bool {
125 self.stdin_slot.is_none() && self.stdout_slot.is_none() && self.stderr_slot.is_none()
126 }
127
128 #[inline(always)]
137 pub fn write_stdin(&mut self) -> Result<bool, CoreError> {
138 let fd = if let Some(s) = &self.stdin_slot {
139 &s.fd
140 } else {
141 return Ok(true);
142 };
143
144 let done = self.writer.write_to_fd(fd)?;
145 if done {
146 self.stdin_slot.take();
147 return Ok(true);
148 }
149 Ok(false)
150 }
151
152 #[inline(always)]
162 pub fn read_fd(&mut self, is_stdout: bool) -> Result<bool, CoreError> {
163 let read_state = {
164 let slot = if is_stdout {
165 &self.stdout_slot
166 } else {
167 &self.stderr_slot
168 };
169 let fd = if let Some(s) = slot {
170 &s.fd
171 } else {
172 return Ok(true);
173 };
174 self.buffer
175 .read_from_fd(fd, is_stdout, &mut self.early_exit)?
176 };
177
178 match read_state {
179 ReadState::Open => Ok(false),
180 ReadState::Paused => Ok(false),
181 ReadState::Eof | ReadState::EarlyExit => {
182 if is_stdout {
183 self.stdout_slot.take();
184 } else {
185 self.stderr_slot.take();
186 }
187 Ok(true)
188 }
189 }
190 }
191
192 pub(crate) fn take_all_slots(&mut self) -> Vec<FdSlot> {
194 let mut slots = Vec::new();
195 if let Some(slot) = self.stdin_slot.take() {
196 slots.push(slot);
197 }
198 if let Some(slot) = self.stdout_slot.take() {
199 slots.push(slot);
200 }
201 if let Some(slot) = self.stderr_slot.take() {
202 slots.push(slot);
203 }
204 slots
205 }
206
207 pub(crate) fn register_with_reactor(
208 &mut self,
209 reactor: &mut crate::reactor::Reactor,
210 ) -> Result<(), CoreError> {
211 register_slot(reactor, &mut self.stdin_slot, false, true)?;
212 register_slot(reactor, &mut self.stdout_slot, true, false)?;
213 register_slot(reactor, &mut self.stderr_slot, true, false)?;
214 Ok(())
215 }
216
217 pub(crate) fn stdout_matches(&self, token: Token) -> bool {
218 self.stdout_slot
219 .as_ref()
220 .is_some_and(|slot| slot.token == Some(token))
221 }
222
223 pub(crate) fn stderr_matches(&self, token: Token) -> bool {
224 self.stderr_slot
225 .as_ref()
226 .is_some_and(|slot| slot.token == Some(token))
227 }
228
229 pub(crate) fn stdin_matches(&self, token: Token) -> bool {
230 self.stdin_slot
231 .as_ref()
232 .is_some_and(|slot| slot.token == Some(token))
233 }
234
235 pub(crate) fn drop_stdout(
236 &mut self,
237 reactor: &mut crate::reactor::Reactor,
238 ) -> Result<(), CoreError> {
239 if let Some(slot) = self.stdout_slot.take() {
240 del_slot(reactor, &slot)?;
241 }
242 Ok(())
243 }
244
245 pub(crate) fn drop_stderr(
246 &mut self,
247 reactor: &mut crate::reactor::Reactor,
248 ) -> Result<(), CoreError> {
249 if let Some(slot) = self.stderr_slot.take() {
250 del_slot(reactor, &slot)?;
251 }
252 Ok(())
253 }
254
255 pub(crate) fn drop_stdin(
256 &mut self,
257 reactor: &mut crate::reactor::Reactor,
258 ) -> Result<(), CoreError> {
259 if let Some(slot) = self.stdin_slot.take() {
260 del_slot(reactor, &slot)?;
261 }
262 self.writer.buf = None;
263 Ok(())
264 }
265
266 pub(crate) fn handle_stdout_ready(
267 &mut self,
268 reactor: &mut crate::reactor::Reactor,
269 ) -> Result<(), CoreError> {
270 if let Some(slot) = &self.stdout_slot {
271 let read_state = self
272 .buffer
273 .read_from_fd(&slot.fd, true, &mut self.early_exit)?;
274 match read_state {
275 ReadState::Open => {}
276 ReadState::Paused => {
277 self.pause_stdout(reactor)?;
282 }
283 ReadState::Eof | ReadState::EarlyExit => {
284 self.drop_stdout(reactor)?;
285 }
286 }
287 }
288 Ok(())
289 }
290
291 pub(crate) fn handle_stderr_ready(
292 &mut self,
293 reactor: &mut crate::reactor::Reactor,
294 ) -> Result<(), CoreError> {
295 if let Some(slot) = &self.stderr_slot {
296 let read_state = self
297 .buffer
298 .read_from_fd(&slot.fd, false, &mut self.early_exit)?;
299 match read_state {
300 ReadState::Open => {}
301 ReadState::Paused => {
302 self.pause_stderr(reactor)?;
303 }
304 ReadState::Eof | ReadState::EarlyExit => {
305 self.drop_stderr(reactor)?;
306 }
307 }
308 }
309 Ok(())
310 }
311
312 pub(crate) fn pause_stdout(
315 &mut self,
316 reactor: &mut crate::reactor::Reactor,
317 ) -> Result<(), CoreError> {
318 pause_slot(reactor, &mut self.stdout_slot)
319 }
320
321 pub(crate) fn pause_stderr(
323 &mut self,
324 reactor: &mut crate::reactor::Reactor,
325 ) -> Result<(), CoreError> {
326 pause_slot(reactor, &mut self.stderr_slot)
327 }
328
329 pub fn stdout_paused(&self) -> bool {
331 self.buffer.stdout_paused()
332 }
333
334 pub fn stderr_paused(&self) -> bool {
336 self.buffer.stderr_paused()
337 }
338
339 pub fn resume_stdout(
343 &mut self,
344 reactor: &mut crate::reactor::Reactor,
345 ) -> Result<bool, CoreError> {
346 if !self.buffer.deliver_pending_stdout()? {
347 return Ok(false);
348 }
349 register_slot(reactor, &mut self.stdout_slot, true, false)?;
350 Ok(true)
351 }
352
353 pub fn resume_stderr(
357 &mut self,
358 reactor: &mut crate::reactor::Reactor,
359 ) -> Result<bool, CoreError> {
360 if !self.buffer.deliver_pending_stderr()? {
361 return Ok(false);
362 }
363 register_slot(reactor, &mut self.stderr_slot, true, false)?;
364 Ok(true)
365 }
366
367 pub(crate) fn take_stdout_pending(&mut self) -> Option<Vec<u8>> {
369 self.buffer.take_stdout_pending()
370 }
371
372 pub(crate) fn take_stderr_pending(&mut self) -> Option<Vec<u8>> {
374 self.buffer.take_stderr_pending()
375 }
376
377 pub(crate) fn handle_stdin_writable(
378 &mut self,
379 reactor: &mut crate::reactor::Reactor,
380 ) -> Result<(), CoreError> {
381 if let Some(slot) = &self.stdin_slot {
382 let done = self.writer.write_to_fd(&slot.fd)?;
383 if done {
384 self.drop_stdin(reactor)?;
385 }
386 }
387 Ok(())
388 }
389
390 pub fn into_parts(mut self) -> (Vec<u8>, Vec<u8>) {
392 let (stdout, stderr, _, _) = std::mem::take(&mut self.buffer).into_parts();
393 (stdout, stderr)
394 }
395
396 #[inline(always)]
398 pub fn output_limit_exceeded(&self) -> bool {
399 self.buffer.output_limit_exceeded()
400 }
401
402 #[inline(always)]
404 pub fn stdout_early_exited(&self) -> bool {
405 self.buffer.stdout_early_exited()
406 }
407
408 pub(crate) fn into_parts_with_state(mut self) -> (Vec<u8>, Vec<u8>, bool, bool) {
410 std::mem::take(&mut self.buffer).into_parts()
411 }
412}
413
414fn register_slot(
417 reactor: &mut crate::reactor::Reactor,
418 slot: &mut Option<FdSlot>,
419 readable: bool,
420 writable: bool,
421) -> Result<(), CoreError> {
422 let Some(s) = slot.as_mut() else {
423 return Ok(());
424 };
425 if s.token.is_some() {
426 return Ok(());
427 }
428 s.token = Some(reactor.add(&s.fd, readable, writable)?);
429 Ok(())
430}
431
432fn del_slot(
436 reactor: &crate::reactor::Reactor,
437 slot: &FdSlot,
438) -> Result<(), CoreError> {
439 if slot.token.is_none() {
440 return Ok(());
441 }
442 match reactor.del(&slot.fd) {
443 Ok(()) => Ok(()),
444 Err(e) if e.raw_os_error() == Some(libc::ENOENT) => Ok(()),
445 Err(e) => Err(e),
446 }
447}
448
449fn pause_slot(
452 reactor: &mut crate::reactor::Reactor,
453 slot: &mut Option<FdSlot>,
454) -> Result<(), CoreError> {
455 let Some(s) = slot.as_mut() else {
456 return Ok(());
457 };
458 if s.token.is_none() {
459 return Ok(());
460 }
461 s.token = None;
462 match reactor.del(&s.fd) {
463 Ok(()) => Ok(()),
464 Err(e) if e.raw_os_error() == Some(libc::ENOENT) => Ok(()),
465 Err(e) => Err(e),
466 }
467}