diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 1fa13e95e6872..394dc90e07782 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -310,6 +310,8 @@ pub use self::error::RawOsError; pub use self::error::SimpleMessage; #[unstable(feature = "io_const_error", issue = "133448")] pub use self::error::const_error; +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +pub use self::pipe::{PipeReader, PipeWriter, pipe}; #[stable(feature = "is_terminal", since = "1.70.0")] pub use self::stdio::IsTerminal; pub(crate) use self::stdio::attempt_print_to_stderr; @@ -330,7 +332,6 @@ pub use self::{ }; use crate::mem::take; use crate::ops::{Deref, DerefMut}; -use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; use crate::{cmp, fmt, slice, str, sys}; mod buffered; @@ -338,6 +339,7 @@ pub(crate) mod copy; mod cursor; mod error; mod impls; +mod pipe; pub mod prelude; mod stdio; mod util; @@ -3251,257 +3253,3 @@ impl Iterator for Lines { } } } - -/// Create an anonymous pipe that is close-on-exec and blocking. -/// -/// # Behavior -/// -/// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is -/// typically used to communicate between two or more separate processes, as there are better, -/// faster ways to communicate within a single process. -/// -/// In particular: -/// -/// * A read on a [`PipeReader`] blocks until the pipe is non-empty. -/// * A write on a [`PipeWriter`] blocks when the pipe is full. -/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`] -/// returns EOF. -/// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but -/// writes (above a target-specific threshold) may have their data interleaved. -/// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any -/// given byte will only get consumed by one reader. There are no guarantees about data -/// interleaving. -/// * Portable applications cannot assume any atomicity of messages larger than a single byte. -/// -/// # Capacity -/// -/// Pipe capacity is platform dependent. To quote the Linux [man page]: -/// -/// > Different implementations have different limits for the pipe capacity. Applications should -/// > not rely on a particular capacity: an application should be designed so that a reading process -/// > consumes data as soon as it is available, so that a writing process does not remain blocked. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(anonymous_pipe)] -/// # #[cfg(miri)] fn main() {} -/// # #[cfg(not(miri))] -/// # fn main() -> std::io::Result<()> { -/// # use std::process::Command; -/// # use std::io::{Read, Write}; -/// let (ping_rx, mut ping_tx) = std::io::pipe()?; -/// let (mut pong_rx, pong_tx) = std::io::pipe()?; -/// -/// // Spawn a process that echoes its input. -/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; -/// -/// ping_tx.write_all(b"hello")?; -/// // Close to unblock echo_server's reader. -/// drop(ping_tx); -/// -/// let mut buf = String::new(); -/// // Block until echo_server's writer is closed. -/// pong_rx.read_to_string(&mut buf)?; -/// assert_eq!(&buf, "hello"); -/// -/// echo_server.wait()?; -/// # Ok(()) -/// # } -/// ``` -/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[inline] -pub fn pipe() -> Result<(PipeReader, PipeWriter)> { - pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) -} - -/// Read end of an anonymous pipe. -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[derive(Debug)] -pub struct PipeReader(pub(crate) AnonPipe); - -/// Write end of an anonymous pipe. -#[unstable(feature = "anonymous_pipe", issue = "127154")] -#[derive(Debug)] -pub struct PipeWriter(pub(crate) AnonPipe); - -impl PipeReader { - /// Create a new [`PipeReader`] instance that shares the same underlying file description. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(anonymous_pipe)] - /// # #[cfg(miri)] fn main() {} - /// # #[cfg(not(miri))] - /// # fn main() -> std::io::Result<()> { - /// # use std::fs; - /// # use std::io::Write; - /// # use std::process::Command; - /// const NUM_SLOT: u8 = 2; - /// const NUM_PROC: u8 = 5; - /// const OUTPUT: &str = "work.txt"; - /// - /// let mut jobs = vec![]; - /// let (reader, mut writer) = std::io::pipe()?; - /// - /// // Write NUM_SLOT characters the pipe. - /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; - /// - /// // Spawn several processes that read a character from the pipe, do some work, then - /// // write back to the pipe. When the pipe is empty, the processes block, so only - /// // NUM_SLOT processes can be working at any given time. - /// for _ in 0..NUM_PROC { - /// jobs.push( - /// Command::new("bash") - /// .args(["-c", - /// &format!( - /// "read -n 1\n\ - /// echo -n 'x' >> '{OUTPUT}'\n\ - /// echo -n '|'", - /// ), - /// ]) - /// .stdin(reader.try_clone()?) - /// .stdout(writer.try_clone()?) - /// .spawn()?, - /// ); - /// } - /// - /// // Wait for all jobs to finish. - /// for mut job in jobs { - /// job.wait()?; - /// } - /// - /// // Check our work and clean up. - /// let xs = fs::read_to_string(OUTPUT)?; - /// fs::remove_file(OUTPUT)?; - /// assert_eq!(xs, "x".repeat(NUM_PROC.into())); - /// # Ok(()) - /// # } - /// ``` - #[unstable(feature = "anonymous_pipe", issue = "127154")] - pub fn try_clone(&self) -> Result { - self.0.try_clone().map(Self) - } -} - -impl PipeWriter { - /// Create a new [`PipeWriter`] instance that shares the same underlying file description. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(anonymous_pipe)] - /// # #[cfg(miri)] fn main() {} - /// # #[cfg(not(miri))] - /// # fn main() -> std::io::Result<()> { - /// # use std::process::Command; - /// # use std::io::Read; - /// let (mut reader, writer) = std::io::pipe()?; - /// - /// // Spawn a process that writes to stdout and stderr. - /// let mut peer = Command::new("bash") - /// .args([ - /// "-c", - /// "echo -n foo\n\ - /// echo -n bar >&2" - /// ]) - /// .stdout(writer.try_clone()?) - /// .stderr(writer) - /// .spawn()?; - /// - /// // Read and check the result. - /// let mut msg = String::new(); - /// reader.read_to_string(&mut msg)?; - /// assert_eq!(&msg, "foobar"); - /// - /// peer.wait()?; - /// # Ok(()) - /// # } - /// ``` - #[unstable(feature = "anonymous_pipe", issue = "127154")] - pub fn try_clone(&self) -> Result { - self.0.try_clone().map(Self) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Read for &PipeReader { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.0.read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { - self.0.read_vectored(bufs) - } - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - self.0.read_to_end(buf) - } - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { - self.0.read_buf(buf) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Read for PipeReader { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.0.read(buf) - } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { - self.0.read_vectored(bufs) - } - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - self.0.read_to_end(buf) - } - fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { - self.0.read_buf(buf) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Write for &PipeWriter { - fn write(&mut self, buf: &[u8]) -> Result { - self.0.write(buf) - } - #[inline] - fn flush(&mut self) -> Result<()> { - Ok(()) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl Write for PipeWriter { - fn write(&mut self, buf: &[u8]) -> Result { - self.0.write(buf) - } - #[inline] - fn flush(&mut self) -> Result<()> { - Ok(()) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } -} diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs new file mode 100644 index 0000000000000..7cedc20b2bfaa --- /dev/null +++ b/library/std/src/io/pipe.rs @@ -0,0 +1,288 @@ +use crate::io; +use crate::sys::pipe::{AnonPipe, anon_pipe}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +/// Create an anonymous pipe. +/// +/// # Behavior +/// +/// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is +/// typically used to communicate between two or more separate processes, as there are better, +/// faster ways to communicate within a single process. +/// +/// In particular: +/// +/// * A read on a [`PipeReader`] blocks until the pipe is non-empty. +/// * A write on a [`PipeWriter`] blocks when the pipe is full. +/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`] +/// returns EOF. +/// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but +/// writes (above a target-specific threshold) may have their data interleaved. +/// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any +/// given byte will only get consumed by one reader. There are no guarantees about data +/// interleaving. +/// * Portable applications cannot assume any atomicity of messages larger than a single byte. +/// +/// # Platform-specific behavior +/// +/// This function currently corresponds to the `pipe` function on Unix and the +/// `CreatePipe` function on Windows. +/// +/// Note that this [may change in the future][changes]. +/// +/// # Capacity +/// +/// Pipe capacity is platform dependent. To quote the Linux [man page]: +/// +/// > Different implementations have different limits for the pipe capacity. Applications should +/// > not rely on a particular capacity: an application should be designed so that a reading process +/// > consumes data as soon as it is available, so that a writing process does not remain blocked. +/// +/// # Examples +/// +/// ```no_run +/// use std::process::Command; +/// use std::io::{pipe, Read, Write}; +/// +/// let (ping_rx, mut ping_tx) = pipe()?; +/// let (mut pong_rx, pong_tx) = pipe()?; +/// +/// // Spawn a process that echoes its input. +/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?; +/// +/// ping_tx.write_all(b"hello")?; +/// // Close to unblock echo_server's reader. +/// drop(ping_tx); +/// +/// let mut buf = String::new(); +/// // Block until echo_server's writer is closed. +/// pong_rx.read_to_string(&mut buf)?; +/// assert_eq!(&buf, "hello"); +/// +/// echo_server.wait()?; +/// # Ok::<(), std::io::Error>(()) +/// ``` +/// [changes]: io#platform-specific-behavior +/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[inline] +pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> { + anon_pipe() + .map(|(reader, writer)| (PipeReader::from_inner(reader), PipeWriter::from_inner(writer))) +} + +/// Read end of an anonymous pipe. +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[derive(Debug)] +pub struct PipeReader { + inner: AnonPipe, +} + +/// Write end of an anonymous pipe. +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +#[derive(Debug)] +pub struct PipeWriter { + inner: AnonPipe, +} + +impl PipeReader { + /// Create a new [`PipeReader`] instance that shares the same underlying file description. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io::{pipe, Write}; + /// use std::process::Command; + /// + /// const NUM_SLOT: u8 = 2; + /// const NUM_PROC: u8 = 5; + /// const OUTPUT: &str = "work.txt"; + /// + /// let mut jobs = vec![]; + /// let (reader, mut writer) = pipe()?; + /// + /// // Write NUM_SLOT characters the pipe. + /// writer.write_all(&[b'|'; NUM_SLOT as usize])?; + /// + /// // Spawn several processes that read a character from the pipe, do some work, then + /// // write back to the pipe. When the pipe is empty, the processes block, so only + /// // NUM_SLOT processes can be working at any given time. + /// for _ in 0..NUM_PROC { + /// jobs.push( + /// Command::new("bash") + /// .args(["-c", + /// &format!( + /// "read -n 1\n\ + /// echo -n 'x' >> '{OUTPUT}'\n\ + /// echo -n '|'", + /// ), + /// ]) + /// .stdin(reader.try_clone()?) + /// .stdout(writer.try_clone()?) + /// .spawn()?, + /// ); + /// } + /// + /// // Wait for all jobs to finish. + /// for mut job in jobs { + /// job.wait()?; + /// } + /// + /// // Check our work and clean up. + /// let xs = fs::read_to_string(OUTPUT)?; + /// fs::remove_file(OUTPUT)?; + /// assert_eq!(xs, "x".repeat(NUM_PROC.into())); + /// # Ok::<(), std::io::Error>(()) + /// ``` + #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] + pub fn try_clone(&self) -> io::Result { + self.as_inner().try_clone().map(Self::from_inner) + } +} + +impl PipeWriter { + /// Create a new [`PipeWriter`] instance that shares the same underlying file description. + /// + /// # Examples + /// + /// ```no_run + /// use std::process::Command; + /// use std::io::{pipe, Read}; + /// + /// let (mut reader, writer) = pipe()?; + /// + /// // Spawn a process that writes to stdout and stderr. + /// let mut peer = Command::new("bash") + /// .args([ + /// "-c", + /// "echo -n foo\n\ + /// echo -n bar >&2" + /// ]) + /// .stdout(writer.try_clone()?) + /// .stderr(writer) + /// .spawn()?; + /// + /// // Read and check the result. + /// let mut msg = String::new(); + /// reader.read_to_string(&mut msg)?; + /// assert_eq!(&msg, "foobar"); + /// + /// peer.wait()?; + /// # Ok::<(), std::io::Error>(()) + /// ``` + #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] + pub fn try_clone(&self) -> io::Result { + self.as_inner().try_clone().map(Self::from_inner) + } +} + +impl AsInner for PipeReader { + #[inline] + fn as_inner(&self) -> &AnonPipe { + &self.inner + } +} +impl FromInner for PipeReader { + fn from_inner(pipe: AnonPipe) -> PipeReader { + PipeReader { inner: pipe } + } +} +impl IntoInner for PipeReader { + fn into_inner(self) -> AnonPipe { + self.inner + } +} + +impl AsInner for PipeWriter { + #[inline] + fn as_inner(&self) -> &AnonPipe { + &self.inner + } +} +impl FromInner for PipeWriter { + fn from_inner(pipe: AnonPipe) -> PipeWriter { + PipeWriter { inner: pipe } + } +} +impl IntoInner for PipeWriter { + fn into_inner(self) -> AnonPipe { + self.inner + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl io::Read for &PipeReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.as_inner().read(buf) + } + fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { + self.as_inner().read_vectored(bufs) + } + #[inline] + fn is_read_vectored(&self) -> bool { + self.as_inner().is_read_vectored() + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + self.as_inner().read_to_end(buf) + } + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + self.as_inner().read_buf(buf) + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl io::Read for PipeReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.as_inner().read(buf) + } + fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result { + self.as_inner().read_vectored(bufs) + } + #[inline] + fn is_read_vectored(&self) -> bool { + self.as_inner().is_read_vectored() + } + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + self.as_inner().read_to_end(buf) + } + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + self.as_inner().read_buf(buf) + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl io::Write for &PipeWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.as_inner().write(buf) + } + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + self.as_inner().write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + self.as_inner().is_write_vectored() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl io::Write for PipeWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.as_inner().write(buf) + } + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result { + self.as_inner().write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + self.as_inner().is_write_vectored() + } +} diff --git a/library/std/src/io/pipe/tests.rs b/library/std/src/io/pipe/tests.rs new file mode 100644 index 0000000000000..c1f3f192ca2d7 --- /dev/null +++ b/library/std/src/io/pipe/tests.rs @@ -0,0 +1,18 @@ +use crate::io::{Read, Write, pipe}; + +#[test] +#[cfg(all(windows, unix, not(miri)))] +fn pipe_creation_clone_and_rw() { + let (rx, tx) = pipe().unwrap(); + + tx.try_clone().unwrap().write_all(b"12345").unwrap(); + drop(tx); + + let mut rx2 = rx.try_clone().unwrap(); + drop(rx); + + let mut s = String::new(); + rx2.read_to_string(&mut s).unwrap(); + drop(rx2); + assert_eq!(s, "12345"); +} diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index 226cc6011bcab..f64f034cce779 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -821,20 +821,3 @@ fn try_oom_error() { let io_err = io::Error::from(reserve_err); assert_eq!(io::ErrorKind::OutOfMemory, io_err.kind()); } - -#[test] -#[cfg(all(windows, unix, not(miri)))] -fn pipe_creation_clone_and_rw() { - let (rx, tx) = std::io::pipe().unwrap(); - - tx.try_clone().unwrap().write_all(b"12345").unwrap(); - drop(tx); - - let mut rx2 = rx.try_clone().unwrap(); - drop(rx); - - let mut s = String::new(); - rx2.read_to_string(&mut s).unwrap(); - drop(rx2); - assert_eq!(s, "12345"); -} diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 1e814eca3c1a5..b33c0513c021c 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -310,6 +310,44 @@ impl From for fs::File { } } +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsFd for io::PipeReader { + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for OwnedFd { + fn from(pipe: io::PipeReader) -> OwnedFd { + pipe.into_inner().into_inner().into_inner() + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for io::PipeReader { + fn from(owned_fd: OwnedFd) -> io::PipeReader { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsFd for io::PipeWriter { + fn as_fd(&self) -> BorrowedFd<'_> { + self.as_inner().as_fd() + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for OwnedFd { + fn from(pipe: io::PipeWriter) -> OwnedFd { + pipe.into_inner().into_inner().into_inner() + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for io::PipeWriter { + fn from(owned_fd: OwnedFd) -> io::PipeWriter { + Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd))) + } +} + #[stable(feature = "io_safety", since = "1.63.0")] impl AsFd for crate::net::TcpStream { #[inline] diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 03dff94350dad..16fed29372306 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -15,7 +15,7 @@ use crate::os::unix::io::AsFd; use crate::os::unix::io::OwnedFd; #[cfg(target_os = "wasi")] use crate::os::wasi::io::OwnedFd; -use crate::sys_common::{AsInner, IntoInner}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fs, io}; /// Raw file descriptors. @@ -182,6 +182,43 @@ impl IntoRawFd for fs::File { } } +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsRawFd for io::PipeReader { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().as_raw_fd() + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl FromRawFd for io::PipeReader { + unsafe fn from_raw_fd(raw_fd: RawFd) -> io::PipeReader { + unsafe { io::PipeReader::from_inner(FromRawFd::from_raw_fd(raw_fd)) } + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl IntoRawFd for io::PipeReader { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_raw_fd() + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsRawFd for io::PipeWriter { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().as_raw_fd() + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl FromRawFd for io::PipeWriter { + unsafe fn from_raw_fd(raw_fd: RawFd) -> io::PipeWriter { + unsafe { io::PipeWriter::from_inner(FromRawFd::from_raw_fd(raw_fd)) } + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl IntoRawFd for io::PipeWriter { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_raw_fd() + } +} + #[stable(feature = "asraw_stdio", since = "1.21.0")] impl AsRawFd for io::Stdin { #[inline] diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 76f5f549dd244..23872526432e1 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -185,7 +185,7 @@ impl OwnedHandle { /// Creates a new `OwnedHandle` instance that shares the same underlying /// object as the existing `OwnedHandle` instance. #[stable(feature = "io_safety", since = "1.63.0")] - pub fn try_clone(&self) -> crate::io::Result { + pub fn try_clone(&self) -> io::Result { self.as_handle().try_clone_to_owned() } } @@ -194,7 +194,7 @@ impl BorrowedHandle<'_> { /// Creates a new `OwnedHandle` instance that shares the same underlying /// object as the existing `BorrowedHandle` instance. #[stable(feature = "io_safety", since = "1.63.0")] - pub fn try_clone_to_owned(&self) -> crate::io::Result { + pub fn try_clone_to_owned(&self) -> io::Result { self.duplicate(0, false, sys::c::DUPLICATE_SAME_ACCESS) } @@ -410,7 +410,7 @@ macro_rules! impl_is_terminal { impl crate::sealed::Sealed for $t {} #[stable(feature = "is_terminal", since = "1.70.0")] - impl crate::io::IsTerminal for $t { + impl io::IsTerminal for $t { #[inline] fn is_terminal(&self) -> bool { crate::sys::io::is_terminal(self) @@ -546,8 +546,46 @@ impl From for fs::File { } } +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsHandle for io::PipeReader { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.as_inner().as_handle() + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for OwnedHandle { + fn from(pipe: io::PipeReader) -> OwnedHandle { + pipe.into_inner().into_inner().into_inner() + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for io::PipeReader { + fn from(owned: OwnedHandle) -> io::PipeReader { + io::PipeReader::from_inner(FromInner::from_inner(FromInner::from_inner(owned))) + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsHandle for io::PipeWriter { + fn as_handle(&self) -> BorrowedHandle<'_> { + self.as_inner().as_handle() + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for OwnedHandle { + fn from(pipe: io::PipeWriter) -> OwnedHandle { + pipe.into_inner().into_inner().into_inner() + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for io::PipeWriter { + fn from(owned: OwnedHandle) -> io::PipeWriter { + io::PipeWriter::from_inner(FromInner::from_inner(FromInner::from_inner(owned))) + } +} + #[stable(feature = "io_safety", since = "1.63.0")] -impl AsHandle for crate::io::Stdin { +impl AsHandle for io::Stdin { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } @@ -555,7 +593,7 @@ impl AsHandle for crate::io::Stdin { } #[stable(feature = "io_safety", since = "1.63.0")] -impl<'a> AsHandle for crate::io::StdinLock<'a> { +impl<'a> AsHandle for io::StdinLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } @@ -563,7 +601,7 @@ impl<'a> AsHandle for crate::io::StdinLock<'a> { } #[stable(feature = "io_safety", since = "1.63.0")] -impl AsHandle for crate::io::Stdout { +impl AsHandle for io::Stdout { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } @@ -571,7 +609,7 @@ impl AsHandle for crate::io::Stdout { } #[stable(feature = "io_safety", since = "1.63.0")] -impl<'a> AsHandle for crate::io::StdoutLock<'a> { +impl<'a> AsHandle for io::StdoutLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } @@ -579,7 +617,7 @@ impl<'a> AsHandle for crate::io::StdoutLock<'a> { } #[stable(feature = "io_safety", since = "1.63.0")] -impl AsHandle for crate::io::Stderr { +impl AsHandle for io::Stderr { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } @@ -587,7 +625,7 @@ impl AsHandle for crate::io::Stderr { } #[stable(feature = "io_safety", since = "1.63.0")] -impl<'a> AsHandle for crate::io::StderrLock<'a> { +impl<'a> AsHandle for io::StderrLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index 6658248d574c9..11f2174435eb5 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -98,6 +98,20 @@ impl AsRawHandle for fs::File { } } +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsRawHandle for io::PipeReader { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().as_raw_handle() + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl AsRawHandle for io::PipeWriter { + fn as_raw_handle(&self) -> RawHandle { + self.as_inner().as_raw_handle() + } +} + #[stable(feature = "asraw_stdio", since = "1.21.0")] impl AsRawHandle for io::Stdin { fn as_raw_handle(&self) -> RawHandle { @@ -158,7 +172,7 @@ impl FromRawHandle for fs::File { unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { unsafe { let handle = handle as sys::c::HANDLE; - fs::File::from_inner(sys::fs::File::from_inner(FromInner::from_inner( + fs::File::from_inner(FromInner::from_inner(FromInner::from_inner( OwnedHandle::from_raw_handle(handle), ))) } @@ -173,6 +187,42 @@ impl IntoRawHandle for fs::File { } } +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl FromRawHandle for io::PipeReader { + unsafe fn from_raw_handle(raw_handle: RawHandle) -> io::PipeReader { + unsafe { + let handle = handle as sys::c::HANDLE; + io::PipeReader::from_inner(FromInner::from_inner(FromInner::from_inner( + OwnedHandle::from_raw_handle(handle), + ))) + } + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl IntoRawHandle for io::PipeReader { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_raw_handle() as *mut _ + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl FromRawHandle for io::PipeWriter { + unsafe fn from_raw_handle(raw_handle: RawHandle) -> io::PipeWriter { + unsafe { + let handle = handle as sys::c::HANDLE; + io::PipeReader::from_inner(FromInner::from_inner(FromInner::from_inner( + OwnedHandle::from_raw_handle(handle), + ))) + } + } +} +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl IntoRawHandle for io::PipeWriter { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_raw_handle() as *mut _ + } +} + /// Extracts raw sockets. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawSocket { diff --git a/library/std/src/process.rs b/library/std/src/process.rs index e0dd2e14817a8..7b118d3e95498 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1657,6 +1657,34 @@ impl From for Stdio { } } +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for Stdio { + /// Make command stdin read from an opened pipe. + /// + /// # Examples + /// + /// ```rust + /// todo!(); + /// ``` + fn from(pipe: io::PipeReader) -> Stdio { + Stdio::from_inner(pipe.into()) + } +} + +#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")] +impl From for Stdio { + /// Redirect command stdout/stderr to an opened pipe. + /// + /// # Examples + /// + /// ```rust + /// todo!(); + /// ``` + fn from(pipe: io::PipeWriter) -> Stdio { + Stdio::from_inner(pipe.into()) + } +} + /// Describes the result of a process after it has terminated. /// /// This `struct` is used to represent the exit status or other termination of a child process. diff --git a/library/std/src/sys/anonymous_pipe/mod.rs b/library/std/src/sys/anonymous_pipe/mod.rs deleted file mode 100644 index aa14c8b650d34..0000000000000 --- a/library/std/src/sys/anonymous_pipe/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -cfg_if::cfg_if! { - if #[cfg(unix)] { - mod unix; - pub use unix::{AnonPipe, pipe}; - } else if #[cfg(windows)] { - mod windows; - pub use windows::{AnonPipe, pipe}; - } else { - mod unsupported; - pub use unsupported::{AnonPipe, pipe}; - } -} diff --git a/library/std/src/sys/anonymous_pipe/unix.rs b/library/std/src/sys/anonymous_pipe/unix.rs deleted file mode 100644 index 9e398765634b7..0000000000000 --- a/library/std/src/sys/anonymous_pipe/unix.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::io::{self, PipeReader, PipeWriter}; -use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; -use crate::process::Stdio; -use crate::sys::fd::FileDesc; -use crate::sys::pipe::anon_pipe; -use crate::sys_common::{FromInner, IntoInner}; - -pub type AnonPipe = FileDesc; - -#[inline] -pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { - anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner())) -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl AsFd for PipeReader { - fn as_fd(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl AsRawFd for PipeReader { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for OwnedFd { - fn from(pipe: PipeReader) -> Self { - FileDesc::into_inner(pipe.0) - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl FromRawFd for PipeReader { - unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - unsafe { Self(FileDesc::from_raw_fd(raw_fd)) } - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl IntoRawFd for PipeReader { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for Stdio { - fn from(pipe: PipeReader) -> Self { - Self::from(OwnedFd::from(pipe)) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl AsFd for PipeWriter { - fn as_fd(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl AsRawFd for PipeWriter { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for OwnedFd { - fn from(pipe: PipeWriter) -> Self { - FileDesc::into_inner(pipe.0) - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl FromRawFd for PipeWriter { - unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - unsafe { Self(FileDesc::from_raw_fd(raw_fd)) } - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl IntoRawFd for PipeWriter { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for Stdio { - fn from(pipe: PipeWriter) -> Self { - Self::from(OwnedFd::from(pipe)) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for PipeReader { - fn from(owned_fd: OwnedFd) -> Self { - Self(FileDesc::from_inner(owned_fd)) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for PipeWriter { - fn from(owned_fd: OwnedFd) -> Self { - Self(FileDesc::from_inner(owned_fd)) - } -} diff --git a/library/std/src/sys/anonymous_pipe/unsupported.rs b/library/std/src/sys/anonymous_pipe/unsupported.rs deleted file mode 100644 index 4e79ac9c21aad..0000000000000 --- a/library/std/src/sys/anonymous_pipe/unsupported.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::io::{self, PipeReader, PipeWriter}; -use crate::process::Stdio; -pub use crate::sys::pipe::AnonPipe; - -#[inline] -pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { - Err(io::Error::UNSUPPORTED_PLATFORM) -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for Stdio { - fn from(pipe: PipeReader) -> Self { - pipe.0.diverge() - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for Stdio { - fn from(pipe: PipeWriter) -> Self { - pipe.0.diverge() - } -} diff --git a/library/std/src/sys/anonymous_pipe/windows.rs b/library/std/src/sys/anonymous_pipe/windows.rs deleted file mode 100644 index eb7fa8ec1c9a1..0000000000000 --- a/library/std/src/sys/anonymous_pipe/windows.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::io::{self, PipeReader, PipeWriter}; -use crate::os::windows::io::{ - AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle, -}; -use crate::process::Stdio; -use crate::ptr; -use crate::sys::c; -use crate::sys::handle::Handle; -use crate::sys_common::{FromInner, IntoInner}; - -pub type AnonPipe = Handle; - -pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { - let mut read_pipe = c::INVALID_HANDLE_VALUE; - let mut write_pipe = c::INVALID_HANDLE_VALUE; - - let ret = unsafe { c::CreatePipe(&mut read_pipe, &mut write_pipe, ptr::null_mut(), 0) }; - - if ret == 0 { - Err(io::Error::last_os_error()) - } else { - unsafe { Ok((Handle::from_raw_handle(read_pipe), Handle::from_raw_handle(write_pipe))) } - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl AsHandle for PipeReader { - fn as_handle(&self) -> BorrowedHandle<'_> { - self.0.as_handle() - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl AsRawHandle for PipeReader { - fn as_raw_handle(&self) -> RawHandle { - self.0.as_raw_handle() - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl FromRawHandle for PipeReader { - unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - unsafe { Self(Handle::from_raw_handle(raw_handle)) } - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl IntoRawHandle for PipeReader { - fn into_raw_handle(self) -> RawHandle { - self.0.into_raw_handle() - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for OwnedHandle { - fn from(pipe: PipeReader) -> Self { - Handle::into_inner(pipe.0) - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for Stdio { - fn from(pipe: PipeReader) -> Self { - Self::from(OwnedHandle::from(pipe)) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl AsHandle for PipeWriter { - fn as_handle(&self) -> BorrowedHandle<'_> { - self.0.as_handle() - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl AsRawHandle for PipeWriter { - fn as_raw_handle(&self) -> RawHandle { - self.0.as_raw_handle() - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl FromRawHandle for PipeWriter { - unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - unsafe { Self(Handle::from_raw_handle(raw_handle)) } - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl IntoRawHandle for PipeWriter { - fn into_raw_handle(self) -> RawHandle { - self.0.into_raw_handle() - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for OwnedHandle { - fn from(pipe: PipeWriter) -> Self { - Handle::into_inner(pipe.0) - } -} -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for Stdio { - fn from(pipe: PipeWriter) -> Self { - Self::from(OwnedHandle::from(pipe)) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for PipeReader { - fn from(owned_handle: OwnedHandle) -> Self { - Self(Handle::from_inner(owned_handle)) - } -} - -#[unstable(feature = "anonymous_pipe", issue = "127154")] -impl From for PipeWriter { - fn from(owned_handle: OwnedHandle) -> Self { - Self(Handle::from_inner(owned_handle)) - } -} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index f17dd47decedc..1cc321f9ffb99 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -8,7 +8,6 @@ mod pal; mod alloc; mod personality; -pub mod anonymous_pipe; pub mod backtrace; pub mod cmath; pub mod exit_guard; diff --git a/library/std/src/sys/pal/unix/process/process_common.rs b/library/std/src/sys/pal/unix/process/process_common.rs index 342818ac91183..e9b91ecf5e281 100644 --- a/library/std/src/sys/pal/unix/process/process_common.rs +++ b/library/std/src/sys/pal/unix/process/process_common.rs @@ -494,6 +494,18 @@ impl From for Stdio { } } +impl From for Stdio { + fn from(pipe: io::PipeReader) -> Stdio { + pipe.into_inner().into() + } +} + +impl From for Stdio { + fn from(pipe: io::PipeWriter) -> Stdio { + pipe.into_inner().into() + } +} + impl From for Stdio { fn from(file: File) -> Stdio { Stdio::Fd(file.into_inner()) diff --git a/library/std/src/sys/pal/unsupported/pipe.rs b/library/std/src/sys/pal/unsupported/pipe.rs index 6799d21a1ff75..f1dce4b7657bc 100644 --- a/library/std/src/sys/pal/unsupported/pipe.rs +++ b/library/std/src/sys/pal/unsupported/pipe.rs @@ -3,6 +3,10 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; pub struct AnonPipe(!); +pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { + Err(io::Error::UNSUPPORTED_PLATFORM) +} + impl fmt::Debug for AnonPipe { fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { self.0 diff --git a/library/std/src/sys/pal/windows/handle/tests.rs b/library/std/src/sys/pal/windows/handle/tests.rs index 0c976ed84e6ba..76a484e2a5c2e 100644 --- a/library/std/src/sys/pal/windows/handle/tests.rs +++ b/library/std/src/sys/pal/windows/handle/tests.rs @@ -1,11 +1,11 @@ -use crate::sys::pipe::{Pipes, anon_pipe}; +use crate::sys::pipe::{Pipes, anon_pipe_relay}; use crate::{thread, time}; /// Test the synchronous fallback for overlapped I/O. #[test] fn overlapped_handle_fallback() { // Create some pipes. `ours` will be asynchronous. - let Pipes { ours, theirs } = anon_pipe(true, false).unwrap(); + let Pipes { ours, theirs } = anon_pipe_relay(true, false).unwrap(); let async_readable = ours.into_handle(); let sync_writeable = theirs.into_handle(); diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index a8f6617c9dc8f..6178e3fe9ce55 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -37,6 +37,24 @@ pub struct Pipes { pub theirs: AnonPipe, } +pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { + let mut read_pipe = c::INVALID_HANDLE_VALUE; + let mut write_pipe = c::INVALID_HANDLE_VALUE; + + let ret = unsafe { c::CreatePipe(&mut read_pipe, &mut write_pipe, ptr::null_mut(), 0) }; + + if ret == 0 { + Err(io::Error::last_os_error()) + } else { + unsafe { + Ok(( + AnonPipe::from_inner(Handle::from_raw_handle(read_pipe)), + AnonPipe::from_inner(Handle::from_raw_handle(write_pipe)), + )) + } + } +} + /// Although this looks similar to `anon_pipe` in the Unix module it's actually /// subtly different. Here we'll return two pipes in the `Pipes` return value, /// but one is intended for "us" where as the other is intended for "someone @@ -56,7 +74,7 @@ pub struct Pipes { /// mode. This means that technically speaking it should only ever be used /// with `OVERLAPPED` instances, but also works out ok if it's only ever used /// once at a time (which we do indeed guarantee). -pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Result { +pub fn anon_pipe_relay(ours_readable: bool, their_handle_inheritable: bool) -> io::Result { // A 64kb pipe capacity is the same as a typical Linux default. const PIPE_BUFFER_CAPACITY: u32 = 64 * 1024; @@ -182,7 +200,7 @@ pub fn spawn_pipe_relay( let source = source.try_clone()?; // create a new pair of anon pipes. - let Pipes { theirs, ours } = anon_pipe(ours_readable, their_handle_inheritable)?; + let Pipes { theirs, ours } = anon_pipe_relay(ours_readable, their_handle_inheritable)?; // Spawn a thread that passes messages from one pipe to the other. // Any errors will simply cause the thread to exit. diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index 9332c9b49ffb9..caf91e27d775c 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -584,7 +584,7 @@ impl Stdio { Stdio::MakePipe => { let ours_readable = stdio_id != c::STD_INPUT_HANDLE; - let pipes = pipe::anon_pipe(ours_readable, true)?; + let pipes = pipe::anon_pipe_relay(ours_readable, true)?; *pipe = Some(pipes.ours); Ok(pipes.theirs.into_handle()) } @@ -622,6 +622,18 @@ impl From for Stdio { } } +impl From for Stdio { + fn from(pipe: io::PipeReader) -> Stdio { + pipe.into_inner().into() + } +} + +impl From for Stdio { + fn from(pipe: io::PipeWriter) -> Stdio { + pipe.into_inner().into() + } +} + impl From for Stdio { fn from(file: File) -> Stdio { Stdio::Handle(file.into_inner()) diff --git a/library/std/tests/pipe_subprocess.rs b/library/std/tests/pipe_subprocess.rs index 00d99a578d580..c51a4459e718b 100644 --- a/library/std/tests/pipe_subprocess.rs +++ b/library/std/tests/pipe_subprocess.rs @@ -1,5 +1,3 @@ -#![feature(anonymous_pipe)] - fn main() { #[cfg(all(not(miri), any(unix, windows), not(target_os = "emscripten")))] { diff --git a/src/tools/miri/tests/pass/shims/pipe.rs b/src/tools/miri/tests/pass/shims/pipe.rs index 1be29886d2d32..c47feb8774ad1 100644 --- a/src/tools/miri/tests/pass/shims/pipe.rs +++ b/src/tools/miri/tests/pass/shims/pipe.rs @@ -1,7 +1,5 @@ //@ignore-target: windows -#![feature(anonymous_pipe)] - use std::io::{Read, Write, pipe}; fn main() {