nftables_async/
process.rs1use std::future::Future;
2#[cfg(any(feature = "tokio-process", feature = "async-process"))]
3use std::process::Stdio;
4
5use futures_util::AsyncWrite;
6#[cfg(feature = "tokio-process")]
7use tokio_util::compat::TokioAsyncWriteCompatExt;
8
9pub trait Process: Send + Sized {
12 type Stdin: AsyncWrite + Send + Unpin;
13
14 fn spawn(program: &str, args: Vec<&str>, pipe_output: bool) -> Result<Self, std::io::Error>;
15
16 fn output(
17 program: &str,
18 args: Vec<&str>,
19 ) -> impl Future<Output = Result<std::process::Output, std::io::Error>> + Send;
20
21 fn take_stdin(&mut self) -> Option<Self::Stdin>;
22
23 fn wait_with_output(
24 self,
25 ) -> impl Future<Output = Result<std::process::Output, std::io::Error>> + Send;
26}
27
28#[cfg(feature = "tokio-process")]
30#[cfg_attr(docsrs, doc(cfg(feature = "tokio-process")))]
31pub struct TokioProcess(tokio::process::Child);
32
33#[cfg(feature = "tokio-process")]
34#[cfg_attr(docsrs, doc(cfg(feature = "tokio-process")))]
35impl Process for TokioProcess {
36 type Stdin = tokio_util::compat::Compat<tokio::process::ChildStdin>;
37
38 fn spawn(program: &str, args: Vec<&str>, pipe_output: bool) -> Result<Self, std::io::Error> {
39 let mut command = tokio::process::Command::new(program);
40
41 command.args(args);
42
43 if pipe_output {
44 command
45 .stdout(Stdio::piped())
46 .stderr(Stdio::piped())
47 .stdin(Stdio::piped());
48 }
49
50 command.spawn().map(Self)
51 }
52
53 fn output(
54 program: &str,
55 args: Vec<&str>,
56 ) -> impl Future<Output = Result<std::process::Output, std::io::Error>> + Send {
57 let mut command = tokio::process::Command::new(program);
58 command.args(args).output()
59 }
60
61 fn take_stdin(&mut self) -> Option<Self::Stdin> {
62 self.0.stdin.take().map(|stdin| stdin.compat_write())
63 }
64
65 fn wait_with_output(
66 self,
67 ) -> impl Future<Output = Result<std::process::Output, std::io::Error>> + Send {
68 self.0.wait_with_output()
69 }
70}
71
72#[cfg(feature = "async-process")]
74#[cfg_attr(docsrs, doc(cfg(feature = "async-process")))]
75pub struct AsyncProcess(async_process::Child);
76
77#[cfg(feature = "async-process")]
78#[cfg_attr(docsrs, doc(cfg(feature = "async-process")))]
79impl Process for AsyncProcess {
80 type Stdin = async_process::ChildStdin;
81
82 fn spawn(program: &str, args: Vec<&str>, pipe_output: bool) -> Result<Self, std::io::Error> {
83 let mut command = async_process::Command::new(program);
84 command.args(args);
85
86 if pipe_output {
87 command
88 .stdout(Stdio::piped())
89 .stderr(Stdio::piped())
90 .stdin(Stdio::piped());
91 }
92
93 command.spawn().map(Self)
94 }
95
96 fn output(
97 program: &str,
98 args: Vec<&str>,
99 ) -> impl Future<Output = Result<std::process::Output, std::io::Error>> + Send {
100 let mut command = async_process::Command::new(program);
101 command.args(args).output()
102 }
103
104 fn take_stdin(&mut self) -> Option<Self::Stdin> {
105 self.0.stdin.take()
106 }
107
108 fn wait_with_output(
109 self,
110 ) -> impl Future<Output = Result<std::process::Output, std::io::Error>> + Send {
111 self.0.output()
112 }
113}