Skip to content

Commit

Permalink
Add ErasedChild
Browse files Browse the repository at this point in the history
  • Loading branch information
passcod committed Nov 4, 2023
1 parent 49000b8 commit bfe6d20
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Clarify why and in which situations `AsyncGroupChild::wait` may not behave as expected when cancelled.
- Add `AsyncGroupChild::start_kill` to align with Tokio's `Child::start_kill`.
- Change `AsyncGroupChild::kill` to also `wait()` on the child, to align with Tokio's `Child::kill`.
- Add `ErasedChild` abstraction to allow using the same type for grouped and ungrouped children.

## v3.0.0 (2023-10-30)

Expand Down
4 changes: 4 additions & 0 deletions src/stdlib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ use std::{

use crate::{builder::CommandGroupBuilder, GroupChild};

#[doc(inline)]
pub use erased::ErasedChild;

#[cfg(target_family = "windows")]
mod windows;

#[cfg(target_family = "unix")]
mod unix;

pub(crate) mod child;
pub(crate) mod erased;

/// Extensions for [`Command`](std::process::Command) adding support for process groups.
pub trait CommandGroup {
Expand Down
79 changes: 79 additions & 0 deletions src/stdlib/erased.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use std::{
io::Result,
process::{Child, ExitStatus, Output},
};

use super::GroupChild;

/// Wrapper around a process child, be it grouped or ungrouped.
///
/// This is a helper which erases that a [`std::process::Child`] is a different type than a
/// [`GroupChild`]. It forwards to the corresponding method on the inner type.
#[derive(Debug)]
pub enum ErasedChild {
/// A grouped process child.
Grouped(GroupChild),

/// An ungrouped process child.
Ungrouped(Child),
}

impl ErasedChild {
/// Forces the child to exit.
///
/// - Grouped: [`GroupChild::kill`]
/// - Ungrouped: [`Child::kill`]
pub fn kill(&mut self) -> Result<()> {
match self {
Self::Grouped(c) => c.kill(),
Self::Ungrouped(c) => c.kill(),
}
}

/// Attempts to collect the exit status of the child if it has already exited.
///
/// - Grouped: [`GroupChild::try_wait`]
/// - Ungrouped: [`Child::try_wait`]
pub fn try_wait(&mut self) -> Result<Option<ExitStatus>> {
match self {
Self::Grouped(c) => c.try_wait(),
Self::Ungrouped(c) => c.try_wait(),
}
}

/// Waits for the process to exit, and returns its exit status.
///
/// - Grouped: [`GroupChild::wait`]
/// - Ungrouped: [`Child::wait`]
pub fn wait(&mut self) -> Result<ExitStatus> {
match self {
Self::Grouped(c) => c.wait(),
Self::Ungrouped(c) => c.wait(),
}
}

/// Waits for the process to exit, and returns its exit status.
///
/// - Grouped: [`GroupChild::wait_with_output`]
/// - Ungrouped: [`Child::wait_with_output`]
pub fn wait_with_output(self) -> Result<Output> {
match self {
Self::Grouped(c) => c.wait_with_output(),
Self::Ungrouped(c) => c.wait_with_output(),
}
}

/// Sends a Unix signal to the process.
///
/// - Grouped: [`GroupChild::signal`]
/// - Ungrouped: [`Child::signal`]
#[cfg(unix)]
pub fn signal(&mut self, sig: crate::Signal) -> Result<()> {
use crate::UnixChildExt;

match self {
Self::Grouped(c) => c.signal(sig),
Self::Ungrouped(c) => c.signal(sig),
}
}
}
4 changes: 4 additions & 0 deletions src/tokio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ use tokio::process::Command;

use crate::{builder::CommandGroupBuilder, AsyncGroupChild};

#[doc(inline)]
pub use erased::ErasedChild;

#[cfg(target_family = "windows")]
mod windows;

#[cfg(target_family = "unix")]
mod unix;

pub(crate) mod child;
pub(crate) mod erased;

/// Extensions for [`Command`](::tokio::process::Command) adding support for process groups.
///
Expand Down
91 changes: 91 additions & 0 deletions src/tokio/erased.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use std::{
io::Result,
process::{ExitStatus, Output},
};

use super::AsyncGroupChild;
use tokio::process::Child;

/// Wrapper around a process child, be it grouped or ungrouped.
///
/// This is a helper which erases that a [`tokio::process::Child`] is a different type than an
/// [`AsyncGroupChild`]. It forwards to the corresponding method on the inner type.
#[derive(Debug)]
pub enum ErasedChild {
/// A grouped process child.
Grouped(AsyncGroupChild),

/// An ungrouped process child.
Ungrouped(Child),
}

impl ErasedChild {
/// Forces the child to exit.
///
/// - Grouped: [`AsyncGroupChild::kill`]
/// - Ungrouped: [`Child::kill`]
pub async fn kill(&mut self) -> Result<()> {
match self {
Self::Grouped(c) => c.kill().await,
Self::Ungrouped(c) => c.kill().await,
}
}

/// Attempts to force the child to exit, but does not wait for the request to take effect.
///
/// - Grouped: [`AsyncGroupChild::start_kill`]
/// - Ungrouped: [`Child::start_kill`]
pub fn start_kill(&mut self) -> Result<()> {
match self {
Self::Grouped(c) => c.start_kill(),
Self::Ungrouped(c) => c.start_kill(),
}
}

/// Attempts to collect the exit status of the child if it has already exited.
///
/// - Grouped: [`AsyncGroupChild::try_wait`]
/// - Ungrouped: [`Child::try_wait`]
pub fn try_wait(&mut self) -> Result<Option<ExitStatus>> {
match self {
Self::Grouped(c) => c.try_wait(),
Self::Ungrouped(c) => c.try_wait(),
}
}

/// Waits for the process to exit, and returns its exit status.
///
/// - Grouped: [`AsyncGroupChild::wait`]
/// - Ungrouped: [`Child::wait`]
pub async fn wait(&mut self) -> Result<ExitStatus> {
match self {
Self::Grouped(c) => c.wait().await,
Self::Ungrouped(c) => c.wait().await,
}
}

/// Waits for the process to exit, and returns its exit status.
///
/// - Grouped: [`AsyncGroupChild::wait_with_output`]
/// - Ungrouped: [`Child::wait_with_output`]
pub async fn wait_with_output(self) -> Result<Output> {
match self {
Self::Grouped(c) => c.wait_with_output().await,
Self::Ungrouped(c) => c.wait_with_output().await,
}
}

/// Sends a Unix signal to the process.
///
/// - Grouped: [`AsyncGroupChild::signal`]
/// - Ungrouped: [`Child::signal`]
#[cfg(unix)]
pub fn signal(&mut self, sig: crate::Signal) -> Result<()> {
use crate::UnixChildExt;

match self {
Self::Grouped(c) => c.signal(sig),
Self::Ungrouped(c) => c.signal(sig),
}
}
}

0 comments on commit bfe6d20

Please sign in to comment.