@@ -310,6 +310,8 @@ pub use self::error::RawOsError;
310310pub use self :: error:: SimpleMessage ;
311311#[ unstable( feature = "io_const_error" , issue = "133448" ) ]
312312pub use self :: error:: const_error;
313+ #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
314+ pub use self :: pipe:: { PipeReader , PipeWriter , pipe} ;
313315#[ stable( feature = "is_terminal" , since = "1.70.0" ) ]
314316pub use self :: stdio:: IsTerminal ;
315317pub ( crate ) use self :: stdio:: attempt_print_to_stderr;
@@ -330,14 +332,14 @@ pub use self::{
330332} ;
331333use crate :: mem:: take;
332334use crate :: ops:: { Deref , DerefMut } ;
333- use crate :: sys:: anonymous_pipe:: { AnonPipe , pipe as pipe_inner} ;
334335use crate :: { cmp, fmt, slice, str, sys} ;
335336
336337mod buffered;
337338pub ( crate ) mod copy;
338339mod cursor;
339340mod error;
340341mod impls;
342+ mod pipe;
341343pub mod prelude;
342344mod stdio;
343345mod util;
@@ -3251,257 +3253,3 @@ impl<B: BufRead> Iterator for Lines<B> {
32513253 }
32523254 }
32533255}
3254-
3255- /// Create an anonymous pipe that is close-on-exec and blocking.
3256- ///
3257- /// # Behavior
3258- ///
3259- /// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is
3260- /// typically used to communicate between two or more separate processes, as there are better,
3261- /// faster ways to communicate within a single process.
3262- ///
3263- /// In particular:
3264- ///
3265- /// * A read on a [`PipeReader`] blocks until the pipe is non-empty.
3266- /// * A write on a [`PipeWriter`] blocks when the pipe is full.
3267- /// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`]
3268- /// returns EOF.
3269- /// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but
3270- /// writes (above a target-specific threshold) may have their data interleaved.
3271- /// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any
3272- /// given byte will only get consumed by one reader. There are no guarantees about data
3273- /// interleaving.
3274- /// * Portable applications cannot assume any atomicity of messages larger than a single byte.
3275- ///
3276- /// # Capacity
3277- ///
3278- /// Pipe capacity is platform dependent. To quote the Linux [man page]:
3279- ///
3280- /// > Different implementations have different limits for the pipe capacity. Applications should
3281- /// > not rely on a particular capacity: an application should be designed so that a reading process
3282- /// > consumes data as soon as it is available, so that a writing process does not remain blocked.
3283- ///
3284- /// # Examples
3285- ///
3286- /// ```no_run
3287- /// #![feature(anonymous_pipe)]
3288- /// # #[cfg(miri)] fn main() {}
3289- /// # #[cfg(not(miri))]
3290- /// # fn main() -> std::io::Result<()> {
3291- /// # use std::process::Command;
3292- /// # use std::io::{Read, Write};
3293- /// let (ping_rx, mut ping_tx) = std::io::pipe()?;
3294- /// let (mut pong_rx, pong_tx) = std::io::pipe()?;
3295- ///
3296- /// // Spawn a process that echoes its input.
3297- /// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?;
3298- ///
3299- /// ping_tx.write_all(b"hello")?;
3300- /// // Close to unblock echo_server's reader.
3301- /// drop(ping_tx);
3302- ///
3303- /// let mut buf = String::new();
3304- /// // Block until echo_server's writer is closed.
3305- /// pong_rx.read_to_string(&mut buf)?;
3306- /// assert_eq!(&buf, "hello");
3307- ///
3308- /// echo_server.wait()?;
3309- /// # Ok(())
3310- /// # }
3311- /// ```
3312- /// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html
3313- #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
3314- #[ inline]
3315- pub fn pipe ( ) -> Result < ( PipeReader , PipeWriter ) > {
3316- pipe_inner ( ) . map ( |( reader, writer) | ( PipeReader ( reader) , PipeWriter ( writer) ) )
3317- }
3318-
3319- /// Read end of an anonymous pipe.
3320- #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
3321- #[ derive( Debug ) ]
3322- pub struct PipeReader ( pub ( crate ) AnonPipe ) ;
3323-
3324- /// Write end of an anonymous pipe.
3325- #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
3326- #[ derive( Debug ) ]
3327- pub struct PipeWriter ( pub ( crate ) AnonPipe ) ;
3328-
3329- impl PipeReader {
3330- /// Create a new [`PipeReader`] instance that shares the same underlying file description.
3331- ///
3332- /// # Examples
3333- ///
3334- /// ```no_run
3335- /// #![feature(anonymous_pipe)]
3336- /// # #[cfg(miri)] fn main() {}
3337- /// # #[cfg(not(miri))]
3338- /// # fn main() -> std::io::Result<()> {
3339- /// # use std::fs;
3340- /// # use std::io::Write;
3341- /// # use std::process::Command;
3342- /// const NUM_SLOT: u8 = 2;
3343- /// const NUM_PROC: u8 = 5;
3344- /// const OUTPUT: &str = "work.txt";
3345- ///
3346- /// let mut jobs = vec![];
3347- /// let (reader, mut writer) = std::io::pipe()?;
3348- ///
3349- /// // Write NUM_SLOT characters the pipe.
3350- /// writer.write_all(&[b'|'; NUM_SLOT as usize])?;
3351- ///
3352- /// // Spawn several processes that read a character from the pipe, do some work, then
3353- /// // write back to the pipe. When the pipe is empty, the processes block, so only
3354- /// // NUM_SLOT processes can be working at any given time.
3355- /// for _ in 0..NUM_PROC {
3356- /// jobs.push(
3357- /// Command::new("bash")
3358- /// .args(["-c",
3359- /// &format!(
3360- /// "read -n 1\n\
3361- /// echo -n 'x' >> '{OUTPUT}'\n\
3362- /// echo -n '|'",
3363- /// ),
3364- /// ])
3365- /// .stdin(reader.try_clone()?)
3366- /// .stdout(writer.try_clone()?)
3367- /// .spawn()?,
3368- /// );
3369- /// }
3370- ///
3371- /// // Wait for all jobs to finish.
3372- /// for mut job in jobs {
3373- /// job.wait()?;
3374- /// }
3375- ///
3376- /// // Check our work and clean up.
3377- /// let xs = fs::read_to_string(OUTPUT)?;
3378- /// fs::remove_file(OUTPUT)?;
3379- /// assert_eq!(xs, "x".repeat(NUM_PROC.into()));
3380- /// # Ok(())
3381- /// # }
3382- /// ```
3383- #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
3384- pub fn try_clone ( & self ) -> Result < Self > {
3385- self . 0 . try_clone ( ) . map ( Self )
3386- }
3387- }
3388-
3389- impl PipeWriter {
3390- /// Create a new [`PipeWriter`] instance that shares the same underlying file description.
3391- ///
3392- /// # Examples
3393- ///
3394- /// ```no_run
3395- /// #![feature(anonymous_pipe)]
3396- /// # #[cfg(miri)] fn main() {}
3397- /// # #[cfg(not(miri))]
3398- /// # fn main() -> std::io::Result<()> {
3399- /// # use std::process::Command;
3400- /// # use std::io::Read;
3401- /// let (mut reader, writer) = std::io::pipe()?;
3402- ///
3403- /// // Spawn a process that writes to stdout and stderr.
3404- /// let mut peer = Command::new("bash")
3405- /// .args([
3406- /// "-c",
3407- /// "echo -n foo\n\
3408- /// echo -n bar >&2"
3409- /// ])
3410- /// .stdout(writer.try_clone()?)
3411- /// .stderr(writer)
3412- /// .spawn()?;
3413- ///
3414- /// // Read and check the result.
3415- /// let mut msg = String::new();
3416- /// reader.read_to_string(&mut msg)?;
3417- /// assert_eq!(&msg, "foobar");
3418- ///
3419- /// peer.wait()?;
3420- /// # Ok(())
3421- /// # }
3422- /// ```
3423- #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
3424- pub fn try_clone ( & self ) -> Result < Self > {
3425- self . 0 . try_clone ( ) . map ( Self )
3426- }
3427- }
3428-
3429- #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
3430- impl Read for & PipeReader {
3431- fn read ( & mut self , buf : & mut [ u8 ] ) -> Result < usize > {
3432- self . 0 . read ( buf)
3433- }
3434- fn read_vectored ( & mut self , bufs : & mut [ IoSliceMut < ' _ > ] ) -> Result < usize > {
3435- self . 0 . read_vectored ( bufs)
3436- }
3437- #[ inline]
3438- fn is_read_vectored ( & self ) -> bool {
3439- self . 0 . is_read_vectored ( )
3440- }
3441- fn read_to_end ( & mut self , buf : & mut Vec < u8 > ) -> Result < usize > {
3442- self . 0 . read_to_end ( buf)
3443- }
3444- fn read_buf ( & mut self , buf : BorrowedCursor < ' _ > ) -> Result < ( ) > {
3445- self . 0 . read_buf ( buf)
3446- }
3447- }
3448-
3449- #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
3450- impl Read for PipeReader {
3451- fn read ( & mut self , buf : & mut [ u8 ] ) -> Result < usize > {
3452- self . 0 . read ( buf)
3453- }
3454- fn read_vectored ( & mut self , bufs : & mut [ IoSliceMut < ' _ > ] ) -> Result < usize > {
3455- self . 0 . read_vectored ( bufs)
3456- }
3457- #[ inline]
3458- fn is_read_vectored ( & self ) -> bool {
3459- self . 0 . is_read_vectored ( )
3460- }
3461- fn read_to_end ( & mut self , buf : & mut Vec < u8 > ) -> Result < usize > {
3462- self . 0 . read_to_end ( buf)
3463- }
3464- fn read_buf ( & mut self , buf : BorrowedCursor < ' _ > ) -> Result < ( ) > {
3465- self . 0 . read_buf ( buf)
3466- }
3467- }
3468-
3469- #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
3470- impl Write for & PipeWriter {
3471- fn write ( & mut self , buf : & [ u8 ] ) -> Result < usize > {
3472- self . 0 . write ( buf)
3473- }
3474- #[ inline]
3475- fn flush ( & mut self ) -> Result < ( ) > {
3476- Ok ( ( ) )
3477- }
3478-
3479- fn write_vectored ( & mut self , bufs : & [ IoSlice < ' _ > ] ) -> Result < usize > {
3480- self . 0 . write_vectored ( bufs)
3481- }
3482-
3483- #[ inline]
3484- fn is_write_vectored ( & self ) -> bool {
3485- self . 0 . is_write_vectored ( )
3486- }
3487- }
3488-
3489- #[ unstable( feature = "anonymous_pipe" , issue = "127154" ) ]
3490- impl Write for PipeWriter {
3491- fn write ( & mut self , buf : & [ u8 ] ) -> Result < usize > {
3492- self . 0 . write ( buf)
3493- }
3494- #[ inline]
3495- fn flush ( & mut self ) -> Result < ( ) > {
3496- Ok ( ( ) )
3497- }
3498-
3499- fn write_vectored ( & mut self , bufs : & [ IoSlice < ' _ > ] ) -> Result < usize > {
3500- self . 0 . write_vectored ( bufs)
3501- }
3502-
3503- #[ inline]
3504- fn is_write_vectored ( & self ) -> bool {
3505- self . 0 . is_write_vectored ( )
3506- }
3507- }
0 commit comments