nftables_async/
process.rs

1use 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
9/// A process backend to use for asynchronous I/O, supporting only the functionality needed by
10/// the nftables-async crate.
11pub 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/// A [Process] implementation using the tokio crate for I/O.
29#[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/// A [Process] implementation using the async-process crate for I/O.
73#[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}