use std::{
fmt,
io::{Read, Result},
process::{Child, ExitStatus, Output},
};
#[cfg(unix)]
use unix::ChildImp;
#[cfg(windows)]
use windows::ChildImp;
#[cfg(unix)]
use crate::UnixChildExt;
#[cfg(unix)]
use nix::sys::signal::Signal;
#[cfg(windows)]
use winapi::um::winnt::HANDLE;
#[cfg(unix)]
mod unix;
#[cfg(windows)]
mod windows;
pub struct GroupChild {
imp: ChildImp,
exitstatus: Option<ExitStatus>,
}
impl fmt::Debug for GroupChild {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("GroupChild").finish()
}
}
impl GroupChild {
#[cfg(unix)]
pub(crate) fn new(inner: Child) -> Self {
Self {
imp: ChildImp::new(inner),
exitstatus: None,
}
}
#[cfg(windows)]
pub(crate) fn new(inner: Child, j: HANDLE, c: HANDLE) -> Self {
Self {
imp: ChildImp::new(inner, j, c),
exitstatus: None,
}
}
pub fn inner(&mut self) -> &mut Child {
self.imp.inner()
}
#[cfg_attr(
windows,
doc = "On Windows, this unnavoidably leaves a handle unclosed. Prefer [`inner()`](Self::inner)."
)]
pub fn into_inner(self) -> Child {
self.imp.into_inner()
}
pub fn kill(&mut self) -> Result<()> {
self.imp.kill()
}
pub fn id(&self) -> u32 {
self.imp.id()
}
pub fn wait(&mut self) -> Result<ExitStatus> {
if let Some(es) = self.exitstatus {
return Ok(es);
}
drop(self.imp.take_stdin());
let status = self.imp.wait()?;
self.exitstatus = Some(status);
Ok(status)
}
pub fn try_wait(&mut self) -> Result<Option<ExitStatus>> {
if self.exitstatus.is_some() {
return Ok(self.exitstatus);
}
match self.imp.try_wait()? {
Some(es) => {
self.exitstatus = Some(es);
Ok(Some(es))
}
None => Ok(None),
}
}
pub fn wait_with_output(mut self) -> Result<Output> {
drop(self.imp.take_stdin());
let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
match (self.imp.take_stdout(), self.imp.take_stderr()) {
(None, None) => {}
(Some(mut out), None) => {
out.read_to_end(&mut stdout)?;
}
(None, Some(mut err)) => {
err.read_to_end(&mut stderr)?;
}
(Some(out), Some(err)) => {
let res = ChildImp::read_both(out, &mut stdout, err, &mut stderr);
res.unwrap();
}
}
let status = self.imp.wait()?;
Ok(Output {
status,
stdout,
stderr,
})
}
}
#[cfg(unix)]
impl UnixChildExt for GroupChild {
fn signal(&self, sig: Signal) -> Result<()> {
self.imp.signal_imp(sig)
}
}