1- //! Module for anonymous pipe
1+ //! A cross-platform anonymous pipe.
22//!
3- //! ```
4- //! #![feature(anonymous_pipe)]
3+ //! This module provides support for anonymous OS pipes, like [pipe] on Linux or [CreatePipe] on
4+ //! Windows, which can be used as synchronous communication channels between related processes.
5+ //!
6+ //! # Behavior
7+ //!
8+ //! A pipe can be thought of as a bounded, interprocess [`mpsc`](crate::sync::mpsc), provided by
9+ //! the OS, with a platform-dependent capacity. 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 through copying the underlying file descriptor, but only one
16+ //! process will consume the data in the pipe at any given time.
17+ //!
18+ //! # Capacity
19+ //!
20+ //! Pipe capacity is platform-dependent. To quote the Linux [man page]:
21+ //!
22+ //! > Different implementations have different limits for the pipe capacity. Applications should
23+ //! > not rely on a particular capacity: an application should be designed so that a reading process
24+ //! > consumes data as soon as it is available, so that a writing process does not remain blocked.
525//!
26+ //! # Examples
27+ //!
28+ //! ```no_run
29+ //! #![feature(anonymous_pipe)]
630//! # #[cfg(miri)] fn main() {}
731//! # #[cfg(not(miri))]
32+ //! # use std::process::Command;
33+ //! # use std::io::{Read, Write};
834//! # fn main() -> std::io::Result<()> {
9- //! let (reader, writer) = std::pipe::pipe()?;
35+ //! let (ping_rx, mut ping_tx) = std::pipe::pipe()?;
36+ //! let (mut pong_rx, pong_tx) = std::pipe::pipe()?;
37+ //!
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 server's reader.
42+ //! drop(ping_tx);
43+ //!
44+ //! let mut buf = String::new();
45+ //! // Block until server's writer is closed.
46+ //! pong_rx.read_to_string(&mut buf)?;
47+ //! assert_eq!(&buf, "hello");
48+ //!
49+ //! echo_server.wait()?;
1050//! # Ok(())
1151//! # }
1252//! ```
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
1456use crate :: io;
1557use crate :: sys:: anonymous_pipe:: { AnonPipe , pipe as pipe_inner} ;
1658
1759/// Create anonymous pipe that is close-on-exec and blocking.
60+ ///
61+ /// # Examples
62+ ///
63+ /// See the [module-level](crate::pipe) documentation for examples.
1864#[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
1965#[ inline]
2066pub fn pipe ( ) -> io:: Result < ( PipeReader , PipeWriter ) > {
@@ -33,6 +79,46 @@ pub struct PipeWriter(pub(crate) AnonPipe);
3379
3480impl PipeReader {
3581 /// 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+ /// # use std::fs;
90+ /// # use std::io::Write;
91+ /// # use std::process::{Command, Stdio};
92+ /// # fn main() -> std::io::Result<()> {
93+ /// const NUM_PROC: u8 = 5;
94+ /// const OUTPUT: &str = "output.txt";
95+ ///
96+ /// let mut jobs = vec![];
97+ /// let (reader, mut writer) = std::pipe::pipe()?;
98+ ///
99+ /// for _ in 0..NUM_PROC {
100+ /// writer.write_all(b"x")?;
101+ /// jobs.push(
102+ /// Command::new("tee")
103+ /// .args(["-a", OUTPUT])
104+ /// .stdin(reader.try_clone()?)
105+ /// .stdout(Stdio::null())
106+ /// .spawn()?,
107+ /// );
108+ /// }
109+ ///
110+ /// drop(writer);
111+ ///
112+ /// for mut job in jobs {
113+ /// job.wait()?;
114+ /// }
115+ ///
116+ /// let xs = fs::read_to_string(OUTPUT)?;
117+ /// fs::remove_file(OUTPUT)?;
118+ /// assert_eq!(xs, "x".repeat(NUM_PROC.into()));
119+ /// # Ok(())
120+ /// # }
121+ /// ```
36122 #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
37123 pub fn try_clone ( & self ) -> io:: Result < Self > {
38124 self . 0 . try_clone ( ) . map ( Self )
@@ -41,6 +127,37 @@ impl PipeReader {
41127
42128impl PipeWriter {
43129 /// Create a new [`PipeWriter`] instance that shares the same underlying file description.
130+ ///
131+ /// # Examples
132+ ///
133+ /// ```no_run
134+ /// #![feature(anonymous_pipe)]
135+ /// # #[cfg(miri)] fn main() {}
136+ /// # #[cfg(not(miri))]
137+ /// # use std::process::Command;
138+ /// # use std::io::Read;
139+ /// # fn main() -> std::io::Result<()> {
140+ /// let (mut reader, writer) = std::pipe::pipe()?;
141+ ///
142+ /// let mut peer = Command::new("python")
143+ /// .args([
144+ /// "-c",
145+ /// "from sys import stdout, stderr\n\
146+ /// stdout.write('foo')\n\
147+ /// stderr.write('bar')"
148+ /// ])
149+ /// .stdout(writer.try_clone()?)
150+ /// .stderr(writer)
151+ /// .spawn()?;
152+ ///
153+ /// let mut msg = String::new();
154+ /// reader.read_to_string(&mut msg)?;
155+ /// assert_eq!(&msg, "foobar");
156+ ///
157+ /// peer.wait()?;
158+ /// # Ok(())
159+ /// # }
160+ /// ```
44161 #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
45162 pub fn try_clone ( & self ) -> io:: Result < Self > {
46163 self . 0 . try_clone ( ) . map ( Self )
0 commit comments