1
- //! Module for anonymous pipe
1
+ //! A cross-platform anonymous pipe.
2
2
//!
3
- //! ```
4
- //! #![feature(anonymous_pipe)]
3
+ //! This module provides support for anonymous OS pipes, like [pipe] on Linux or [CreatePipe] on
4
+ //! Windows.
5
+ //!
6
+ //! # Behavior
7
+ //!
8
+ //! A pipe is a synchronous, unidirectional data channel between two or more processes, like an
9
+ //! interprocess [`mpsc`](crate::sync::mpsc) provided by the OS. In particular:
10
+ //!
11
+ //! * A read on a [`PipeReader`] blocks until the pipe is non-empty.
12
+ //! * A write on a [`PipeWriter`] blocks when the pipe is full.
13
+ //! * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`]
14
+ //! returns EOF.
15
+ //! * [`PipeReader`] can be shared, but only one process will consume the data in the pipe.
16
+ //!
17
+ //! # Capacity
18
+ //!
19
+ //! Pipe capacity is platform dependent. To quote the Linux [man page]:
20
+ //!
21
+ //! > Different implementations have different limits for the pipe capacity. Applications should
22
+ //! > not rely on a particular capacity: an application should be designed so that a reading process
23
+ //! > consumes data as soon as it is available, so that a writing process does not remain blocked.
5
24
//!
25
+ //! # Examples
26
+ //!
27
+ //! ```no_run
28
+ //! #![feature(anonymous_pipe)]
6
29
//! # #[cfg(miri)] fn main() {}
7
30
//! # #[cfg(not(miri))]
8
31
//! # fn main() -> std::io::Result<()> {
9
- //! let (reader, writer) = std::pipe::pipe()?;
32
+ //! # use std::process::Command;
33
+ //! # use std::io::{Read, Write};
34
+ //! let (ping_rx, mut ping_tx) = std::pipe::pipe()?;
35
+ //! let (mut pong_rx, pong_tx) = std::pipe::pipe()?;
36
+ //!
37
+ //! // Spawn a process that echoes its input.
38
+ //! let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?;
39
+ //!
40
+ //! ping_tx.write_all(b"hello")?;
41
+ //! // Close to unblock echo_server's reader.
42
+ //! drop(ping_tx);
43
+ //!
44
+ //! let mut buf = String::new();
45
+ //! // Block until echo_server's writer is closed.
46
+ //! pong_rx.read_to_string(&mut buf)?;
47
+ //! assert_eq!(&buf, "hello");
48
+ //!
49
+ //! echo_server.wait()?;
10
50
//! # Ok(())
11
51
//! # }
12
52
//! ```
13
-
53
+ //! [pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html
54
+ //! [CreatePipe]: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe
55
+ //! [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html
14
56
use crate :: io;
15
57
use crate :: sys:: anonymous_pipe:: { AnonPipe , pipe as pipe_inner} ;
16
58
17
59
/// Create anonymous pipe that is close-on-exec and blocking.
60
+ ///
61
+ /// # Examples
62
+ ///
63
+ /// See the [module-level](crate::pipe) documentation for examples.
18
64
#[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
19
65
#[ inline]
20
66
pub fn pipe ( ) -> io:: Result < ( PipeReader , PipeWriter ) > {
@@ -33,6 +79,58 @@ pub struct PipeWriter(pub(crate) AnonPipe);
33
79
34
80
impl PipeReader {
35
81
/// Create a new [`PipeReader`] instance that shares the same underlying file description.
82
+ ///
83
+ /// # Examples
84
+ ///
85
+ /// ```no_run
86
+ /// #![feature(anonymous_pipe)]
87
+ /// # #[cfg(miri)] fn main() {}
88
+ /// # #[cfg(not(miri))]
89
+ /// # fn main() -> std::io::Result<()> {
90
+ /// # use std::fs;
91
+ /// # use std::io::Write;
92
+ /// # use std::process::Command;
93
+ /// const NUM_SLOT: u8 = 2;
94
+ /// const NUM_PROC: u8 = 5;
95
+ /// const OUTPUT: &str = "work.txt";
96
+ ///
97
+ /// let mut jobs = vec![];
98
+ /// let (reader, mut writer) = std::pipe::pipe()?;
99
+ ///
100
+ /// // Write NUM_SLOT characters the the pipe.
101
+ /// writer.write_all(&[b'|'; NUM_SLOT as usize])?;
102
+ ///
103
+ /// // Spawn several processes that read a character from the pipe, do some work, then
104
+ /// // write back to the pipe. When the pipe is empty, the processes block, so only
105
+ /// // NUM_SLOT processes can be working at any given time.
106
+ /// for _ in 0..NUM_PROC {
107
+ /// jobs.push(
108
+ /// Command::new("bash")
109
+ /// .args(["-c",
110
+ /// &format!(
111
+ /// "read -n 1\n\
112
+ /// echo -n 'x' >> '{OUTPUT}'\n\
113
+ /// echo -n '|'",
114
+ /// ),
115
+ /// ])
116
+ /// .stdin(reader.try_clone()?)
117
+ /// .stdout(writer.try_clone()?)
118
+ /// .spawn()?,
119
+ /// );
120
+ /// }
121
+ ///
122
+ /// // Wait for all jobs to finish.
123
+ /// for mut job in jobs {
124
+ /// job.wait()?;
125
+ /// }
126
+ ///
127
+ /// // Check our work and clean up.
128
+ /// let xs = fs::read_to_string(OUTPUT)?;
129
+ /// fs::remove_file(OUTPUT)?;
130
+ /// assert_eq!(xs, "x".repeat(NUM_PROC.into()));
131
+ /// # Ok(())
132
+ /// # }
133
+ /// ```
36
134
#[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
37
135
pub fn try_clone ( & self ) -> io:: Result < Self > {
38
136
self . 0 . try_clone ( ) . map ( Self )
@@ -41,6 +139,38 @@ impl PipeReader {
41
139
42
140
impl PipeWriter {
43
141
/// Create a new [`PipeWriter`] instance that shares the same underlying file description.
142
+ ///
143
+ /// # Examples
144
+ ///
145
+ /// ```no_run
146
+ /// #![feature(anonymous_pipe)]
147
+ /// # #[cfg(miri)] fn main() {}
148
+ /// # #[cfg(not(miri))]
149
+ /// # fn main() -> std::io::Result<()> {
150
+ /// # use std::process::Command;
151
+ /// # use std::io::Read;
152
+ /// let (mut reader, writer) = std::pipe::pipe()?;
153
+ ///
154
+ /// // Spawn a process that writes to stdout and stderr.
155
+ /// let mut peer = Command::new("bash")
156
+ /// .args([
157
+ /// "-c",
158
+ /// "echo -n foo\n\
159
+ /// echo -n bar >&2"
160
+ /// ])
161
+ /// .stdout(writer.try_clone()?)
162
+ /// .stderr(writer)
163
+ /// .spawn()?;
164
+ ///
165
+ /// // Read and check the result.
166
+ /// let mut msg = String::new();
167
+ /// reader.read_to_string(&mut msg)?;
168
+ /// assert_eq!(&msg, "foobar");
169
+ ///
170
+ /// peer.wait()?;
171
+ /// # Ok(())
172
+ /// # }
173
+ /// ```
44
174
#[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
45
175
pub fn try_clone ( & self ) -> io:: Result < Self > {
46
176
self . 0 . try_clone ( ) . map ( Self )
0 commit comments