From 4260d6c79adc88eaf7d09e72a2be0cabf5a4fd86 Mon Sep 17 00:00:00 2001 From: Kotauskas Date: Wed, 12 Jun 2024 14:37:39 +0300 Subject: [PATCH] Sync unnamed pipe examples --- examples/unnamed_pipe/sync/main.rs | 16 ++++++++++++-- examples/unnamed_pipe/sync/side_a.rs | 31 ++++++++++++++++++++++++++++ examples/unnamed_pipe/sync/side_b.rs | 17 +++++++++++++++ src/unnamed_pipe.rs | 14 +++++++++++++ 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/examples/unnamed_pipe/sync/main.rs b/examples/unnamed_pipe/sync/main.rs index 881353c..d1ed5de 100644 --- a/examples/unnamed_pipe/sync/main.rs +++ b/examples/unnamed_pipe/sync/main.rs @@ -1,6 +1,18 @@ mod side_a; mod side_b; -fn main() { - todo!() +#[cfg(windows)] +type Handle = std::os::windows::io::OwnedHandle; +#[cfg(unix)] +type Handle = std::os::unix::io::OwnedFd; + +use std::{io, sync::mpsc, thread}; + +fn main() -> io::Result<()> { + let (htx, hrx) = mpsc::sync_channel(1); + let jh = thread::spawn(move || side_a::main(htx)); + let handle = hrx.recv().unwrap(); + + side_b::main(handle)?; + jh.join().unwrap() } diff --git a/examples/unnamed_pipe/sync/side_a.rs b/examples/unnamed_pipe/sync/side_a.rs index e69de29..12974dc 100644 --- a/examples/unnamed_pipe/sync/side_a.rs +++ b/examples/unnamed_pipe/sync/side_a.rs @@ -0,0 +1,31 @@ +//{ +use std::{io, sync::mpsc}; +pub(super) fn main(handle_sender: mpsc::SyncSender) -> io::Result<()> { + //} + use interprocess::unnamed_pipe::pipe; + use std::io::{prelude::*, BufReader}; + + // Create the unnamed pipe, yielding a sender and a receiver. + let (tx, rx) = pipe()?; + + // Let's extract the raw handle or file descriptor of the sender. Note that `OwnedHandle` and + // `OwnedFd` both implement `From`. + let txh = tx.into(); + // Now deliver `txh` to the child process. This may be done by starting it here with a + // command-line argument or via stdin. This works because child processes inherit handles and + // file descriptors to unnamed pipes. You can also use a different platform-specific way of + // transferring handles or file descriptors across a process boundary. + //{ + handle_sender.send(txh).unwrap(); + //} + + let mut buf = String::with_capacity(128); + // We'd like to receive a line, so buffer our input. + let mut rx = BufReader::new(rx); + // Receive the line from the other process. + rx.read_line(&mut buf)?; + + assert_eq!(buf.trim(), "Hello from side B!"); + //{ + Ok(()) +} //} diff --git a/examples/unnamed_pipe/sync/side_b.rs b/examples/unnamed_pipe/sync/side_b.rs index e69de29..73e8c02 100644 --- a/examples/unnamed_pipe/sync/side_b.rs +++ b/examples/unnamed_pipe/sync/side_b.rs @@ -0,0 +1,17 @@ +//{ +pub(super) fn main(handle: super::Handle) -> std::io::Result<()> { + //} + use interprocess::unnamed_pipe; + use std::io::prelude::*; + + // `handle` here is an `OwnedHandle` or an `OwnedFd` from the standard library. Those + // implement `FromRawHandle` and `FromRawFd` respectively. The actual value can be transferred + // via a command-line parameter since it's numerically equal to the value obtained in the + // parent process via `OwnedHandle::from()`/`OwnedFd::from()` thanks to handle inheritance. + let mut tx = unnamed_pipe::Sender::from(handle); + + // Send our message to the other side. + tx.write_all(b"Hello from side B!\n")?; + //{ + Ok(()) +} //} diff --git a/src/unnamed_pipe.rs b/src/unnamed_pipe.rs index da6c156..15ba683 100644 --- a/src/unnamed_pipe.rs +++ b/src/unnamed_pipe.rs @@ -15,6 +15,9 @@ //! which can be used in simple cases instead of unnamed pipes. Making use of that feature is //! advisable if the program of the child process can be modified to communicate with its parent //! via standard I/O streams. +//! +//! # Examples +//! See [`pipe()`]. #[cfg(feature = "tokio")] #[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "tokio")))] @@ -33,6 +36,17 @@ use std::io; /// /// The platform-specific builders in the `os` module of the crate might be more helpful if extra /// configuration for the pipe is needed. +/// +/// # Examples +/// ## Basic communication +/// In a parent process: +/// ```no_run +#[doc = doctest_file::include_doctest!("examples/unnamed_pipe/sync/side_a.rs")] +/// ``` +/// In a child process: +/// ```no_run +#[doc = doctest_file::include_doctest!("examples/unnamed_pipe/sync/side_b.rs")] +/// ``` #[inline] pub fn pipe() -> io::Result<(Sender, Recver)> { pipe_impl()