fibre 0.3.1

High-performance, memory-efficient sync/async channels built for real-time, low-overhead communication in concurrent Rust applications.
Documentation
# Usage Guide: `fibre`

This guide provides detailed examples and an overview of the core concepts and APIs in the `fibre` library.

### Table of Contents

*   [Core Concepts]#core-concepts
*   [Quick Start Examples]#quick-start-examples
    *   [MPMC Sync Example]#mpmc-sync-example
    *   [MPSC Async Example]#mpsc-async-example
    *   [SPSC Hybrid Example]#spsc-hybrid-example
*   [API by Channel Type]#api-by-channel-type
    *   [Module: `fibre::mpmc`]#module-fibrempmc
    *   [Module: `fibre::mpsc`]#module-fibrempsc
    *   [Module: `fibre::spmc`]#module-fibrespmc
    *   [Module: `fibre::spsc`]#module-fibrespsc
    *   [Module: `fibre::oneshot`]#module-fibreoneshot
*   [Error Handling]#error-handling

## Core Concepts

### Specialized Channels

Fibre's main philosophy is to provide the right tool for the job. Instead of using a general-purpose MPMC channel for all tasks, you can choose a specialized implementation that is algorithmically optimized for your use case, leading to better performance and lower overhead.

*   **SPSC (Single-Sender, Single-Receiver):** The fastest pattern for 1-to-1 communication. Implemented with a lock-free ring buffer. It's bounded and requires `T: Send`.
*   **MPSC (Multi-Sender, Single-Receiver):** Many threads/tasks send to one receiver. Great for collecting results or distributing work to a single processor. Implemented with a lock-free linked list and is unbounded. Requires `T: Send`.
*   **SPMC (Single-Sender, Multi-Receiver):** One thread/task broadcasts the same message to many receivers. Each consumer gets a clone of the message. Implemented with a specialized ring buffer that tracks individual consumer progress. It's bounded and requires `T: Send + Clone`.
*   **MPMC (Multi-Sender, Multi-Receiver):** The most flexible pattern, allowing many-to-many communication. Implemented with a `parking_lot::Mutex` for robust state management and support for mixed sync/async waiters. Supports bounded (including rendezvous) and "unbounded" (memory-limited) capacities. Requires `T: Send`.
*   **Oneshot:** A channel for sending a single value, once, from one of potentially many senders to a single receiver. Requires `T: Send`.

### Hybrid Sync/Async Model

The `mpmc`, `mpsc`, `spmc`, and `spsc` channels support full interoperability between synchronous and asynchronous code. Every sender and receiver handle has a `to_sync()` or `to_async()` method that performs a zero-cost conversion. This allows you to, for example, have producers running in standard OS threads (`std::thread`) sending data to a consumer running in a Tokio task, all on the same channel.

### Sender/Receiver Handles

All channels are interacted with via sender and receiver handles (e.g., `Sender`, `Receiver`, `AsyncSender`, `AsyncReceiver`; SPSC uses `BoundedSyncSender`, etc.). These handles control access to the channel and manage its lifetime. When all senders for a channel are dropped, the channel becomes "disconnected" from the perspective of the receiver. When all receivers are dropped, the channel becomes "closed" from the perspective of the sender.

## Quick Start Examples

### MPMC Sync Example

A simple many-to-many example using standard threads.

```rust
use fibre::mpmc;
use std::thread;

fn main() {
    let (tx, rx) = mpmc::bounded(4); // Bounded channel with capacity 4
    let num_producers = 2;
    let items_per_producer = 5;
    let mut handles = Vec::new();

    // Spawn producers
    for i in 0..num_producers {
        let tx_clone = tx.clone();
        handles.push(thread::spawn(move || {
            for j in 0..items_per_producer {
                let msg = format!("Sender {} says: {}", i, j);
                if tx_clone.send(msg).is_err() {
                    eprintln!("Sender {}: Receiver dropped!", i);
                    break;
                }
            }
        }));
    }
    drop(tx); // Drop the original sender

    // Spawn consumers (or receive in main thread)
    let mut consumer_handles = Vec::new();
    let num_consumers = 2; // Example with multiple consumers
    for c_id in 0..num_consumers {
        let rx_clone = rx.clone();
        consumer_handles.push(thread::spawn(move || {
            loop {
                match rx_clone.recv() {
                    Ok(received) => println!("Receiver {}: Got: {}", c_id, received),
                    Err(_) => { // Disconnected
                        println!("Receiver {}: Channel disconnected.", c_id);
                        break;
                    }
                }
            }
        }));
    }
    drop(rx); // Drop original receiver

    for handle in handles { // Sender handles
        handle.join().unwrap();
    }
    for handle in consumer_handles {
        handle.join().unwrap();
    }
}
```

### MPSC Async Example

An example with multiple asynchronous producers sending to a single consumer task.

```rust
use fibre::mpsc;
use tokio::task;

#[tokio::main]
async fn main() {
    let (tx, mut rx) = mpsc::unbounded_async(); // MPSC is unbounded
    let num_producers = 3;
    let items_per_producer = 5;

    // Spawn async producers
    for i in 0..num_producers {
        let tx_clone = tx.clone();
        task::spawn(async move {
            for j in 0..items_per_producer {
                if tx_clone.send((i, j)).await.is_err() {
                    eprintln!("Async Sender {}: Receiver dropped!", i);
                    break;
                }
            }
        });
    }
    drop(tx); // Signal to the consumer that all producers are potentially done after their work

    // The single consumer receives all the work
    let mut total = 0;
    while let Ok(msg) = rx.recv().await {
        println!("Received: {:?}", msg);
        total += 1;
    }
    assert_eq!(total, num_producers * items_per_producer);
    println!("MPSC async example finished.");
}
```

### SPSC Hybrid Example

An example demonstrating a synchronous producer sending to an asynchronous consumer.

```rust
use fibre::spsc;
use std::thread;
use tokio::runtime::Runtime;

fn main() {
    let rt = Runtime::new().unwrap();
    rt.block_on(async {
        // Start with an async channel, then convert the producer to sync
        let (p_async, mut c_async) = spsc::bounded_async::<String>(2);
        let mut p_sync = p_async.to_sync(); // Convert producer to sync

        let producer_thread = thread::spawn(move || {
            p_sync.send("Hello from sync thread!".to_string()).unwrap();
            p_sync.send("Goodbye from sync thread!".to_string()).unwrap();
            // p_sync is dropped here, consumer will see Disconnected after messages
        });

        println!("Async consumer received: {}", c_async.recv().await.unwrap());
        println!("Async consumer received: {}", c_async.recv().await.unwrap());
        assert!(matches!(c_async.recv().await, Err(fibre::error::RecvError::Disconnected)));

        producer_thread.join().unwrap();
    });
}
```

## API by Channel Type

_(Note: `T` must generally be `Send`. Specific trait bounds like `Clone` are noted.)_

### Module: `fibre::mpmc`

A flexible channel for many-to-many communication.

*   **Constructors:**
    *   `pub fn bounded<T: Send>(capacity: usize) -> (Sender<T>, Receiver<T>)`: Creates a bounded, synchronous channel. `capacity = 0` creates a rendezvous channel.
    *   `pub fn bounded_async<T: Send>(capacity: usize) -> (AsyncSender<T>, AsyncReceiver<T>)`: Creates a bounded, asynchronous channel. `capacity = 0` for rendezvous.
    *   `pub fn unbounded<T: Send>() -> (Sender<T>, Receiver<T>)`: Creates an "unbounded" synchronous channel.
    *   `pub fn unbounded_async<T: Send>() -> (AsyncSender<T>, AsyncReceiver<T>)`: Creates an "unbounded" asynchronous channel.
*   **Handles:**
    *   `Sender<T: Send>` (`Clone`) and `Receiver<T: Send>` (`Clone`).
    *   `AsyncSender<T: Send>` (`Clone`) and `AsyncReceiver<T: Send>` (`Clone`).
*   **Key Methods (All handles unless specified):**
    *   `send(...)`: (Sync `Sender`, Async `AsyncSender` returns `SendFuture`)
    *   `try_send(&self, item: T) -> Result<(), TrySendError<T>>`
    *   `recv(...)`: (Sync `Receiver`, Async `AsyncReceiver` returns `ReceiveFuture`)
    *   `try_recv(&self) -> Result<T, TryRecvError>`
    *   `is_closed(&self) -> bool` (Meaning depends on sender/receiver context)
    *   `capacity(&self) -> Option<usize>`
    *   `len(&self) -> usize`
    *   `is_empty(&self) -> bool`
    *   `is_full(&self) -> bool`
    *   `to_async(self) -> ...` (On sync handles)
    *   `to_sync(self) -> ...` (On async handles)

### Module: `fibre::mpsc`

An optimized lock-free channel for many-to-one communication (unbounded).

*   **Constructors:**
    *   `pub fn unbounded<T: Send>() -> (Sender<T>, Receiver<T>)`: Creates a synchronous MPSC channel.
    *   `pub fn unbounded_async<T: Send>() -> (AsyncSender<T>, AsyncReceiver<T>)`: Creates an asynchronous MPSC channel.
*   **Handles:**
    *   `Sender<T: Send>` (sync, `Clone`) and `Receiver<T: Send>` (sync, `!Clone`).
    *   `AsyncSender<T: Send>` (async, `Clone`) and `AsyncReceiver<T: Send>` (async, `!Clone`).
*   **Key Methods:**
    *   `Sender::send(&self, value: T) -> Result<(), SendError>`
    *   `Sender::len(&self) -> usize`
    *   `Sender::to_async(self) -> AsyncSender<T>`
    *   `Receiver::recv(&mut self) -> Result<T, RecvError>`
    *   `Receiver::try_recv(&mut self) -> Result<T, TryRecvError>`
    *   `Receiver::len(&self) -> usize`
    *   `Receiver::is_empty(&self) -> bool`
    *   `Receiver::to_async(self) -> AsyncReceiver<T>`
    *   `AsyncSender::send(&self, value: T) -> SendFuture<'_, T>`
    *   `AsyncSender::len(&self) -> usize`
    *   `AsyncSender::to_sync(self) -> Sender<T>`
    *   `AsyncReceiver::recv(&mut self) -> RecvFuture<'_, T>`
    *   `AsyncReceiver::try_recv(&mut self) -> Result<T, TryRecvError>`
    *   `AsyncReceiver::len(&self) -> usize`
    *   `AsyncReceiver::is_empty(&self) -> bool`
    *   `AsyncReceiver::to_sync(self) -> Receiver<T>`

### Module: `fibre::spmc`

A broadcast-style channel for one-to-many communication (bounded). `T` must be `Send + Clone`.

*   **Constructors:**
    *   `pub fn bounded<T: Send + Clone>(capacity: usize) -> (Sender<T>, Receiver<T>)`: Creates a synchronous SPMC channel. Panics if capacity is 0.
    *   `pub fn bounded_async<T: Send + Clone>(capacity: usize) -> (AsyncSender<T>, AsyncReceiver<T>)`: Creates an asynchronous SPMC channel. Panics if capacity is 0.
*   **Handles:**
    *   `Sender<T: Send + Clone>` (sync, `!Clone`) and `Receiver<T: Send + Clone>` (sync, `Clone`).
    *   `AsyncSender<T: Send + Clone>` (async, `!Clone`) and `AsyncReceiver<T: Send + Clone>` (async, `Clone`).
*   **Key Methods (All handles unless specified):**
    *   `send(&mut self, ...)`: (Sync `Sender`, Async `AsyncSender` returns `SendFuture`)
    *   `try_send(&mut self, value: T) -> Result<(), TrySendError<T>>`
    *   `recv(&mut self, ...)`: (Sync `Receiver`, Async `AsyncReceiver` returns `ReceiveFuture`)
    *   `try_recv(&mut self) -> Result<T, TryRecvError>`
    *   `len(&self) -> usize` (For `Sender`, it's `head - min_tail`; for `Receiver`, it's items available for *this* receiver)
    *   `is_empty(&self) -> bool`
    *   `is_full(&self) -> bool`
    *   `to_async(self) -> ...` (On sync handles)
    *   `to_sync(self) -> ...` (On async handles)

### Module: `fibre::spsc`

A high-performance lock-free channel for one-to-one communication (bounded). `T` must be `Send`.

*   **Constructors:**
    *   `pub fn bounded_sync<T: Send>(capacity: usize) -> (BoundedSyncSender<T>, BoundedSyncReceiver<T>)`: Creates a bounded, synchronous SPSC channel. Panics if capacity is 0.
    *   `pub fn bounded_async<T: Send>(capacity: usize) -> (AsyncBoundedSpscSender<T>, AsyncBoundedSpscReceiver<T>)`: Creates a bounded, asynchronous SPSC channel. Panics if capacity is 0.
*   **Handles:**
    *   `BoundedSyncSender<T: Send>` (`!Clone`) and `BoundedSyncReceiver<T: Send>` (`!Clone`).
    *   `AsyncBoundedSpscSender<T: Send>` (`!Clone`) and `AsyncBoundedSpscReceiver<T: Send>` (`!Clone`).
*   **Key Methods (All handles unless specified):**
    *   `send(...)`: (Sync `BoundedSyncSender` takes `&mut self`, Async `AsyncBoundedSpscSender` takes `&self` and returns `SendFuture`)
    *   `try_send(...)`: (Sync `BoundedSyncSender` takes `&mut self`, Async `AsyncBoundedSpscSender` takes `&self`)
    *   `recv(...)`: (Sync `BoundedSyncReceiver` takes `&mut self`, Async `AsyncBoundedSpscReceiver` takes `&self` and returns `ReceiveFuture`)
    *   `try_recv(...)`: (Sync `BoundedSyncReceiver` takes `&mut self`, Async `AsyncBoundedSpscReceiver` takes `&self`)
    *   `BoundedSyncReceiver::recv_timeout(&mut self, timeout: Duration) -> Result<T, RecvErrorTimeout>`
    *   `len(&self) -> usize`
    *   `is_empty(&self) -> bool`
    *   `is_full(&self) -> bool`
    *   `to_async(self) -> ...` (On sync handles)
    *   `to_sync(self) -> ...` (On async handles)
    *   Async `SendFuture` requires `T: Unpin + Send`.

### Module: `fibre::oneshot`

A channel for sending a single value once. `T` must be `Send`.

*   **Constructors:**
    *   `pub fn oneshot<T>() -> (Sender<T>, Receiver<T>)`: Creates a oneshot channel.
*   **Handles:**
    *   `Sender<T>` (`Clone`) and `Receiver<T>` (`!Clone`).
*   **Key Methods:**
    *   `Sender::send(self, value: T) -> Result<(), TrySendError<T>>`: Sends the single value. Consumes the sender. Fails if already sent or receiver dropped.
    *   `Sender::is_closed(&self) -> bool`: Checks if the receiver has been dropped.
    *   `Sender::is_sent(&self) -> bool`: Checks if a value has been successfully sent (or taken).
    *   `Receiver::recv(&mut self) -> ReceiveFuture<'_, T>`: Returns a future that resolves to the sent value or an error if sender drops.
    *   `Receiver::try_recv(&mut self) -> Result<T, TryRecvError>`: Attempts to receive the value non-blockingly.
    *   `Receiver::is_closed(&self) -> bool`: Checks if the channel is terminally closed (value taken, or senders dropped without sending).

## Error Handling

Fibre uses a clear set of error enums to signal the result of channel operations.

*   **`TrySendError<T>`:** Returned from `try_send`.
    *   `Full(T)`: The channel is full. The unsent item is returned.
    *   `Closed(T)`: The receiver was dropped. The unsent item is returned.
    *   `Sent(T)`: (Oneshot only) A value was already sent.
    *   Use `.into_inner()` to recover the value.

*   **`SendError`:** Returned from blocking/async `send`.
    *   `Closed`: The receiver was dropped.
    *   `Sent`: (Oneshot only) A value was already sent.

*   **`TryRecvError`:** Returned from `try_recv`.
    *   `Empty`: The channel is currently empty but not disconnected.
    *   `Disconnected`: The channel is empty and all senders have been dropped.

*   **`RecvError`:** Returned from blocking/async `recv`.
    *   `Disconnected`: The channel is empty and all senders have been dropped.

*   **`RecvErrorTimeout`:** Returned from `recv_timeout`.
    *   `Timeout`: The operation timed out before a value was received.
    *   `Disconnected`: The channel became disconnected during the wait.