Skip to main content

pistonite_cu/process/pio/
write.rs

1use std::process::Stdio;
2
3use tokio::io::AsyncWriteExt;
4use tokio::process::{Child as TokioChild, ChildStdin, Command as TokioCommand};
5
6use crate::{BoxedFuture, Context as _};
7
8use super::{ChildInConfig, ChildInTask};
9
10/// Write an in-memory buffer to child's stdin.
11///
12/// Budgeting and scheduling of the write task is up to Tokio.
13///
14/// # Example
15/// ```rust
16/// # use pistonite_cu as cu;
17/// use cu::pre::*;
18///
19/// # #[cfg(unix)]
20/// # fn main() -> cu::Result<()> {
21/// let (hello, out) = cu::which("grep")?.command()
22///     .args(["foo", "-"])
23///     .stdin(cu::pio::write("foobar\nhello"))
24///     .stdout(cu::pio::buffer())
25///     .stderr_null()
26///     .spawn()?;
27///
28/// assert_eq!(b"foobar\n".to_vec(), out.join()??);
29/// # Ok(()) }
30/// # #[cfg(not(unix))] fn main() {}
31/// ```
32#[inline(always)]
33pub fn write<B: AsRef<[u8]> + Send + 'static>(buf: B) -> Write<B> {
34    Write(buf)
35}
36pub struct Write<B>(B);
37impl<B: AsRef<[u8]> + Send + 'static> ChildInConfig for Write<B> {
38    type Task = WriteTask<B>;
39
40    fn configure_stdin(&mut self, command: &mut TokioCommand) -> crate::Result<()> {
41        command.stdin(Stdio::piped());
42        Ok(())
43    }
44
45    fn take(self, child: &mut TokioChild) -> crate::Result<Self::Task> {
46        let stdin = crate::check!(child.stdin.take(), "unexpected: pipe was already taken")?;
47        Ok(WriteTask { buf: self.0, stdin })
48    }
49}
50pub struct WriteTask<B> {
51    buf: B,
52    stdin: ChildStdin,
53}
54impl<B: AsRef<[u8]> + Send + 'static> ChildInTask for WriteTask<B> {
55    fn run(mut self) -> Option<BoxedFuture<crate::Result<()>>> {
56        Some(Box::pin(async move {
57            Ok(self.stdin.write_all(self.buf.as_ref()).await?)
58        }))
59    }
60}