use super::name::{ProcessName, generate_name};
use super::stream_config::{ProcessStreamBuilder, ProcessStreamConfig};
use crate::error::SpawnError;
use crate::output_stream::OutputStream;
use crate::process_handle::ProcessHandle;
use std::marker::PhantomData;
#[doc(hidden)]
pub struct Unnamed;
#[doc(hidden)]
pub struct Named {
name: ProcessName,
}
#[doc(hidden)]
pub struct Unset;
pub struct Process<
NameState = Unnamed,
StdoutConfig = Unset,
Stdout = Unset,
StderrConfig = Unset,
Stderr = Unset,
> {
cmd: tokio::process::Command,
name_state: NameState,
stdout_config: StdoutConfig,
stderr_config: StderrConfig,
_streams: PhantomData<fn() -> (Stdout, Stderr)>,
}
impl Process {
#[must_use]
pub fn new(cmd: tokio::process::Command) -> Self {
Self {
cmd,
name_state: Unnamed,
stdout_config: Unset,
stderr_config: Unset,
_streams: PhantomData,
}
}
#[must_use]
pub fn name(self, name: impl Into<ProcessName>) -> Process<Named> {
Process {
cmd: self.cmd,
name_state: Named { name: name.into() },
stdout_config: Unset,
stderr_config: Unset,
_streams: PhantomData,
}
}
}
impl Process<Named> {
#[must_use]
pub fn stdout_and_stderr<Config, Stream>(
self,
configure: impl FnOnce(ProcessStreamBuilder) -> Config,
) -> Process<Named, Config, Stream, Config, Stream>
where
Config: ProcessStreamConfig<Stream> + Copy,
Stream: OutputStream,
{
let config = configure(ProcessStreamBuilder);
Process {
cmd: self.cmd,
name_state: self.name_state,
stdout_config: config,
stderr_config: config,
_streams: PhantomData,
}
}
#[must_use]
pub fn stdout<StdoutConfig, Stdout>(
self,
configure: impl FnOnce(ProcessStreamBuilder) -> StdoutConfig,
) -> Process<Named, StdoutConfig, Stdout>
where
StdoutConfig: ProcessStreamConfig<Stdout>,
Stdout: OutputStream,
{
Process {
cmd: self.cmd,
name_state: self.name_state,
stdout_config: configure(ProcessStreamBuilder),
stderr_config: Unset,
_streams: PhantomData,
}
}
#[must_use]
pub fn stderr<StderrConfig, Stderr>(
self,
configure: impl FnOnce(ProcessStreamBuilder) -> StderrConfig,
) -> Process<Named, Unset, Unset, StderrConfig, Stderr>
where
StderrConfig: ProcessStreamConfig<Stderr>,
Stderr: OutputStream,
{
Process {
cmd: self.cmd,
name_state: self.name_state,
stdout_config: Unset,
stderr_config: configure(ProcessStreamBuilder),
_streams: PhantomData,
}
}
}
impl<StdoutConfig, Stdout> Process<Named, StdoutConfig, Stdout>
where
Stdout: OutputStream,
{
#[must_use]
pub fn stderr<StderrConfig, Stderr>(
self,
configure: impl FnOnce(ProcessStreamBuilder) -> StderrConfig,
) -> Process<Named, StdoutConfig, Stdout, StderrConfig, Stderr>
where
StdoutConfig: ProcessStreamConfig<Stdout>,
StderrConfig: ProcessStreamConfig<Stderr>,
Stderr: OutputStream,
{
Process {
cmd: self.cmd,
name_state: self.name_state,
stdout_config: self.stdout_config,
stderr_config: configure(ProcessStreamBuilder),
_streams: PhantomData,
}
}
}
impl<StderrConfig, Stderr> Process<Named, Unset, Unset, StderrConfig, Stderr>
where
Stderr: OutputStream,
{
#[must_use]
pub fn stdout<StdoutConfig, Stdout>(
self,
configure: impl FnOnce(ProcessStreamBuilder) -> StdoutConfig,
) -> Process<Named, StdoutConfig, Stdout, StderrConfig, Stderr>
where
StderrConfig: ProcessStreamConfig<Stderr>,
StdoutConfig: ProcessStreamConfig<Stdout>,
Stdout: OutputStream,
{
Process {
cmd: self.cmd,
name_state: self.name_state,
stdout_config: configure(ProcessStreamBuilder),
stderr_config: self.stderr_config,
_streams: PhantomData,
}
}
}
impl<StdoutConfig, Stdout, StderrConfig, Stderr>
Process<Named, StdoutConfig, Stdout, StderrConfig, Stderr>
where
Stdout: OutputStream,
Stderr: OutputStream,
{
pub fn spawn(self) -> Result<ProcessHandle<Stdout, Stderr>, SpawnError>
where
StdoutConfig: ProcessStreamConfig<Stdout>,
StderrConfig: ProcessStreamConfig<Stderr>,
{
let name = generate_name(&self.name_state.name, &self.cmd);
ProcessHandle::<Stdout, Stderr>::spawn_with_stream_configs(
name,
self.cmd,
self.stdout_config,
self.stderr_config,
)
}
}