chaser_oxide/
async_process.rs1use std::ffi::OsStr;
4use std::pin::Pin;
5pub use std::process::{ExitStatus, Stdio};
6use std::task::{Context, Poll};
7
8cfg_if::cfg_if! {
9 if #[cfg(feature = "async-std-runtime")] {
10 use ::async_std::process;
11 } else if #[cfg(feature = "tokio-runtime")] {
12 use ::tokio::process;
13 }
14}
15
16#[derive(Debug)]
17pub struct Command {
18 inner: process::Command,
19}
20
21impl Command {
22 pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
23 let mut inner = process::Command::new(program);
24 inner.kill_on_drop(true);
30 Self { inner }
31 }
32
33 pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
34 self.inner.arg(arg);
35 self
36 }
37
38 pub fn args<I, S>(&mut self, args: I) -> &mut Self
39 where
40 I: IntoIterator<Item = S>,
41 S: AsRef<OsStr>,
42 {
43 self.inner.args(args);
44 self
45 }
46
47 pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
48 where
49 I: IntoIterator<Item = (K, V)>,
50 K: AsRef<OsStr>,
51 V: AsRef<OsStr>,
52 {
53 self.inner.envs(vars);
54 self
55 }
56
57 pub fn stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Self {
58 self.inner.stderr(cfg);
59 self
60 }
61
62 pub fn spawn(&mut self) -> std::io::Result<Child> {
63 let inner = self.inner.spawn()?;
64 Ok(Child::new(inner))
65 }
66}
67
68#[derive(Debug)]
69pub struct Child {
70 pub stderr: Option<ChildStderr>,
71 pub inner: process::Child,
72}
73
74impl Child {
79 fn new(mut inner: process::Child) -> Self {
80 let stderr = inner.stderr.take();
81 Self {
82 inner,
83 stderr: stderr.map(|inner| ChildStderr { inner }),
84 }
85 }
86
87 pub async fn kill(&mut self) -> std::io::Result<()> {
90 cfg_if::cfg_if! {
91 if #[cfg(feature = "async-std-runtime")] {
92 self.inner.kill()?;
93 self.wait().await?;
94 Ok(())
95 } else if #[cfg(feature = "tokio-runtime")] {
96 self.inner.kill().await
98 }
99 }
100 }
101
102 pub async fn wait(&mut self) -> std::io::Result<ExitStatus> {
104 cfg_if::cfg_if! {
105 if #[cfg(feature = "async-std-runtime")] {
106 self.inner.status().await
107 } else if #[cfg(feature = "tokio-runtime")] {
108 self.inner.wait().await
109 }
110 }
111 }
112
113 pub fn try_wait(&mut self) -> std::io::Result<Option<ExitStatus>> {
115 cfg_if::cfg_if! {
116 if #[cfg(feature = "async-std-runtime")] {
117 self.inner.try_status()
118 } else if #[cfg(feature = "tokio-runtime")] {
119 self.inner.try_wait()
120 }
121 }
122 }
123
124 pub fn as_mut_inner(&mut self) -> &mut process::Child {
128 &mut self.inner
129 }
130
131 pub fn into_inner(self) -> process::Child {
133 let mut inner = self.inner;
134 inner.stderr = self.stderr.map(ChildStderr::into_inner);
135 inner
136 }
137}
138
139#[derive(Debug)]
140pub struct ChildStderr {
141 pub inner: process::ChildStderr,
142}
143
144impl ChildStderr {
145 pub fn into_inner(self) -> process::ChildStderr {
146 self.inner
147 }
148}
149
150impl futures::AsyncRead for ChildStderr {
151 fn poll_read(
152 mut self: Pin<&mut Self>,
153 cx: &mut Context<'_>,
154 buf: &mut [u8],
155 ) -> Poll<std::io::Result<usize>> {
156 cfg_if::cfg_if! {
157 if #[cfg(feature = "async-std-runtime")] {
158 Pin::new(&mut self.inner).poll_read(cx, buf)
159 } else if #[cfg(feature = "tokio-runtime")] {
160 let mut buf = tokio::io::ReadBuf::new(buf);
161 futures::ready!(tokio::io::AsyncRead::poll_read(
162 Pin::new(&mut self.inner),
163 cx,
164 &mut buf
165 ))?;
166 Poll::Ready(Ok(buf.filled().len()))
167 }
168 }
169 }
170}