### Integrate fdringbuf with mio Event Loop Source: https://context7.com/diwic/fdringbuf-rs/llms.txt This example demonstrates integrating fdringbuf with the mio event loop for concurrent handling of multiple channels. It includes producer threads and a mio handler to process messages. ```rust extern crate nix; extern crate mio; extern crate fdringbuf; use fdringbuf::fdbuf::{self, Pipe}; use nix::sys::eventfd::{eventfd, EfdFlags}; use std::os::unix::io::FromRawFd; #[derive(Copy, Clone, Debug)] enum Message { Hello(i32), Data(u8), Goodbye, } // Producer function running in separate thread fn producer(id: i32, mut sender: fdbuf::Sender>) { sender.send_foreach(1, |_| Message::Hello(id)).unwrap(); std::thread::sleep(std::time::Duration::from_millis(50)); sender.send_foreach(5, |i| Message::Data(i as u8)).unwrap(); std::thread::sleep(std::time::Duration::from_millis(50)); sender.send_foreach(1, |_| Message::Goodbye).unwrap(); } // Handler for mio event loop struct Receiver { channels: Vec>>, io_handles: Vec, goodbye_count: i32, } impl mio::Handler for Receiver { type Timeout = (); type Message = (); fn ready(&mut self, event_loop: &mut mio::EventLoop, token: mio::Token, _: mio::EventSet) { let mut should_shutdown = false; self.channels[token.0].recv(|data| { for msg in data { println!("Channel {}: {:?}", token.0, msg); if let Message::Goodbye = msg { self.goodbye_count += 1; if self.goodbye_count == self.channels.len() as i32 { should_shutdown = true; } } } (data.len(), false) }).unwrap(); if should_shutdown { event_loop.shutdown(); } } } fn main() { let mut event_loop = mio::EventLoop::new().unwrap(); let mut handler = Receiver { channels: vec![], io_handles: vec![], goodbye_count: 0, }; // Create 4 channels with separate producer threads for i in 0..4 { let efd1 = eventfd(0, EfdFlags::EFD_CLOEXEC).unwrap(); let efd2 = eventfd(0, EfdFlags::EFD_CLOEXEC).unwrap(); let pipe1 = Pipe { reader: efd1, writer: efd1 }; let pipe2 = Pipe { reader: efd2, writer: efd2 }; let buffer = vec![0u8; fdringbuf::channel_bufsize::(64)]; let (sender, receiver) = fdbuf::channel(buffer, pipe1, pipe2); // Spawn producer thread std::thread::spawn(move || producer(i, sender)); // Register with mio handler.channels.push(receiver); for &fd in &[efd1, efd2] { let io = unsafe { mio::Io::from_raw_fd(fd) }; event_loop.register(&io, mio::Token(i as usize)).unwrap(); handler.io_handles.push(io); } } // Run event loop - processes all channels concurrently event_loop.run(&mut handler).unwrap(); println!("All producers finished"); } ``` -------------------------------- ### Efficient Blocking with wait_status and wait_clear Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Use `wait_status` to get the file descriptor for waiting and the current buffer status. Call `wait_clear` after being woken up to prevent immediate re-triggering. This example demonstrates receiver-side waiting. ```rust use fdringbuf::fdbuf::{self, Pipe}; use fdringbuf::channel_bufsize; extern crate nix; use nix::sys::epoll::*; fn make_epoll(fd: i32) -> i32 { let epoll_fd = epoll_create().unwrap(); let event = EpollEvent::new(EpollFlags::EPOLLIN, 0); epoll_ctl(epoll_fd, EpollOp::EpollCtlAdd, fd, Some(&mut event.clone())).unwrap(); epoll_fd } fn make_pipe() -> Pipe { let pipe = Pipe { reader: -1, writer: -1 }; unsafe { libc::pipe(std::mem::transmute(&pipe)) }; pipe } let buffer = vec![0u8; channel_bufsize::(512)]; let (mut sender, mut receiver) = fdbuf::channel::( buffer, make_pipe(), make_pipe() ); // Receiver side - efficient waiting let (wait_fd, available) = receiver.wait_status(); let epoll_fd = make_epoll(wait_fd); loop { // Check if data available without syscall let (_, count) = receiver.wait_status(); if count > 0 { // Data available - process it receiver.recv(|data| { println!("Processing {} items", data.len()); (data.len(), false) }).unwrap(); } else { // No data - wait on fd (blocks efficiently) let mut events = [EpollEvent::empty()]; epoll_wait(epoll_fd, &mut events, 5000).unwrap(); // IMPORTANT: Clear the wait state after wakeup receiver.wait_clear().unwrap(); } } ``` -------------------------------- ### fdbuf::Receiver::recv - Receive Data with Signalling Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Receives data from the ringbuffer using a closure that gets a slice of available data. Returns the number of remaining items. Automatically signals the sender if the buffer was full and space was freed. ```APIDOC ## fdbuf::Receiver::recv - Receive Data with Signalling ### Description Receives data from the ringbuffer using a closure that gets a slice of available data. Returns the number of remaining items. Automatically signals the sender if the buffer was full and space was freed. ### Method GET (conceptual, as it retrieves data from the buffer) ### Endpoint N/A (This is a library function, not a network endpoint) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None (Data is provided via closure) ### Request Example ```rust use fdringbuf::fdbuf::{self, Pipe}; use fdringbuf::channel_bufsize; use std::thread; fn make_pipe() -> Pipe { let pipe = Pipe { reader: -1, writer: -1 }; unsafe { libc::pipe(std::mem::transmute(&pipe)) }; pipe } let buffer = vec![0u8; channel_bufsize::(1024)]; let (mut sender, mut receiver) = fdbuf::channel::( buffer, make_pipe(), make_pipe() ); // Producer thread thread::spawn(move || { for batch in 0..10 { sender.send_foreach(100, |i| (batch * 100 + i) as i32).unwrap(); thread::sleep(std::time::Duration::from_millis(10)); } }); // Consumer - process all data in batches let mut total_received = 0; loop { let remaining = receiver.recv(|data| { let to_process = std::cmp::min(data.len(), 50); for item in &data[..to_process] { // Process each item total_received += 1; } (to_process, true) // (consumed, call again for more) }).unwrap(); if remaining == 0 { let (wait_fd, available) = receiver.wait_status(); if available == 0 { // No data available, wait on fd // Using epoll: epoll_wait(epoll_fd, &mut events, timeout) receiver.wait_clear().unwrap(); } } if total_received >= 1000 { break; } } println!("Received {} items total", total_received); ``` ### Response #### Success Response (200) - **remaining** (usize) - The number of items remaining in the buffer after the receive operation. #### Response Example ``` 50 ``` ### Error Handling - **RecvError**: If the receive operation fails (e.g., due to underlying pipe errors). ``` -------------------------------- ### Create Basic Ringbuffer Channel (No FD Signalling) Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Creates a sender/receiver pair for a ringbuffer channel without file descriptor signalling. Use this when implementing custom signalling or employing busy-waiting. The channel requires a pre-allocated buffer and is non-allocating after initialization. ```rust use fdringbuf::ringbuf; // Allocate buffer for 3 u16 items let buffer: Vec = vec![0; ringbuf::channel_bufsize::(3)]; let (mut sender, mut receiver) = ringbuf::channel::(buffer); // Send data using low-level send (pointer-based, zero-copy) sender.send(|ptr, capacity| { // ptr is an out parameter - contains garbage, write only unsafe { *ptr = 100u16; *ptr.offset(1) = 200; } 2 // Return number of items written }); // Send data using safe send_foreach (uses RVO to avoid copies) let mut counter = 0; sender.send_foreach(1, |_index| { counter += 1; 300u16 // Return value written to buffer }); // Receive data receiver.recv(|data| { println!("Received {} items: {:?}", data.len(), data); // Output: Received 3 items: [100, 200, 300] data.len() // Return number of items consumed }); // Check buffer status println!("Items available to read: {}", receiver.read_count()); println!("Space available to write: {}", sender.write_count()); ``` -------------------------------- ### Create Ringbuffer Channel with FD Signalling Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Creates a sender/receiver pair for a ringbuffer channel with file descriptor signalling for efficient blocking. This is ideal for integration with event loops like mio. It requires two `Pipe` structures for bidirectional signalling. ```rust use fdringbuf::fdbuf::{self, Pipe}; use fdringbuf::channel_bufsize; // Using pipes for signalling (cross-platform) fn make_pipe() -> Pipe { let pipe = Pipe { reader: -1, writer: -1 }; unsafe { libc::pipe(std::mem::transmute(&pipe)) }; pipe } let pipe_empty = make_pipe(); // Signals when buffer becomes non-empty let pipe_full = make_pipe(); // Signals when buffer becomes non-full // Allocate buffer for 1024 i32 items let buffer = vec![0u8; channel_bufsize::(1024)]; let (mut sender, mut receiver) = fdbuf::channel::(buffer, pipe_empty, pipe_full); // Send data - automatically signals receiver if buffer was empty let free_space = sender.send_foreach(100, |i| (i * 2) as i32).unwrap(); println!("Free space after send: {}", free_space); // Receive data - automatically signals sender if buffer was full let remaining = receiver.recv(|data| { let count = std::cmp::min(50, data.len()); for item in &data[..count] { println!("Got: {}", item); } (count, false) // (items consumed, call again flag) }).unwrap(); println!("Remaining items: {}", remaining); ``` -------------------------------- ### Send data with low-level zero-copy API Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Uses a closure to write directly to a raw pointer. The closure may be invoked multiple times to handle ringbuffer wrap-around. ```rust use fdringbuf::fdbuf::{self, Pipe}; use fdringbuf::channel_bufsize; // Setup (using eventfd for best performance on Linux) extern crate nix; use nix::sys::eventfd::{eventfd, EfdFlags}; let efd1 = eventfd(0, EfdFlags::EFD_CLOEXEC).unwrap(); let efd2 = eventfd(0, EfdFlags::EFD_CLOEXEC).unwrap(); let pipe1 = Pipe { reader: efd1, writer: efd1 }; let pipe2 = Pipe { reader: efd2, writer: efd2 }; let buffer = vec![0u8; channel_bufsize::(256)]; let (mut sender, mut receiver) = fdbuf::channel::(buffer, pipe1, pipe2); // Send with low-level API - closure called potentially twice for wrap-around let mut total_written = 0; let free_slots = sender.send(|ptr, capacity| { let to_write = std::cmp::min(capacity, 100); for i in 0..to_write { unsafe { *ptr.offset(i as isize) = i as f64 * 1.5 }; } total_written += to_write; (to_write, total_written < 100) // (written, continue flag) }).unwrap(); println!("Wrote {} items, {} slots free", total_written, free_slots); // Check if we need to wait before sending more let (wait_fd, can_write) = sender.wait_status(); if can_write == 0 { // Buffer is full, need to wait on wait_fd // Use epoll/mio to wait, then call: // sender.wait_clear().unwrap(); } ``` -------------------------------- ### Utility Function: channel_bufsize Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Calculates the required buffer size for a ringbuffer channel, accounting for data capacity and internal atomic counter storage. ```APIDOC ## Utility Function: channel_bufsize ### Description Calculates the exact buffer size needed before allocating memory for a ringbuffer channel. The function accounts for both the data capacity and internal atomic counter storage. ### Method N/A (Utility Function) ### Endpoint N/A ### Parameters None ### Request Example ```rust use fdringbuf::channel_bufsize; // Calculate buffer size for 1024 u32 items let buf_size = channel_bufsize::(1024); println!("Need {} bytes for 1024 u32 items", buf_size); // Calculate buffer size for 64 custom Protocol items #[derive(Copy, Clone)] enum Protocol { Hello(i32), Data(u8), Goodbye, } let proto_buf_size = channel_bufsize::(64); let buffer = vec![0u8; proto_buf_size]; ``` ### Response N/A (Utility Function) ### Response Example N/A ``` -------------------------------- ### Receive data with signaling Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Processes available data via a slice-based closure. Automatically triggers signaling to the sender when space is freed. ```rust use fdringbuf::fdbuf::{self, Pipe}; use fdringbuf::channel_bufsize; use std::thread; fn make_pipe() -> Pipe { let pipe = Pipe { reader: -1, writer: -1 }; unsafe { libc::pipe(std::mem::transmute(&pipe)) }; pipe } let buffer = vec![0u8; channel_bufsize::(1024)]; let (mut sender, mut receiver) = fdbuf::channel::( buffer, make_pipe(), make_pipe() ); // Producer thread thread::spawn(move || { for batch in 0..10 { sender.send_foreach(100, |i| (batch * 100 + i) as i32).unwrap(); thread::sleep(std::time::Duration::from_millis(10)); } }); // Consumer - process all data in batches let mut total_received = 0; loop { let remaining = receiver.recv(|data| { let to_process = std::cmp::min(data.len(), 50); for item in &data[..to_process] { // Process each item total_received += 1; } (to_process, true) // (consumed, call again for more) }).unwrap(); if remaining == 0 { let (wait_fd, available) = receiver.wait_status(); if available == 0 { // No data available, wait on fd // Using epoll: epoll_wait(epoll_fd, &mut events, timeout) receiver.wait_clear().unwrap(); } } if total_received >= 1000 { break; } } println!("Received {} items total", total_received); ``` -------------------------------- ### Calculate Ringbuffer Size Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Use `channel_bufsize` to determine the exact byte size required for a ringbuffer, accounting for data capacity and internal atomic counters. This is essential before allocating memory for a channel. ```rust use fdringbuf::channel_bufsize; // Calculate buffer size for 1024 u32 items let buf_size = channel_bufsize::(1024); println!("Need {} bytes for 1024 u32 items", buf_size); // Output: Need 4104 bytes for 1024 u32 items // Calculate buffer size for 64 custom Protocol items #[derive(Copy, Clone)] enum Protocol { Hello(i32), Data(u8), Goodbye, } let proto_buf_size = channel_bufsize::(64); let buffer = vec![0u8; proto_buf_size]; ``` -------------------------------- ### Send data with safe iterative API Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Provides a safer interface that processes items individually. It relies on Return Value Optimization to minimize memory copies. ```rust use fdringbuf::fdbuf::{self, Pipe}; use fdringbuf::channel_bufsize; #[derive(Copy, Clone, Debug)] struct AudioSample { left: f32, right: f32, timestamp: u64, } // Setup channel fn make_pipe() -> Pipe { let pipe = Pipe { reader: -1, writer: -1 }; unsafe { libc::pipe(std::mem::transmute(&pipe)) }; pipe } let buffer = vec![0u8; channel_bufsize::(4096)]; let (mut sender, mut receiver) = fdbuf::channel::( buffer, make_pipe(), make_pipe() ); // Generate and send 1000 audio samples let mut timestamp = 0u64; let free_after = sender.send_foreach(1000, |index| { timestamp += 1; AudioSample { left: (index as f32 * 0.01).sin(), right: (index as f32 * 0.01).cos(), timestamp, } }).unwrap(); println!("Sent 1000 samples, {} slots free", free_after); // If buffer full, wait and retry if free_after == 0 { let (fd, _) = sender.wait_status(); // Wait on fd using epoll/mio... sender.wait_clear().unwrap(); // Now can send more } ``` -------------------------------- ### fdbuf::Sender::send - Low-Level Zero-Copy Send Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Sends data to the ringbuffer using a closure that receives a raw pointer and available capacity. Returns the number of free slots remaining. The closure may need to be called multiple times for wrap-around scenarios. ```APIDOC ## fdbuf::Sender::send - Low-Level Zero-Copy Send ### Description Sends data to the ringbuffer using a closure that receives a raw pointer and available capacity. Returns the number of free slots remaining. The closure may need to be called multiple times for wrap-around scenarios. ### Method POST (conceptual, as it modifies the buffer) ### Endpoint N/A (This is a library function, not a network endpoint) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None (Data is provided via closure) ### Request Example ```rust use fdringbuf::fdbuf::{self, Pipe}; use fdringbuf::channel_bufsize; // Setup (using eventfd for best performance on Linux) extern crate nix; use nix::sys::eventfd::{eventfd, EfdFlags}; let efd1 = eventfd(0, EfdFlags::EFD_CLOEXEC).unwrap(); let efd2 = eventfd(0, EfdFlags::EFD_CLOEXEC).unwrap(); let pipe1 = Pipe { reader: efd1, writer: efd1 }; let pipe2 = Pipe { reader: efd2, writer: efd2 }; let buffer = vec![0u8; channel_bufsize::(256)]; let (mut sender, mut receiver) = fdbuf::channel::(buffer, pipe1, pipe2); // Send with low-level API - closure called potentially twice for wrap-around let mut total_written = 0; let free_slots = sender.send(|ptr, capacity| { let to_write = std::cmp::min(capacity, 100); for i in 0..to_write { unsafe { *ptr.offset(i as isize) = i as f64 * 1.5 }; } total_written += to_write; (to_write, total_written < 100) // (written, continue flag) }).unwrap(); println!("Wrote {} items, {} slots free", total_written, free_slots); // Check if we need to wait before sending more let (wait_fd, can_write) = sender.wait_status(); if can_write == 0 { // Buffer is full, need to wait on wait_fd // Use epoll/mio to wait, then call: // sender.wait_clear().unwrap(); } ``` ### Response #### Success Response (200) - **free_slots** (usize) - The number of free slots remaining in the buffer after the send operation. #### Response Example ``` 150 ``` ### Error Handling - **SendError**: If the send operation fails (e.g., due to underlying pipe errors). ``` -------------------------------- ### fdbuf::Sender::send_foreach - Safe Iterative Send Source: https://context7.com/diwic/fdringbuf-rs/llms.txt A safer version of send that calls your closure for each item to be written, relying on Return Value Optimization (RVO) to avoid memory copies. Will not block if the buffer becomes full. ```APIDOC ## fdbuf::Sender::send_foreach - Safe Iterative Send ### Description A safer version of send that calls your closure for each item to be written, relying on Return Value Optimization (RVO) to avoid memory copies. Will not block if the buffer becomes full. ### Method POST (conceptual, as it modifies the buffer) ### Endpoint N/A (This is a library function, not a network endpoint) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None (Data is provided via closure) ### Request Example ```rust use fdringbuf::fdbuf::{self, Pipe}; use fdringbuf::channel_bufsize; #[derive(Copy, Clone, Debug)] struct AudioSample { left: f32, right: f32, timestamp: u64, } // Setup channel fn make_pipe() -> Pipe { let pipe = Pipe { reader: -1, writer: -1 }; unsafe { libc::pipe(std::mem::transmute(&pipe)) }; pipe } let buffer = vec![0u8; channel_bufsize::(4096)]; let (mut sender, mut receiver) = fdbuf::channel::( buffer, make_pipe(), make_pipe() ); // Generate and send 1000 audio samples let mut timestamp = 0u64; let free_after = sender.send_foreach(1000, |index| { timestamp += 1; AudioSample { left: (index as f32 * 0.01).sin(), right: (index as f32 * 0.01).cos(), timestamp, } }).unwrap(); println!("Sent 1000 samples, {} slots free", free_after); // If buffer full, wait and retry if free_after == 0 { let (fd, _) = sender.wait_status(); // Wait on fd using epoll/mio... sender.wait_clear().unwrap(); // Now can send more } ``` ### Response #### Success Response (200) - **free_after** (usize) - The number of free slots remaining in the buffer after the send operation. #### Response Example ``` 3000 ``` ### Error Handling - **SendError**: If the send operation fails (e.g., due to underlying pipe errors). ``` -------------------------------- ### Ringbuffer Channel with FD Signalling: fdbuf::channel Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Creates a sender/receiver pair for a ringbuffer channel with file descriptor signalling for efficient blocking. ```APIDOC ## Ringbuffer Channel with FD Signalling: fdbuf::channel ### Description Creates a sender/receiver pair with file descriptor signalling for efficient blocking when the buffer is empty or full. Requires two `Pipe` structures for bidirectional signalling. Ideal for integration with mio or other event loops. ### Method N/A (Constructor Function) ### Endpoint N/A ### Parameters None ### Request Example ```rust use fdringbuf::fdbuf::{self, Pipe}; use fdringbuf::channel_bufsize; // Using pipes for signalling (cross-platform) fn make_pipe() -> Pipe { let pipe = Pipe { reader: -1, writer: -1 }; unsafe { libc::pipe(std::mem::transmute(&pipe)) }; pipe } let pipe_empty = make_pipe(); // Signals when buffer becomes non-empty let pipe_full = make_pipe(); // Signals when buffer becomes non-full // Allocate buffer for 1024 i32 items let buffer = vec![0u8; channel_bufsize::(1024)]; let (mut sender, mut receiver) = fdbuf::channel::(buffer, pipe_empty, pipe_full); // Send data - automatically signals receiver if buffer was empty let free_space = sender.send_foreach(100, |i| (i * 2) as i32).unwrap(); println!("Free space after send: {}", free_space); // Receive data - automatically signals sender if buffer was full let remaining = receiver.recv(|data| { let count = std::cmp::min(50, data.len()); for item in &data[..count] { println!("Got: {}", item); } (count, false) // (items consumed, call again flag) }).unwrap(); println!("Remaining items: {}", remaining); ``` ### Response N/A (Constructor Function) ### Response Example N/A ``` -------------------------------- ### Ringbuffer Channel: ringbuf::channel Source: https://context7.com/diwic/fdringbuf-rs/llms.txt Creates a sender/receiver pair for a ringbuffer channel without file descriptor signalling. Suitable for custom signalling or busy-waiting. ```APIDOC ## Ringbuffer Channel: ringbuf::channel ### Description Creates a sender/receiver pair without fd signalling. Use this when you want to implement your own signalling mechanism or are willing to busy-wait. The channel is non-allocating and expects a pre-allocated buffer. ### Method N/A (Constructor Function) ### Endpoint N/A ### Parameters None ### Request Example ```rust use fdringbuf::ringbuf; // Allocate buffer for 3 u16 items let buffer: Vec = vec![0; ringbuf::channel_bufsize::(3)]; let (mut sender, mut receiver) = ringbuf::channel::(buffer); // Send data using low-level send (pointer-based, zero-copy) sender.send(|ptr, capacity| { // ptr is an out parameter - contains garbage, write only unsafe { *ptr = 100u16; *ptr.offset(1) = 200; } 2 // Return number of items written }); // Send data using safe send_foreach (uses RVO to avoid copies) let mut counter = 0; sender.send_foreach(1, |_index| { counter += 1; 300u16 // Return value written to buffer }); // Receive data receiver.recv(|data| { println!("Received {} items: {:?}", data.len(), data); // Output: Received 3 items: [100, 200, 300] data.len() // Return number of items consumed }); // Check buffer status println!("Items available to read: {}", receiver.read_count()); println!("Space available to write: {}", sender.write_count()); ``` ### Response N/A (Constructor Function) ### Response Example N/A ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.