Skip to content

Commit 1def601

Browse files
authored
Make ChildStd{in, out, err} opaque types (#53)
For future Windows support. Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
1 parent 00fbbac commit 1def601

File tree

3 files changed

+112
-37
lines changed

3 files changed

+112
-37
lines changed

src/changelog.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ use crate::*;
99
/// ## Added
1010
/// - Added changelog
1111
/// - Added [`SessionBuilder::compression`]
12+
///
13+
/// ## Changed
14+
/// - Make [`ChildStdin`] an opaque type.
15+
/// - Make [`ChildStdout`] an opaque type.
16+
/// - Make [`ChildStderr`] an opaque type.
1217
#[doc(hidden)]
1318
pub mod unreleased {}
1419

src/command.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use super::stdio::{ChildInputWrapper, ChildOutputWrapper};
21
use super::RemoteChild;
32
use super::Stdio;
43
use super::{Error, Session};
@@ -236,18 +235,9 @@ impl<'s> Command<'s> {
236235
let (imp, stdin, stdout, stderr) = imp.spawn().await?;
237236
(
238237
imp.into(),
239-
stdin
240-
.map(TryFrom::try_from)
241-
.transpose()?
242-
.map(|wrapper: ChildInputWrapper| wrapper.0),
243-
stdout
244-
.map(TryFrom::try_from)
245-
.transpose()?
246-
.map(|wrapper: ChildOutputWrapper| wrapper.0),
247-
stderr
248-
.map(TryFrom::try_from)
249-
.transpose()?
250-
.map(|wrapper: ChildOutputWrapper| wrapper.0),
238+
stdin.map(TryFrom::try_from).transpose()?,
239+
stdout.map(TryFrom::try_from).transpose()?,
240+
stderr.map(TryFrom::try_from).transpose()?,
251241
)
252242
}),
253243
))

src/stdio.rs

Lines changed: 104 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ use io_lifetimes::OwnedFd;
77
use std::fs::File;
88
use std::io;
99
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
10+
use std::pin::Pin;
1011
use std::process;
11-
12-
use std::convert::TryFrom;
13-
use std::convert::TryInto;
12+
use std::task::{Context, Poll};
13+
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
1414

1515
pub(crate) unsafe fn dup(raw_fd: RawFd) -> Result<OwnedFd, Error> {
1616
let res = libc::dup(raw_fd);
@@ -101,40 +101,44 @@ impl_from_for_stdio!(process::ChildStdin);
101101
impl_from_for_stdio!(process::ChildStdout);
102102
impl_from_for_stdio!(process::ChildStderr);
103103

104+
impl_from_for_stdio!(ChildStdin);
105+
impl_from_for_stdio!(ChildStdout);
106+
impl_from_for_stdio!(ChildStderr);
107+
104108
impl_from_for_stdio!(File);
105109

106110
macro_rules! impl_try_from_tokio_process_child_for_stdio {
107-
($type:ident, $wrapper:ty) => {
111+
($type:ident) => {
108112
impl TryFrom<tokio::process::$type> for Stdio {
109113
type Error = Error;
110114

111115
fn try_from(arg: tokio::process::$type) -> Result<Self, Self::Error> {
112-
let wrapper: $wrapper = arg.try_into()?;
116+
let wrapper: $type = arg.try_into()?;
113117
Ok(wrapper.0.into())
114118
}
115119
}
116120
};
117121
}
118122

119-
impl_try_from_tokio_process_child_for_stdio!(ChildStdin, ChildInputWrapper);
120-
impl_try_from_tokio_process_child_for_stdio!(ChildStdout, ChildOutputWrapper);
121-
impl_try_from_tokio_process_child_for_stdio!(ChildStderr, ChildOutputWrapper);
123+
impl_try_from_tokio_process_child_for_stdio!(ChildStdin);
124+
impl_try_from_tokio_process_child_for_stdio!(ChildStdout);
125+
impl_try_from_tokio_process_child_for_stdio!(ChildStderr);
122126

123127
/// Input for the remote child.
124-
pub type ChildStdin = tokio_pipe::PipeWrite;
128+
#[derive(Debug)]
129+
pub struct ChildStdin(tokio_pipe::PipeWrite);
125130

126131
/// Stdout for the remote child.
127-
pub type ChildStdout = tokio_pipe::PipeRead;
132+
#[derive(Debug)]
133+
pub struct ChildStdout(tokio_pipe::PipeRead);
128134

129135
/// Stderr for the remote child.
130-
pub type ChildStderr = tokio_pipe::PipeRead;
131-
132-
pub(crate) struct ChildInputWrapper(pub(crate) ChildStdin);
133-
pub(crate) struct ChildOutputWrapper(pub(crate) ChildStderr);
136+
#[derive(Debug)]
137+
pub struct ChildStderr(tokio_pipe::PipeRead);
134138

135139
macro_rules! impl_from_impl_child_io {
136-
(process, $type:ident, $wrapper:ty) => {
137-
impl TryFrom<tokio::process::$type> for $wrapper {
140+
(process, $type:ident, $inner:ty) => {
141+
impl TryFrom<tokio::process::$type> for $type {
138142
type Error = Error;
139143

140144
fn try_from(arg: tokio::process::$type) -> Result<Self, Self::Error> {
@@ -143,15 +147,15 @@ macro_rules! impl_from_impl_child_io {
143147
// safety: arg.as_raw_fd() is guaranteed to return a valid fd.
144148
let fd = unsafe { dup(fd) }?.into_raw_fd();
145149
Ok(Self(
146-
$type::from_raw_fd_checked(fd).map_err(Error::ChildIo)?,
150+
<$inner>::from_raw_fd_checked(fd).map_err(Error::ChildIo)?,
147151
))
148152
}
149153
}
150154
};
151155

152-
(native_mux, $type:ident, $wrapper:ty) => {
156+
(native_mux, $type:ident) => {
153157
#[cfg(feature = "native-mux")]
154-
impl TryFrom<native_mux_impl::$type> for $wrapper {
158+
impl TryFrom<native_mux_impl::$type> for $type {
155159
type Error = Error;
156160

157161
fn try_from(arg: native_mux_impl::$type) -> Result<Self, Self::Error> {
@@ -161,9 +165,85 @@ macro_rules! impl_from_impl_child_io {
161165
};
162166
}
163167

164-
impl_from_impl_child_io!(process, ChildStdin, ChildInputWrapper);
165-
impl_from_impl_child_io!(process, ChildStdout, ChildOutputWrapper);
166-
impl_from_impl_child_io!(process, ChildStderr, ChildOutputWrapper);
168+
impl_from_impl_child_io!(process, ChildStdin, tokio_pipe::PipeWrite);
169+
impl_from_impl_child_io!(process, ChildStdout, tokio_pipe::PipeRead);
170+
impl_from_impl_child_io!(process, ChildStderr, tokio_pipe::PipeRead);
171+
172+
impl_from_impl_child_io!(native_mux, ChildStdin);
173+
impl_from_impl_child_io!(native_mux, ChildStdout);
174+
impl_from_impl_child_io!(native_mux, ChildStderr);
175+
176+
macro_rules! impl_child_stdio {
177+
(AsRawFd, $type:ty) => {
178+
impl AsRawFd for $type {
179+
fn as_raw_fd(&self) -> RawFd {
180+
self.0.as_raw_fd()
181+
}
182+
}
183+
};
184+
185+
(IntoRawFd, $type:ty) => {
186+
impl IntoRawFd for $type {
187+
fn into_raw_fd(self) -> RawFd {
188+
self.0.into_raw_fd()
189+
}
190+
}
191+
};
192+
193+
(AsyncRead, $type:ty) => {
194+
impl_child_stdio!(AsRawFd, $type);
195+
impl_child_stdio!(IntoRawFd, $type);
196+
197+
impl AsyncRead for $type {
198+
fn poll_read(
199+
mut self: Pin<&mut Self>,
200+
cx: &mut Context<'_>,
201+
buf: &mut ReadBuf<'_>,
202+
) -> Poll<io::Result<()>> {
203+
Pin::new(&mut self.0).poll_read(cx, buf)
204+
}
205+
}
206+
};
207+
208+
(AsyncWrite, $type: ty) => {
209+
impl_child_stdio!(AsRawFd, $type);
210+
impl_child_stdio!(IntoRawFd, $type);
211+
212+
impl AsyncWrite for $type {
213+
fn poll_write(
214+
mut self: Pin<&mut Self>,
215+
cx: &mut Context<'_>,
216+
buf: &[u8],
217+
) -> Poll<io::Result<usize>> {
218+
Pin::new(&mut self.0).poll_write(cx, buf)
219+
}
220+
221+
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
222+
Pin::new(&mut self.0).poll_flush(cx)
223+
}
224+
225+
fn poll_shutdown(
226+
mut self: Pin<&mut Self>,
227+
cx: &mut Context<'_>,
228+
) -> Poll<io::Result<()>> {
229+
Pin::new(&mut self.0).poll_shutdown(cx)
230+
}
231+
232+
fn poll_write_vectored(
233+
mut self: Pin<&mut Self>,
234+
cx: &mut Context<'_>,
235+
bufs: &[io::IoSlice<'_>],
236+
) -> Poll<io::Result<usize>> {
237+
Pin::new(&mut self.0).poll_write_vectored(cx, bufs)
238+
}
239+
240+
fn is_write_vectored(&self) -> bool {
241+
self.0.is_write_vectored()
242+
}
243+
}
244+
};
245+
}
167246

168-
impl_from_impl_child_io!(native_mux, ChildStdin, ChildInputWrapper);
169-
impl_from_impl_child_io!(native_mux, ChildStdout, ChildOutputWrapper);
247+
impl_child_stdio!(AsyncWrite, ChildStdin);
248+
impl_child_stdio!(AsyncRead, ChildStdout);
249+
impl_child_stdio!(AsyncRead, ChildStderr);

0 commit comments

Comments
 (0)