Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 826902b

Browse files
committedJul 14, 2024·
Auto merge of rust-lang#127153 - NobodyXu:pipe, r=jhpratt
Initial implementation of anonymous_pipe API ACP completed in rust-lang/libs-team#375 Tracking issue: rust-lang#127154
2 parents 88fa119 + 6d2240d commit 826902b

File tree

10 files changed

+425
-3
lines changed

10 files changed

+425
-3
lines changed
 

‎library/std/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,9 @@ pub use core::{
684684
module_path, option_env, stringify, trace_macros,
685685
};
686686

687+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
688+
pub use crate::sys::anonymous_pipe as pipe;
689+
687690
#[unstable(
688691
feature = "concat_bytes",
689692
issue = "87555",
+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
//! Module for anonymous pipe
2+
//!
3+
//! ```
4+
//! #![feature(anonymous_pipe)]
5+
//! # fn main() -> std::io::Result<()> {
6+
//! let (reader, writer) = std::pipe::pipe()?;
7+
//! # Ok(())
8+
//! # }
9+
//! ```
10+
11+
use crate::{io, sys::pipe::AnonPipe};
12+
13+
/// Create anonymous pipe that is close-on-exec and blocking.
14+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
15+
#[inline]
16+
pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
17+
cfg_if::cfg_if! {
18+
if #[cfg(unix)] {
19+
unix::pipe()
20+
} else if #[cfg(windows)] {
21+
windows::pipe()
22+
} else {
23+
Err(io::Error::UNSUPPORTED_PLATFORM)
24+
}
25+
}
26+
}
27+
28+
/// Read end of the anonymous pipe.
29+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
30+
#[derive(Debug)]
31+
pub struct PipeReader(AnonPipe);
32+
33+
/// Write end of the anonymous pipe.
34+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
35+
#[derive(Debug)]
36+
pub struct PipeWriter(AnonPipe);
37+
38+
impl PipeReader {
39+
/// Create a new [`PipeReader`] instance that shares the same underlying file description.
40+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
41+
pub fn try_clone(&self) -> io::Result<Self> {
42+
self.0.try_clone().map(Self)
43+
}
44+
}
45+
46+
impl PipeWriter {
47+
/// Create a new [`PipeWriter`] instance that shares the same underlying file description.
48+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
49+
pub fn try_clone(&self) -> io::Result<Self> {
50+
self.0.try_clone().map(Self)
51+
}
52+
}
53+
54+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
55+
impl io::Read for &PipeReader {
56+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
57+
self.0.read(buf)
58+
}
59+
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
60+
self.0.read_vectored(bufs)
61+
}
62+
#[inline]
63+
fn is_read_vectored(&self) -> bool {
64+
self.0.is_read_vectored()
65+
}
66+
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
67+
self.0.read_to_end(buf)
68+
}
69+
fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
70+
self.0.read_buf(buf)
71+
}
72+
}
73+
74+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
75+
impl io::Read for PipeReader {
76+
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
77+
self.0.read(buf)
78+
}
79+
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
80+
self.0.read_vectored(bufs)
81+
}
82+
#[inline]
83+
fn is_read_vectored(&self) -> bool {
84+
self.0.is_read_vectored()
85+
}
86+
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
87+
self.0.read_to_end(buf)
88+
}
89+
fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
90+
self.0.read_buf(buf)
91+
}
92+
}
93+
94+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
95+
impl io::Write for &PipeWriter {
96+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
97+
self.0.write(buf)
98+
}
99+
#[inline]
100+
fn flush(&mut self) -> io::Result<()> {
101+
Ok(())
102+
}
103+
104+
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
105+
self.0.write_vectored(bufs)
106+
}
107+
108+
#[inline]
109+
fn is_write_vectored(&self) -> bool {
110+
self.0.is_write_vectored()
111+
}
112+
}
113+
114+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
115+
impl io::Write for PipeWriter {
116+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
117+
self.0.write(buf)
118+
}
119+
#[inline]
120+
fn flush(&mut self) -> io::Result<()> {
121+
Ok(())
122+
}
123+
124+
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
125+
self.0.write_vectored(bufs)
126+
}
127+
128+
#[inline]
129+
fn is_write_vectored(&self) -> bool {
130+
self.0.is_write_vectored()
131+
}
132+
}
133+
134+
#[cfg(unix)]
135+
mod unix;
136+
137+
#[cfg(windows)]
138+
mod windows;
139+
140+
#[cfg(all(test, not(miri)))]
141+
mod tests;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use super::*;
2+
use crate::io::{Read, Write};
3+
4+
#[test]
5+
fn pipe_creation_and_rw() {
6+
let (mut rx, mut tx) = pipe().unwrap();
7+
tx.write_all(b"12345").unwrap();
8+
drop(tx);
9+
10+
let mut s = String::new();
11+
rx.read_to_string(&mut s).unwrap();
12+
assert_eq!(s, "12345");
13+
}
14+
15+
#[test]
16+
fn pipe_try_clone_and_rw() {
17+
let (mut rx, mut tx) = pipe().unwrap();
18+
tx.try_clone().unwrap().write_all(b"12").unwrap();
19+
tx.write_all(b"345").unwrap();
20+
drop(tx);
21+
22+
let mut s = String::new();
23+
rx.try_clone().unwrap().take(3).read_to_string(&mut s).unwrap();
24+
assert_eq!(s, "123");
25+
26+
s.clear();
27+
rx.read_to_string(&mut s).unwrap();
28+
assert_eq!(s, "45");
29+
}
+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
use super::*;
2+
3+
use crate::{
4+
os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd},
5+
process::Stdio,
6+
sys::{
7+
fd::FileDesc,
8+
pipe::{anon_pipe, AnonPipe},
9+
},
10+
sys_common::{FromInner, IntoInner},
11+
};
12+
13+
#[inline]
14+
pub(super) fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
15+
anon_pipe().map(|(rx, tx)| (PipeReader(rx), PipeWriter(tx)))
16+
}
17+
18+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
19+
impl AsFd for PipeReader {
20+
fn as_fd(&self) -> BorrowedFd<'_> {
21+
self.0.as_fd()
22+
}
23+
}
24+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
25+
impl AsRawFd for PipeReader {
26+
fn as_raw_fd(&self) -> RawFd {
27+
self.0.as_raw_fd()
28+
}
29+
}
30+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
31+
impl From<PipeReader> for OwnedFd {
32+
fn from(pipe: PipeReader) -> Self {
33+
FileDesc::into_inner(AnonPipe::into_inner(pipe.0))
34+
}
35+
}
36+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
37+
impl FromRawFd for PipeReader {
38+
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
39+
Self(AnonPipe::from_raw_fd(raw_fd))
40+
}
41+
}
42+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
43+
impl IntoRawFd for PipeReader {
44+
fn into_raw_fd(self) -> RawFd {
45+
self.0.into_raw_fd()
46+
}
47+
}
48+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
49+
impl From<PipeReader> for Stdio {
50+
fn from(pipe: PipeReader) -> Self {
51+
Self::from(OwnedFd::from(pipe))
52+
}
53+
}
54+
55+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
56+
impl AsFd for PipeWriter {
57+
fn as_fd(&self) -> BorrowedFd<'_> {
58+
self.0.as_fd()
59+
}
60+
}
61+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
62+
impl AsRawFd for PipeWriter {
63+
fn as_raw_fd(&self) -> RawFd {
64+
self.0.as_raw_fd()
65+
}
66+
}
67+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
68+
impl From<PipeWriter> for OwnedFd {
69+
fn from(pipe: PipeWriter) -> Self {
70+
FileDesc::into_inner(AnonPipe::into_inner(pipe.0))
71+
}
72+
}
73+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
74+
impl FromRawFd for PipeWriter {
75+
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
76+
Self(AnonPipe::from_raw_fd(raw_fd))
77+
}
78+
}
79+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
80+
impl IntoRawFd for PipeWriter {
81+
fn into_raw_fd(self) -> RawFd {
82+
self.0.into_raw_fd()
83+
}
84+
}
85+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
86+
impl From<PipeWriter> for Stdio {
87+
fn from(pipe: PipeWriter) -> Self {
88+
Self::from(OwnedFd::from(pipe))
89+
}
90+
}
91+
92+
fn convert_to_pipe(owned_fd: OwnedFd) -> AnonPipe {
93+
AnonPipe::from_inner(FileDesc::from_inner(OwnedFd::from(owned_fd)))
94+
}
95+
96+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
97+
impl From<OwnedFd> for PipeReader {
98+
fn from(owned_fd: OwnedFd) -> Self {
99+
Self(convert_to_pipe(owned_fd))
100+
}
101+
}
102+
103+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
104+
impl From<OwnedFd> for PipeWriter {
105+
fn from(owned_fd: OwnedFd) -> Self {
106+
Self(convert_to_pipe(owned_fd))
107+
}
108+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use super::*;
2+
3+
use crate::{
4+
os::windows::io::{
5+
AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
6+
},
7+
process::Stdio,
8+
sys::{
9+
handle::Handle,
10+
pipe::{anon_pipe, AnonPipe, Pipes},
11+
},
12+
sys_common::{FromInner, IntoInner},
13+
};
14+
15+
#[inline]
16+
pub(super) fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
17+
anon_pipe(true, false).map(|Pipes { ours, theirs }| (PipeReader(ours), PipeWriter(theirs)))
18+
}
19+
20+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
21+
impl AsHandle for PipeReader {
22+
fn as_handle(&self) -> BorrowedHandle<'_> {
23+
self.0.handle().as_handle()
24+
}
25+
}
26+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
27+
impl AsRawHandle for PipeReader {
28+
fn as_raw_handle(&self) -> RawHandle {
29+
self.0.handle().as_raw_handle()
30+
}
31+
}
32+
33+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
34+
impl FromRawHandle for PipeReader {
35+
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
36+
Self(AnonPipe::from_inner(Handle::from_raw_handle(raw_handle)))
37+
}
38+
}
39+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
40+
impl IntoRawHandle for PipeReader {
41+
fn into_raw_handle(self) -> RawHandle {
42+
self.0.into_handle().into_raw_handle()
43+
}
44+
}
45+
46+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
47+
impl From<PipeReader> for OwnedHandle {
48+
fn from(pipe: PipeReader) -> Self {
49+
Handle::into_inner(AnonPipe::into_inner(pipe.0))
50+
}
51+
}
52+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
53+
impl From<PipeReader> for Stdio {
54+
fn from(pipe: PipeReader) -> Self {
55+
Self::from(OwnedHandle::from(pipe))
56+
}
57+
}
58+
59+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
60+
impl AsHandle for PipeWriter {
61+
fn as_handle(&self) -> BorrowedHandle<'_> {
62+
self.0.handle().as_handle()
63+
}
64+
}
65+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
66+
impl AsRawHandle for PipeWriter {
67+
fn as_raw_handle(&self) -> RawHandle {
68+
self.0.handle().as_raw_handle()
69+
}
70+
}
71+
72+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
73+
impl FromRawHandle for PipeWriter {
74+
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
75+
Self(AnonPipe::from_inner(Handle::from_raw_handle(raw_handle)))
76+
}
77+
}
78+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
79+
impl IntoRawHandle for PipeWriter {
80+
fn into_raw_handle(self) -> RawHandle {
81+
self.0.into_handle().into_raw_handle()
82+
}
83+
}
84+
85+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
86+
impl From<PipeWriter> for OwnedHandle {
87+
fn from(pipe: PipeWriter) -> Self {
88+
Handle::into_inner(AnonPipe::into_inner(pipe.0))
89+
}
90+
}
91+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
92+
impl From<PipeWriter> for Stdio {
93+
fn from(pipe: PipeWriter) -> Self {
94+
Self::from(OwnedHandle::from(pipe))
95+
}
96+
}
97+
98+
fn convert_to_pipe(owned_handle: OwnedHandle) -> AnonPipe {
99+
AnonPipe::from_inner(Handle::from_inner(owned_handle))
100+
}
101+
102+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
103+
impl From<OwnedHandle> for PipeReader {
104+
fn from(owned_handle: OwnedHandle) -> Self {
105+
Self(convert_to_pipe(owned_handle))
106+
}
107+
}
108+
109+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
110+
impl From<OwnedHandle> for PipeWriter {
111+
fn from(owned_handle: OwnedHandle) -> Self {
112+
Self(convert_to_pipe(owned_handle))
113+
}
114+
}

‎library/std/src/sys/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ mod pal;
55

66
mod personality;
77

8+
#[unstable(feature = "anonymous_pipe", issue = "127154")]
9+
pub mod anonymous_pipe;
810
pub mod backtrace;
911
pub mod cmath;
1012
pub mod exit_guard;

‎library/std/src/sys/pal/unix/pipe.rs

+9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::sys_common::{FromInner, IntoInner};
99
// Anonymous pipes
1010
////////////////////////////////////////////////////////////////////////////////
1111

12+
#[derive(Debug)]
1213
pub struct AnonPipe(FileDesc);
1314

1415
pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
@@ -46,6 +47,10 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
4647
}
4748

4849
impl AnonPipe {
50+
pub fn try_clone(&self) -> io::Result<Self> {
51+
self.0.duplicate().map(Self)
52+
}
53+
4954
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
5055
self.0.read(buf)
5156
}
@@ -79,6 +84,10 @@ impl AnonPipe {
7984
pub fn is_write_vectored(&self) -> bool {
8085
self.0.is_write_vectored()
8186
}
87+
88+
pub fn as_file_desc(&self) -> &FileDesc {
89+
&self.0
90+
}
8291
}
8392

8493
impl IntoInner<FileDesc> for AnonPipe {

‎library/std/src/sys/pal/unsupported/pipe.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
1-
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
1+
use crate::{
2+
fmt,
3+
io::{self, BorrowedCursor, IoSlice, IoSliceMut},
4+
};
25

36
pub struct AnonPipe(!);
47

8+
impl fmt::Debug for AnonPipe {
9+
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
10+
self.0
11+
}
12+
}
13+
514
impl AnonPipe {
15+
pub fn try_clone(&self) -> io::Result<Self> {
16+
self.0
17+
}
18+
619
pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
720
self.0
821
}

‎library/std/src/sys/pal/windows/handle.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
1717
/// An owned container for `HANDLE` object, closing them on Drop.
1818
///
1919
/// All methods are inherited through a `Deref` impl to `RawHandle`
20+
#[derive(Debug)]
2021
pub struct Handle(OwnedHandle);
2122

2223
impl Handle {

‎library/std/src/sys/pal/windows/pipe.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::sys_common::{FromInner, IntoInner};
1919
// Anonymous pipes
2020
////////////////////////////////////////////////////////////////////////////////
2121

22+
#[derive(Debug)]
2223
pub struct AnonPipe {
2324
inner: Handle,
2425
}
@@ -182,7 +183,7 @@ pub fn spawn_pipe_relay(
182183
their_handle_inheritable: bool,
183184
) -> io::Result<AnonPipe> {
184185
// We need this handle to live for the lifetime of the thread spawned below.
185-
let source = source.duplicate()?;
186+
let source = source.try_clone()?;
186187

187188
// create a new pair of anon pipes.
188189
let Pipes { theirs, ours } = anon_pipe(ours_readable, their_handle_inheritable)?;
@@ -238,7 +239,8 @@ impl AnonPipe {
238239
pub fn into_handle(self) -> Handle {
239240
self.inner
240241
}
241-
fn duplicate(&self) -> io::Result<Self> {
242+
243+
pub fn try_clone(&self) -> io::Result<Self> {
242244
self.inner.duplicate(0, false, c::DUPLICATE_SAME_ACCESS).map(|inner| AnonPipe { inner })
243245
}
244246

0 commit comments

Comments
 (0)
Please sign in to comment.