#![allow(deprecated)]
#![cfg_attr(process_control_docs_rs, feature(doc_cfg))]
#![warn(unused_results)]
use std::fmt;
use std::fmt::Display;
use std::fmt::Formatter;
use std::io;
use std::process;
use std::process::Child;
use std::time::Duration;
macro_rules! if_memory_limit {
( $($item:item)+ ) => {
$(
#[cfg(any(
target_os = "android",
all(
target_os = "linux",
any(target_env = "gnu", target_env = "musl"),
),
windows,
))]
$item
)+
};
}
mod control;
#[cfg_attr(unix, path = "unix.rs")]
#[cfg_attr(windows, path = "windows.rs")]
mod imp;
#[derive(Debug)]
pub struct Terminator(imp::DuplicatedHandle);
impl Terminator {
#[inline]
pub unsafe fn terminate(&self) -> io::Result<()> {
self.0.terminate()
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ExitStatus(imp::ExitStatus);
impl ExitStatus {
#[inline]
#[must_use]
pub fn success(self) -> bool {
self.0.success()
}
#[inline]
#[must_use]
pub fn code(self) -> Option<i64> {
self.0.code().map(Into::into)
}
#[cfg(any(unix, doc))]
#[cfg_attr(process_control_docs_rs, doc(cfg(unix)))]
#[inline]
#[must_use]
pub fn signal(self) -> Option<::std::os::raw::c_int> {
self.0.signal()
}
}
impl Display for ExitStatus {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<process::ExitStatus> for ExitStatus {
#[inline]
fn from(value: process::ExitStatus) -> Self {
#[cfg_attr(windows, allow(clippy::useless_conversion))]
Self(value.into())
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Output {
pub status: ExitStatus,
pub stdout: Vec<u8>,
pub stderr: Vec<u8>,
}
impl From<process::Output> for Output {
#[inline]
fn from(value: process::Output) -> Self {
Self {
status: value.status.into(),
stdout: value.stdout,
stderr: value.stderr,
}
}
}
impl From<Output> for ExitStatus {
#[inline]
fn from(value: Output) -> Self {
value.status
}
}
#[must_use]
pub trait Control: private::Sealed {
type Result;
if_memory_limit! {
#[cfg_attr(
process_control_docs_rs,
doc(cfg(any(
target_os = "android",
all(
target_os = "linux",
any(target_env = "gnu", target_env = "musl"),
),
windows,
)))
)]
#[must_use]
fn memory_limit(self, limit: usize) -> Self;
}
#[must_use]
fn time_limit(self, limit: Duration) -> Self;
#[must_use]
fn strict_errors(self) -> Self;
#[must_use]
fn terminate_for_timeout(self) -> Self;
fn wait(self) -> io::Result<Option<Self::Result>>;
}
#[deprecated = "use `Control` instead"]
pub trait Timeout: private::Sealed {
#[deprecated = "use `Control::Result` instead"]
type Result;
#[must_use]
#[deprecated = "use `Control::strict_errors` instead"]
fn strict_errors(self) -> Self;
#[must_use]
#[deprecated = "use `Control::terminate_for_timeout` instead"]
fn terminating(self) -> Self;
#[deprecated = "use `Control::wait` instead"]
fn wait(self) -> io::Result<Option<Self::Result>>;
}
pub trait ChildExt<'a>: private::Sealed {
type ExitStatusControl: 'a + Control<Result = ExitStatus>;
type OutputControl: Control<Result = Output>;
#[deprecated = "use `ExitStatusControl` instead"]
type ExitStatusTimeout: 'a + Timeout<Result = ExitStatus>;
#[deprecated = "use `OutputControl` instead"]
type OutputTimeout: Timeout<Result = Output>;
fn terminator(&self) -> io::Result<Terminator>;
#[must_use]
fn controlled(&'a mut self) -> Self::ExitStatusControl;
#[must_use]
fn controlled_with_output(self) -> Self::OutputControl;
#[deprecated = "use `controlled` and `Control::time_limit` instead"]
#[must_use]
fn with_timeout(
&'a mut self,
time_limit: Duration,
) -> Self::ExitStatusTimeout;
#[deprecated = "use `controlled_with_output` and `Control::time_limit` \
instead"]
#[must_use]
fn with_output_timeout(self, time_limit: Duration) -> Self::OutputTimeout;
}
impl<'a> ChildExt<'a> for Child {
type ExitStatusControl = control::ExitStatusControl<'a>;
type OutputControl = control::OutputControl;
type ExitStatusTimeout = control::ExitStatusTimeout<'a>;
type OutputTimeout = control::OutputTimeout;
#[inline]
fn terminator(&self) -> io::Result<Terminator> {
imp::DuplicatedHandle::new(self).map(Terminator)
}
#[inline]
fn controlled(&'a mut self) -> Self::ExitStatusControl {
Self::ExitStatusControl::new(self)
}
#[inline]
fn controlled_with_output(self) -> Self::OutputControl {
Self::OutputControl::new(self)
}
#[inline]
fn with_timeout(
&'a mut self,
time_limit: Duration,
) -> Self::ExitStatusTimeout {
Self::ExitStatusTimeout::new(self, time_limit)
}
#[inline]
fn with_output_timeout(self, time_limit: Duration) -> Self::OutputTimeout {
Self::OutputTimeout::new(self, time_limit)
}
}
mod private {
use std::process::Child;
use super::control;
pub trait Sealed {}
impl Sealed for Child {}
impl Sealed for control::ExitStatusControl<'_> {}
impl Sealed for control::ExitStatusTimeout<'_> {}
impl Sealed for control::OutputControl {}
impl Sealed for control::OutputTimeout {}
}