### Build and Start a Local Socket Server (Sync) Source: https://context7.com/kotauskas/interprocess/llms.txt Use `ListenerOptions` to configure and create a synchronous local socket server. Handles 'Address in use' errors and processes incoming connections sequentially. ```Rust use interprocess::local_socket::{prelude::*, GenericNamespaced, ListenerOptions}; use std::io::{self, prelude::*, BufReader}; fn main() -> io::Result<()> { let printname = "example.sock"; let name = printname.to_ns_name::()?; let listener = match ListenerOptions::new() .name(name) .try_overwrite(true) // replace stale socket files automatically .create_sync() { Err(e) if e.kind() == io::ErrorKind::AddrInUse => { eprintln!("Socket {printname} is in use by another process."); return Err(e); } x => x?, }; eprintln!("Server listening on {printname}"); let mut buffer = String::with_capacity(128); for mut conn in listener .incoming() .filter_map(|c| c.map_err(|e| eprintln!("Connection error: {e}")).ok()) .map(BufReader::new) { conn.read_line(&mut buffer)?; conn.get_mut().write_all(b"Hello from server!\n")?; drop(conn); print!("Client said: {buffer}"); buffer.clear(); } Ok(()) } ``` -------------------------------- ### ListenerOptions::create_sync() Source: https://context7.com/kotauskas/interprocess/llms.txt Builds and starts a local socket server synchronously. It allows configuration of the socket's name, blocking mode, and other options before creating the listener. ```APIDOC ## ListenerOptions::create_sync() ### Description Builds and starts a local socket server synchronously. Key methods include `.name(name)`, `.nonblocking(mode)`, `.reclaim_name(bool)`, `.try_overwrite(bool)`, and `.max_spin_time(duration)`. Call `.create_sync()` to bind and start listening. ### Method `ListenerOptions::create_sync()` ### Parameters - `name` (Name): The name of the socket to create. - `nonblocking` (bool): If true, the socket operates in non-blocking mode. - `reclaim_name` (bool): If true, attempts to reclaim the socket name if it's already in use. - `try_overwrite` (bool): If true, attempts to overwrite a stale socket file. - `max_spin_time` (duration): The maximum time to spin when waiting for resources. ### Request Example ```rust use interprocess::local_socket::{prelude::*, GenericNamespaced, ListenerOptions}; use std::io; let name = "example.sock".to_ns_name::()?; let listener = ListenerOptions::new() .name(name) .try_overwrite(true) .create_sync()?; ``` ### Response #### Success Response A `Listener` object that can be used to accept incoming connections. #### Response Example ```rust // Successful listener creation let listener = ListenerOptions::new().name(name).create_sync()?; ``` ### Error Handling Returns an `io::Error` if the socket address is already in use or another error occurs during creation. ``` -------------------------------- ### Windows Named Pipe Server Source: https://context7.com/kotauskas/interprocess/llms.txt On Windows, `PipeListenerOptions` allows configuration of named pipe servers, supporting byte-stream or message-framed modes. This example demonstrates a byte-stream duplex pipe server. ```rust // Windows-only #[cfg(windows)] fn main() -> std::io::Result<()> { use interprocess::os::windows::named_pipe::{pipe_mode, PipeListenerOptions}; use std::{io::{prelude::*, BufReader}, path::Path}; let pipe_name = r"\\.\pipe\Example"; let listener = PipeListenerOptions::new() .path(Path::new(pipe_name)) .create_duplex::()?; eprintln!("Named-pipe server at {pipe_name}"); let mut buffer = String::with_capacity(128); for mut conn in listener .incoming() .filter_map(|c| c.map_err(|e| eprintln!("{e}")).ok()) .map(BufReader::new) { conn.read_line(&mut buffer)?; conn.get_mut().write_all(b"Hello from server!\n")?; print!("Client said: {buffer}"); buffer.clear(); } Ok(()) } #[cfg(not(windows))] fn main() { eprintln!("Windows only."); } ``` -------------------------------- ### Accepting Client Connections with Sync Listener Source: https://context7.com/kotauskas/interprocess/llms.txt Demonstrates accepting synchronous client connections using `Listener::incoming()` and handling them in a loop. Configures `accept` to be nonblocking while streams remain blocking. ```rust use interprocess::local_socket::{ prelude::*, GenericNamespaced, ListenerNonblockingMode, ListenerOptions, }; use std::io::{self, BufRead, BufReader, Write}; fn main() -> io::Result<()> { let name = "demo.sock".to_ns_name::()?; let listener = ListenerOptions::new().name(name).create_sync()?; // Make `accept` nonblocking while keeping created streams blocking. listener.set_nonblocking(ListenerNonblockingMode::Accept)?; for conn in listener.incoming() { match conn { Ok(mut stream) => { let mut reader = BufReader::new(&stream); let mut line = String::new(); reader.read_line(&mut line)?; stream.write_all(b"ACK\n")?; println!("Handled: {line}"); } Err(e) if e.kind() == io::ErrorKind::WouldBlock => { // No client waiting right now — do other work. std::thread::sleep(std::time::Duration::from_millis(10)); } Err(e) => eprintln!("Accept error: {e}"), } } Ok(()) } ``` -------------------------------- ### Listener::accept() / ListenerExt::incoming() Source: https://context7.com/kotauskas/interprocess/llms.txt Accepts incoming client connections. `accept()` blocks until a client connects, returning a `Stream`. `incoming()` provides an iterator over incoming connections. ```APIDOC ## `Listener::accept()` / `ListenerExt::incoming()` — Accept client connections ### Description `accept()` blocks until a client connects and returns a `Stream`. `incoming()` (from `ListenerExt`) wraps `accept()` in an infinite `Iterator>`, enabling idiomatic `for` loops for server main loops. `set_nonblocking(mode)` can be used to configure independent nonblocking behavior for `accept` and for the returned streams. ### Methods - `accept()` - `incoming()` - `set_nonblocking(mode)` ### Parameters #### `set_nonblocking` Parameter - **mode** (ListenerNonblockingMode) - Configures nonblocking behavior for accept and/or streams. ### Usage Example ```rust use interprocess::local_socket::{ListenerOptions, GenericNamespaced, ListenerNonblockingMode}; let name = "demo.sock".to_ns_name::()?; let listener = ListenerOptions::new().name(name).create_sync()?; // Make `accept` nonblocking listener.set_nonblocking(ListenerNonblockingMode::Accept)?; for conn in listener.incoming() { // Handle connection... } ``` ### Response #### Success Response (`accept()`) - **Stream** - A connected stream to the client. #### Success Response (`incoming()`) - **Iterator>** - An iterator yielding connected streams. ``` -------------------------------- ### ListenerOptions::create_tokio() Source: https://context7.com/kotauskas/interprocess/llms.txt Creates an asynchronous local socket server using Tokio. Accepted connections implement `AsyncRead + AsyncWrite`, and concurrent handling is achieved via `tokio::spawn`. ```APIDOC ## ListenerOptions::create_tokio() ### Description Creates an asynchronous local socket server using Tokio. Accepted connections implement `AsyncRead + AsyncWrite`. Concurrent connection handling is achieved by spawning tasks with `tokio::spawn`. ### Method `ListenerOptions::create_tokio()` ### Parameters - `name` (Name): The name of the socket to create. ### Request Example ```rust use interprocess::local_socket::tokio::Listener; use interprocess::local_socket::GenericNamespaced; use interprocess::local_socket::ListenerOptions; let name = "example.sock".to_ns_name::()?; let listener = ListenerOptions::new().name(name).create_tokio()?; ``` ### Response #### Success Response A `tokio::Listener` object that can be used to accept incoming asynchronous connections. #### Response Example ```rust let listener = ListenerOptions::new().name(name).create_tokio()?; ``` ### Error Handling Returns an `io::Error` if the socket cannot be created or bound. ``` -------------------------------- ### Windows Named Pipes: Async Tokio Server Source: https://context7.com/kotauskas/interprocess/llms.txt Sets up an asynchronous server using Tokio for Windows named pipes in byte mode. Handles incoming connections by spawning a new task for each client. ```rust #[cfg(all(windows, feature = "tokio"))] #[tokio::main] async fn main() -> Result<(), Box> { use interprocess::os::windows::named_pipe::{pipe_mode, tokio::*, PipeListenerOptions}; use std::{io, path::Path}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::try_join; async fn handle(conn: DuplexPipeStream) -> io::Result<()> { let [mut r, mut s] = [&conn; 2]; let mut buf = String::new(); try_join!( async { s.write_all(b"Hi!").await?; s.shutdown().await }, r.read_to_string(&mut buf) )?; println!("Client: {buf}"); Ok(()) } let listener = PipeListenerOptions::new() .path(Path::new(r"\\.\pipe\AsyncExample")) .create_tokio_duplex::()?; loop { let conn = listener.accept().await?; tokio::spawn(async move { let _ = handle(conn).await; }); } } ``` -------------------------------- ### Async Local Socket Server (Tokio) Source: https://context7.com/kotauskas/interprocess/llms.txt Implement an asynchronous local socket server using `ListenerOptions::create_tokio()` and Tokio. Handles connections concurrently by spawning tasks for each client. ```Rust use interprocess::local_socket::{ tokio::{prelude::*, Stream}, GenericNamespaced, ListenerOptions, }; use std::io; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::try_join; async fn handle_conn(conn: Stream) -> io::Result<()> { let mut recver = BufReader::new(&conn); let mut sender = &conn; let mut buffer = String::with_capacity(128); // Send and receive concurrently to avoid deadlock. try_join!( sender.write_all(b"Hello from server!\n"), recver.read_line(&mut buffer) )?; drop(conn); print!("Client said: {buffer}"); Ok(()) } #[tokio::main] async fn main() -> Result<(), Box> { let name = "example.sock".to_ns_name::()?; let listener = ListenerOptions::new().name(name).create_tokio()?; eprintln!("Async server ready"); loop { match listener.accept().await { Ok(conn) => { tokio::spawn(async move { if let Err(e) = handle_conn(conn).await { eprintln!("Connection error: {e}"); } }); } Err(e) => eprintln!("Accept error: {e}"), } } } ``` -------------------------------- ### Connect to a Local Socket Server (Sync) Source: https://context7.com/kotauskas/interprocess/llms.txt Use `Stream::connect` to establish a synchronous connection to a local socket server. It resolves names based on platform support for namespaced or filesystem paths. ```Rust use interprocess::local_socket::{ prelude::*, GenericFilePath, GenericNamespaced, Stream, }; use std::io::{prelude::*, BufReader}; fn main() -> std::io::Result<()> { // Use a namespaced name when available (Linux abstract namespace / // Windows named-pipe namespace), fall back to a filesystem path on // platforms that lack a dedicated socket namespace. let name = if GenericNamespaced::is_supported() { "example.sock".to_ns_name::()? } else { "/tmp/example.sock".to_fs_name::()? }; let mut conn = BufReader::new(Stream::connect(name)?); conn.get_mut().write_all(b"Hello from client!\n")?; let mut buffer = String::with_capacity(128); conn.read_line(&mut buffer)?; drop(conn); print!("Server replied: {buffer}"); Ok(()) } ``` -------------------------------- ### Control Client Connection Wait Behavior Source: https://context7.com/kotauskas/interprocess/llms.txt Configure how a client waits for a server connection using `ConnectWaitMode`. Options include `Unbounded` (default), `Timeout(Duration)` for a specific wait period, and `Deferred` for immediate return with errors surfacing on subsequent I/O. ```rust use interprocess::{ConnectWaitMode, local_socket::{prelude::*, ConnectOptions, GenericNamespaced}}; use std::time::Duration; fn main() -> std::io::Result<()> { let name = "wait_demo.sock".to_ns_name::()?; // Try to connect; give up after 2 seconds. let conn = ConnectOptions::new() .name(name) .wait_mode(ConnectWaitMode::Timeout(Duration::from_secs(2))) .connect_sync()?; println!("Connected: {conn:?}"); Ok(()) } ``` -------------------------------- ### Stream::connect() Source: https://context7.com/kotauskas/interprocess/llms.txt Connects to a local socket server synchronously. This is the client-side entry point, blocking until the server accepts the connection or it fails. ```APIDOC ## Stream::connect() ### Description Connects to a local socket server synchronously. It resolves the provided `Name` and establishes a connection, blocking until the server accepts or the connection fails. ### Method `Stream::connect(name)` ### Parameters - `name` (Name): The name of the socket to connect to, typically created using `to_ns_name` or `to_fs_name`. ### Request Example ```rust use interprocess::local_socket::{GenericFilePath, GenericNamespaced, Stream}; let name = if GenericNamespaced::is_supported() { "example.sock".to_ns_name::()? } else { "/tmp/example.sock".to_fs_name::()? }; let mut conn = Stream::connect(name)?; ``` ### Response #### Success Response A `Stream` object representing the established connection. #### Response Example ```rust let mut conn = Stream::connect(name)?; ``` ### Error Handling Returns an `io::Error` if the connection fails to establish. ``` -------------------------------- ### Windows named pipes - PipeListenerOptions Source: https://context7.com/kotauskas/interprocess/llms.txt Provides low-level control over named pipe servers on Windows. It supports both byte-stream and message-framed modes, and includes options for Tokio integration. ```APIDOC ## Windows named pipes — `PipeListenerOptions` (Windows-only) On Windows, `interprocess::os::windows::named_pipe::PipeListenerOptions` provides low-level control over named pipe servers. Supports both byte-stream (`pipe_mode::Bytes`) and message-framed (`pipe_mode::Messages`) modes, plus Tokio variants via `.create_tokio_duplex()`. ### Example ```rust // Windows-only #[cfg(windows)] fn main() -> std::io::Result<()> { use interprocess::os::windows::named_pipe::{pipe_mode, PipeListenerOptions}; use std::{io::{prelude::*, BufReader}, path::Path}; let pipe_name = r"\\.\pipe\Example"; let listener = PipeListenerOptions::new() .path(Path::new(pipe_name)) .create_duplex::()?; eprintln!("Named-pipe server at {pipe_name}"); let mut buffer = String::with_capacity(128); for mut conn in listener .incoming() .filter_map(|c| c.map_err(|e| eprintln!("{e}")).ok()) .map(BufReader::new) { conn.read_line(&mut buffer)?; conn.get_mut().write_all(b"Hello from server!\n")?; print!("Client said: {buffer}"); buffer.clear(); } Ok(()) } #[cfg(not(windows))] fn main() { eprintln!("Windows only."); } ``` ``` -------------------------------- ### tokio::Stream::connect() Source: https://context7.com/kotauskas/interprocess/llms.txt Connects to a local socket asynchronously. Allows concurrent reading and writing by holding references to the stream. ```APIDOC ## `tokio::Stream::connect()` — Async local socket client (Tokio) ### Description The Tokio client mirrors the sync API. `Stream::connect(name).await` resolves and connects asynchronously. Reading and writing can be performed concurrently by holding both a `BufReader<&Stream>` and a `&Stream` reference. ### Method `Stream::connect(name).await` ### Parameters #### Path Parameters - **name** (Name<'_>) - Required - The name of the local socket to connect to. ### Request Example ```rust use interprocess::local_socket::tokio::Stream; let name = ...; // Construct a valid socket name let conn = Stream::connect(name).await?; ``` ### Response #### Success Response (Stream) - **Stream** - An asynchronous stream representing the connected socket. ``` -------------------------------- ### Async Local Socket Client with Tokio Source: https://context7.com/kotauskas/interprocess/llms.txt Connects to a local socket asynchronously using Tokio. Reading and writing can be performed concurrently by holding separate references to the stream. ```rust use interprocess::local_socket::{ tokio::{prelude::*, Stream}, GenericFilePath, GenericNamespaced, }; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::try_join; #[tokio::main] async fn main() -> Result<(), Box> { let name = if GenericNamespaced::is_supported() { "example.sock".to_ns_name::()? } else { "/tmp/example.sock".to_fs_name::()? }; let conn = Stream::connect(name).await?; let mut recver = BufReader::new(&conn); let mut sender = &conn; let mut buffer = String::with_capacity(128); try_join!( sender.write_all(b"Hello from client!\n"), recver.read_line(&mut buffer) )?; drop(recver); drop(conn); print!("Server replied: {buffer}"); Ok(()) } ``` -------------------------------- ### ToFsName / ToNsName — Construct local socket names Source: https://context7.com/kotauskas/interprocess/llms.txt Extension traits to convert strings and paths into `Name<'_>` values for local socket dispatch. `ToFsName` targets filesystem paths, and `ToNsName` targets abstract/namespaced sockets. ```APIDOC ## `ToFsName` / `ToNsName` — Construct local socket names ### Description These two extension traits convert strings and paths into `Name<'_>` values that drive local socket implementation dispatch. `ToFsName` targets filesystem paths; `ToNsName` targets abstract/named-pipe namespaces. The generic type argument (`GenericFilePath`, `GenericNamespaced`, or a platform-specific type) controls the mapping. ### Methods - `to_fs_name::()` - `to_ns_name::()` ### Parameters #### Path Parameters - **self** (String, &Path, &OsStr) - The input string, path, or OS string to convert. - **T** (GenericFilePath, GenericNamespaced, or platform-specific type) - The target name type. ### Usage Example ```rust use interprocess::local_socket::{GenericFilePath, GenericNamespaced}; // Filesystem path let fs_name = "/tmp/my.sock".to_fs_name::()?; // Namespaced path let ns_name = "my.sock".to_ns_name::()?; ``` ``` -------------------------------- ### Constructing Local Socket Names Source: https://context7.com/kotauskas/interprocess/llms.txt Uses `ToFsName` and `ToNsName` traits to create `Name<'_>` values for local socket implementations. `ToFsName` is for filesystem paths, while `ToNsName` is for abstract/named-pipe namespaces. ```rust use interprocess::local_socket::{ prelude::*, GenericFilePath, GenericNamespaced, }; use std::{ffi::OsStr, path::Path}; fn demo_names() -> std::io::Result<()> { // Filesystem path — always supported on Unix; on Windows maps to \\.\pipe\ let fs_from_str = "/tmp/my.sock".to_fs_name::()?; let fs_from_path = Path::new("/tmp/my.sock").to_fs_name::()?; let fs_from_os = OsStr::new("/tmp/my.sock").to_fs_name::()?; // Namespaced — Linux abstract namespace, Windows \\.\pipe\, or /tmp/ fallback let ns_from_str = "my.sock".to_ns_name::()?; println!("fs namespaced? {}", fs_from_str.is_namespaced()); // false on Unix println!("ns namespaced? {}", ns_from_str.is_namespaced()); // true // Check runtime support before choosing the name type if GenericNamespaced::is_supported() { println!("Using namespaced sockets"); } else { println!("Falling back to filesystem sockets"); } Ok(()) } ``` -------------------------------- ### Create Unnamed Pipe (Async/Tokio) Source: https://context7.com/kotauskas/interprocess/llms.txt Use `interprocess::unnamed_pipe::tokio::pipe()` for asynchronous unnamed pipes with Tokio. The sender and receiver implement `AsyncWrite` and `AsyncRead`. Ownership transfer across process boundaries uses `TryFrom`. ```rust use interprocess::unnamed_pipe::tokio::pipe; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::sync::oneshot; use std::{io, os::unix::io::OwnedFd}; async fn side_a(handle_sender: oneshot::Sender) -> io::Result<()> { let (tx, rx) = pipe()?; // Extract OwnedFd from the async Sender via TryFrom. let txh: OwnedFd = tx.try_into()?; handle_sender.send(txh).unwrap(); let mut buf = String::with_capacity(128); let mut rx = BufReader::new(rx); rx.read_line(&mut buf).await?; assert_eq!(buf.trim(), "Hello from side B!"); Ok(()) } async fn side_b(handle: OwnedFd) -> io::Result<()> { use interprocess::unnamed_pipe; let mut tx = unnamed_pipe::tokio::Sender::try_from(handle)?; tx.write_all(b"Hello from side B!\n").await?; Ok(()) } #[tokio::main] async fn main() -> io::Result<()> { let (htx, hrx) = oneshot::channel(); let jh = tokio::task::spawn(side_a(htx)); let handle = hrx.await.unwrap(); side_b(handle).await?; jh.await.unwrap() } ``` -------------------------------- ### Query Peer Process Credentials Source: https://context7.com/kotauskas/interprocess/llms.txt The `peer_creds()` method retrieves OS-level process credentials for the connected peer. The availability of specific fields like PID and UID depends on the operating system. ```rust use interprocess::local_socket::{prelude::*, GenericNamespaced, Stream}; fn main() -> std::io::Result<()> { let name = "creds_demo.sock".to_ns_name::()?; let conn = Stream::connect(name)?; let creds = conn.peer_creds()?; if let Some(pid) = creds.pid() { println!("Peer PID: {pid}"); } #[cfg(unix)] { if let Some(uid) = creds.euid() { println!("Peer effective UID: {uid}"); } if let Some(gid) = creds.egid() { println!("Peer effective GID: {gid}"); } if let Some(groups) = creds.groups() { println!("Peer supplementary groups: {groups:?}"); } } Ok(()) } ``` -------------------------------- ### Split and Reunite Streams Source: https://context7.com/kotauskas/interprocess/llms.txt Use `split()` to divide a stream into receiving and sending halves, allowing them to be used in different threads. `reunite()` can reconstruct the original stream if both halves are still available. ```rust use interprocess::local_socket::{prelude::*, GenericNamespaced, Stream}; use std::io::{prelude::*, BufReader}; use std::thread; fn main() -> std::io::Result<()> { let name = "split_demo.sock".to_ns_name::()?; let conn = Stream::connect(name)?; let (recv_half, mut send_half) = conn.split(); let reader_thread = thread::spawn(move || { let mut reader = BufReader::new(recv_half); let mut buf = String::new(); reader.read_line(&mut buf).unwrap(); println!("Received: {buf}"); }); send_half.write_all(b"Hello!\n")?; reader_thread.join().unwrap(); // Reunite is also possible if you still hold both halves: // let stream = Stream::reunite(recv_half, send_half).unwrap(); Ok(()) } ``` -------------------------------- ### Stream::split() / Stream::reunite() Source: https://context7.com/kotauskas/interprocess/llms.txt Splits a stream into two halves, allowing each half to be moved to a different thread. `reunite()` can be used to reconstruct the original stream from its halves. ```APIDOC ## `Stream::split()` / `Stream::reunite()` — Split a stream into halves `split()` consumes a `Stream` and returns a `(RecvHalf, SendHalf)` pair. Each half can be moved to a different thread. `reunite()` reconstructs the original stream; it fails (returning both halves in the error) if the halves originate from different streams. ### Example ```rust use interprocess::local_socket::{prelude::*, GenericNamespaced, Stream}; use std::io::{prelude::*, BufReader}; use std::thread; fn main() -> std::io::Result<()> { let name = "split_demo.sock".to_ns_name::()?; let conn = Stream::connect(name)?; let (recv_half, mut send_half) = conn.split(); let reader_thread = thread::spawn(move || { let mut reader = BufReader::new(recv_half); let mut buf = String::new(); reader.read_line(&mut buf).unwrap(); println!("Received: {buf}"); }); send_half.write_all(b"Hello!\n")?; reader_thread.join().unwrap(); // Reunite is also possible if you still hold both halves: // let stream = Stream::reunite(recv_half, send_half).unwrap(); Ok(()) } ``` ``` -------------------------------- ### ConnectWaitMode Source: https://context7.com/kotauskas/interprocess/llms.txt An enum that controls how a client connection attempt waits for the server. It offers options for unbounded waiting, a specific timeout, or immediate return with deferred error surfacing. ```APIDOC ## `ConnectWaitMode` — Control client connection wait behavior `ConnectWaitMode` is an enum passed to `ConnectOptions` (or used internally) to decide how the client waits for the server during connection. Three variants: `Unbounded` (default – block until connected), `Timeout(Duration)` (return `TimedOut` if not connected in time), and `Deferred` (return immediately; errors surface on subsequent I/O). ### Example ```rust use interprocess::{ConnectWaitMode, local_socket::{prelude::*, ConnectOptions, GenericNamespaced}}; use std::time::Duration; fn main() -> std::io::Result<()> { let name = "wait_demo.sock".to_ns_name::()?; // Try to connect; give up after 2 seconds. let conn = ConnectOptions::new() .name(name) .wait_mode(ConnectWaitMode::Timeout(Duration::from_secs(2))) .connect_sync()?; println!("Connected: {conn:?}"); Ok(()) } ``` ``` -------------------------------- ### Recoverable Conversion Errors Source: https://context7.com/kotauskas/interprocess/llms.txt Demonstrates handling `ConversionError` which occurs during fallible `TryFrom` conversions, such as converting an `OwnedFd` to a Tokio sender. The error type allows recovery of the original source object. ```rust use interprocess::error::ConversionError; use std::io; fn try_convert(fd: std::os::unix::io::OwnedFd) -> Result> { interprocess::unnamed_pipe::tokio::Sender::try_from(fd) } fn main() { // (hypothetical usage — requires a real inheritable pipe FD) // match try_convert(some_fd) { // Ok(sender) => { /* use sender */ } // Err(e) => { // eprintln!("Conversion failed: {e}"); // if let Some(original_fd) = e.source { // // recover ownership of the fd // } // } // } } ``` -------------------------------- ### StreamCommon::peer_creds() Source: https://context7.com/kotauskas/interprocess/llms.txt Queries the operating system for credentials of the connected peer process. This is available on all local socket streams and returns a `PeerCreds` struct. ```APIDOC ## `StreamCommon::peer_creds()` — Query peer process credentials Available on all local socket streams (both sync and async), `peer_creds()` returns a `PeerCreds` struct containing OS-level process credentials for the connected peer. Availability of individual fields (`pid`, `euid`, `egid`, `groups`) varies by OS. ### Example ```rust use interprocess::local_socket::{prelude::*, GenericNamespaced, Stream}; fn main() -> std::io::Result<()> { let name = "creds_demo.sock".to_ns_name::()?; let conn = Stream::connect(name)?; let creds = conn.peer_creds()?; if let Some(pid) = creds.pid() { println!("Peer PID: {pid}"); } #[cfg(unix)] { if let Some(uid) = creds.euid() { println!("Peer effective UID: {uid}"); } if let Some(gid) = creds.egid() { println!("Peer effective GID: {gid}"); } if let Some(groups) = creds.groups() { println!("Peer supplementary groups: {groups:?}"); } } Ok(()) } ``` ``` -------------------------------- ### Windows Named Pipes: Message Mode Client Source: https://context7.com/kotauskas/interprocess/llms.txt Connects to a Windows named pipe in message mode and sends a discrete message. The receiver must use `recv_msg` to retrieve the message atomically. ```rust #[cfg(windows)] fn client_messages() -> std::io::Result<()> { use interprocess::os::windows::named_pipe::{pipe_mode, DuplexPipeStream}; use recvmsg::prelude::*; let name = r"\\.\pipe\Example"; let mut conn = DuplexPipeStream::::connect_by_path(name)?; const MSG: &[u8] = b"Hello from client!"; let sent = conn.send(MSG)?; assert_eq!(sent, MSG.len()); let mut buf = MsgBuf::from(Vec::with_capacity(128)); conn.recv_msg(&mut buf, None)?; let reply = String::from_utf8_lossy(buf.filled_part()); println!("Server replied: {reply}"); Ok(()) } ``` -------------------------------- ### Create Unnamed Pipe (Sync) Source: https://context7.com/kotauskas/interprocess/llms.txt Use `interprocess::unnamed_pipe::pipe()` to create a unidirectional byte channel for parent-child process communication. The sender and receiver can be inherited by child processes. Dropping the sender flushes any buffered data. ```rust use interprocess::unnamed_pipe::pipe; use std::io::{prelude::*, BufReader, sync::mpsc}; use std::{os, thread}; // ── Side A (parent) ────────────────────────────────────────────────────────── fn side_a(handle_sender: std::sync::mpsc::SyncSender) -> std::io::Result<()> { let (tx, rx) = pipe()?; // Convert the Sender to an OwnedFd and pass it to "side B" (the child). // Child processes inherit handles/file-descriptors of unnamed pipes. let txh: os::unix::io::OwnedFd = tx.into(); handle_sender.send(txh).unwrap(); let mut buf = String::with_capacity(128); let mut rx = BufReader::new(rx); rx.read_line(&mut buf)?; assert_eq!(buf.trim(), "Hello from side B!"); Ok(()) } // ── Side B (child) ─────────────────────────────────────────────────────────── fn side_b(handle: os::unix::io::OwnedFd) -> std::io::Result<()> { use interprocess::unnamed_pipe; // Reconstruct the Sender from the inherited file descriptor. let mut tx = unnamed_pipe::Sender::from(handle); tx.write_all(b"Hello from side B!\n")?; Ok(()) } // ── Orchestrator ───────────────────────────────────────────────────────────── fn main() -> std::io::Result<()> { let (htx, hrx) = std::sync::mpsc::sync_channel(1); let jh = thread::spawn(move || side_a(htx)); let handle = hrx.recv().unwrap(); side_b(handle)?; jh.join().unwrap() } ``` -------------------------------- ### interprocess::unnamed_pipe::tokio::pipe() — Create an unnamed pipe (async/Tokio) Source: https://context7.com/kotauskas/interprocess/llms.txt The asynchronous version of `pipe()`, utilizing Tokio. It returns a `(tokio::Sender, tokio::Recver)` pair that implement `AsyncWrite` and `AsyncRead` respectively. ```APIDOC ## interprocess::unnamed_pipe::tokio::pipe() — Create an unnamed pipe (async/Tokio) ### Description The async counterpart of the sync `pipe()`. Returns `(tokio::Sender, tokio::Recver)` that implement `AsyncWrite` and `AsyncRead` respectively. Ownership transfer across process boundaries uses `TryFrom`. ### Method ```rust fn pipe() -> io::Result<(tokio::Sender, tokio::Recver)> ``` ### Parameters None ### Request Example ```rust use interprocess::unnamed_pipe::tokio::pipe; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; use tokio::sync::oneshot; use std::{io, os::unix::io::OwnedFd}; async fn side_a(handle_sender: oneshot::Sender) -> io::Result<()> { let (tx, rx) = pipe()?; let txh: OwnedFd = tx.try_into()?; handle_sender.send(txh).unwrap(); let mut buf = String::with_capacity(128); let mut rx = BufReader::new(rx); rx.read_line(&mut buf).await?; assert_eq!(buf.trim(), "Hello from side B!"); Ok(()) } async fn side_b(handle: OwnedFd) -> io::Result<()> { use interprocess::unnamed_pipe; let mut tx = unnamed_pipe::tokio::Sender::try_from(handle)?; tx.write_all(b"Hello from side B!\n").await?; Ok(()) } #[tokio::main] async fn main() -> io::Result<()> { let (htx, hrx) = oneshot::channel(); let jh = tokio::task::spawn(side_a(htx)); let handle = hrx.await.unwrap(); side_b(handle).await?; jh.await.unwrap() } ``` ### Response #### Success Response (200) Returns a tuple containing a `tokio::Sender` and a `tokio::Recver` for the unnamed pipe. #### Response Example ```rust // Example of the returned tuple structure (not actual output) // (tokio::Sender, tokio::Recver) ``` ``` -------------------------------- ### interprocess::unnamed_pipe::pipe() — Create an unnamed pipe (sync) Source: https://context7.com/kotauskas/interprocess/llms.txt Creates a unidirectional byte channel for interprocess communication. The returned sender and receiver implement `std::io::Write` and `std::io::Read` respectively, and can be inherited by child processes. ```APIDOC ## interprocess::unnamed_pipe::pipe() — Create an unnamed pipe (sync) ### Description Returns a `(Sender, Recver)` pair connected by a unidirectional byte channel. `Sender` implements `Write` and `Recver` implements `Read`. Both types are inheritable by child processes, enabling the classic parent–child pipe pattern. On Windows, dropping a `Sender` enters "limbo" (data already in the buffer is still flushed). ### Method ```rust fn pipe() -> std::io::Result<(Sender, Recver)> ``` ### Parameters None ### Request Example ```rust use interprocess::unnamed_pipe::pipe; use std::io::{prelude::*, BufReader}; use std::thread; fn side_a(handle_sender: std::sync::mpsc::SyncSender) -> std::io::Result<()> { let (tx, rx) = pipe()?; let txh: std::os::unix::io::OwnedFd = tx.into(); handle_sender.send(txh).unwrap(); let mut buf = String::with_capacity(128); let mut rx = BufReader::new(rx); rx.read_line(&mut buf)?; assert_eq!(buf.trim(), "Hello from side B!"); Ok(()) } fn side_b(handle: std::os::unix::io::OwnedFd) -> std::io::Result<()> { use interprocess::unnamed_pipe; let mut tx = unnamed_pipe::Sender::from(handle); tx.write_all(b"Hello from side B!\n")?; Ok(()) } fn main() -> std::io::Result<()> { let (htx, hrx) = std::sync::mpsc::sync_channel(1); let jh = thread::spawn(move || side_a(htx)); let handle = hrx.recv().unwrap(); side_b(handle)?; jh.join().unwrap() } ``` ### Response #### Success Response (200) Returns a tuple containing a `Sender` and a `Recver` for the unnamed pipe. #### Response Example ```rust // Example of the returned tuple structure (not actual output) // (Sender, Recver) ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.