use log::{debug, trace};
use thiserror::Error;
use crate::{command::Command, io::ProcessIo, status::SpawnStatus};
#[derive(Debug, Error)]
pub enum SpawnThenWaitError {
#[error("Invalid argument: expected {0}, got {1:?}")]
InvalidArgument(&'static str, ProcessIo),
#[error("Command not initialized")]
NotInitialized,
}
#[derive(Debug)]
pub enum SpawnThenWaitResult {
Ok(SpawnStatus),
Io(ProcessIo),
Err(SpawnThenWaitError),
}
#[derive(Debug)]
pub struct SpawnThenWait {
cmd: Option<Command>,
}
impl SpawnThenWait {
pub fn new(command: Command) -> Self {
trace!("prepare command to be spawned: {command:?}");
let cmd = Some(command);
Self { cmd }
}
pub fn resume(&mut self, arg: Option<ProcessIo>) -> SpawnThenWaitResult {
let Some(arg) = arg else {
let Some(cmd) = self.cmd.take() else {
return SpawnThenWaitResult::Err(SpawnThenWaitError::NotInitialized);
};
trace!("break: need I/O to spawn command");
return SpawnThenWaitResult::Io(ProcessIo::SpawnThenWait(Err(cmd)));
};
trace!("resume after spawning command");
let ProcessIo::SpawnThenWait(io) = arg else {
let err = SpawnThenWaitError::InvalidArgument("spawn output", arg);
return SpawnThenWaitResult::Err(err);
};
let output = match io {
Ok(output) => output,
Err(cmd) => return SpawnThenWaitResult::Io(ProcessIo::SpawnThenWait(Err(cmd))),
};
debug!("spawned command: {:?}", output.status);
SpawnThenWaitResult::Ok(output)
}
}