# Linch
[](https://crates.io/crates/linch)
[](https://docs.rs/linch)
[](https://opensource.org/licenses/MIT)
**Linch** is a high-performance async/sync channel library for Rust that prioritizes **simplicity** and **efficiency**. While performance is important, Linch's primary focus is providing a clean, straightforward implementation that's easy to understand and use, with **seamless communication between sync and async contexts**.
> **Etymology**: The name "linch" is short for "**lined channel**" - like a concrete-lined channel that provides a smooth, reliable pathway for water flow. Similarly, Linch provides a smooth, reliable pathway for data flow between different parts of your application.
## Key Features
- ๐ **Mixed Sync/Async**: Send and receive both synchronously and asynchronously
- ๐ **Cross-Context Communication**: Seamlessly bridge sync and async code without blocking
- ๐ฏ **Simple Design**: Clean, minimal API that's easy to understand and integrate
- โก **High Performance**: Optimized for throughput and low latency
- ๐ **Select Operations**: Support for selecting over multiple channels
- ๐ฆ **Two Implementations**: Choose between the main channel and schannel variants
- ๐งต **Thread Safe**: Full support for multi-producer, multi-consumer scenarios
## Quick Start
Add this to your `Cargo.toml`:
```toml
[dependencies]
linch = "0.1"
```
### Basic Usage
```rust
use linch::channel;
// Create a bounded channel with capacity 10
let (sender, receiver) = channel(10);
// Send synchronously
sender.send(42).unwrap();
// Receive synchronously
let value = receiver.recv().unwrap();
assert_eq!(value, 42);
```
### Async Usage
```rust
use linch::channel;
#[tokio::main]
async fn main() {
let (sender, receiver) = channel(10);
// Send asynchronously
sender.send_async(42).await.unwrap();
// Receive asynchronously
let value = receiver.recv_async().await.unwrap();
assert_eq!(value, 42);
}
```
## Two Channel Implementations
Linch provides two channel implementations to suit different use cases:
### 1. Main Channel (`linch::channel`)
The primary implementation focuses on **simplicity and correctness** with efficient async handling:
```rust
use linch::channel;
let (tx, rx) = channel(100);
```
**When to use:**
- โ
General-purpose applications
- โ
When you want proper async/await integration
- โ
Applications with mixed sync/async workloads
- โ
Bridging sync and async contexts (e.g., sync threads communicating with async tasks)
- โ
When CPU efficiency matters during idle periods
- โ
Production applications requiring reliability
**Characteristics:**
- Uses proper waker-based async coordination
- CPU-efficient when channels are idle
- Slightly more complex internals for better async integration
- Supports select operations
### 2. SChannel (`linch::schannel`)
A **high-throughput** implementation optimized for maximum performance:
```rust
use linch::schannel;
let (tx, rx) = schannel::with_capacity(100);
```
**When to use:**
- โก Benchmarking against other channel implementations
- โก When maximum throughput is critical
- โก Applications that keep channels busy continuously
**Characteristics:**
- Uses active polling for async operations
- Optimized for scenarios where channels rarely stay empty
- Higher CPU usage during async operations
- Maximum performance for high-throughput scenarios
## Examples
### Cross-Context Communication
One of Linch's key strengths is enabling seamless communication between sync and async contexts:
```rust
use linch::channel;
use std::thread;
#[tokio::main]
async fn main() {
let (tx, rx) = channel(10);
// Spawn a synchronous thread (e.g., CPU-intensive work)
let tx_clone = tx.clone();
thread::spawn(move || {
for i in 0..5 {
// Synchronous send from thread
tx_clone.send(format!("Processed item {}", i)).unwrap();
// Simulate work
thread::sleep(std::time::Duration::from_millis(100));
}
});
// Receive asynchronously in async context without blocking
for _ in 0..5 {
let value = rx.recv_async().await.unwrap();
println!("Async task received: {}", value);
// Can continue with other async work here
}
}
```
You can also send from async contexts to sync contexts:
```rust
use linch::channel;
use std::thread;
#[tokio::main]
async fn main() {
let (tx, rx) = channel(10);
// Spawn a sync thread that receives
let handle = thread::spawn(move || {
while let Ok(value) = rx.recv() {
println!("Sync thread received: {}", value);
}
});
// Send from async context
for i in 0..5 {
tx.send_async(format!("Async message {}", i)).await.unwrap();
// Can do other async work between sends
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
}
drop(tx); // Close channel
handle.join().unwrap();
}
```
### Select Operations
```rust
use linch::{channel, Select};
#[tokio::main]
async fn main() {
let (tx1, rx1) = channel(1);
let (tx2, rx2) = channel(1);
// Send to both channels
tx1.send("Hello").unwrap();
tx2.send("World").unwrap();
// Select from multiple receivers
let mut sel = Select::new();
let idx1 = sel.recv(&rx1);
let idx2 = sel.recv(&rx2);
let op = sel.select();
match op.index() {
i if i == idx1 => {
let msg = op.recv(&rx1).unwrap();
println!("Received from channel 1: {}", msg);
},
i if i == idx2 => {
let msg = op.recv(&rx2).unwrap();
println!("Received from channel 2: {}", msg);
},
_ => unreachable!(),
}
}
```
### Stream Integration
The schannel implementation supports conversion to async streams:
```rust
use linch::schannel;
use futures::StreamExt;
#[tokio::main]
async fn main() {
let (tx, rx) = schannel::with_capacity(10);
// Send some values
for i in 0..5 {
tx.send(i).unwrap();
}
drop(tx); // Close the channel
// Convert to stream and collect
let values: Vec<_> = rx.into_stream().collect().await;
println!("Collected: {:?}", values);
}
```
## Performance Characteristics
Linch is designed with performance in mind, but **simplicity comes first**. The implementations are:
- **Zero-copy** where possible
- **Optimized** for both single and multi-threaded scenarios
- **Benchmarked** against other popular Rust channel libraries
### Benchmarking
The crate includes comprehensive benchmarks comparing against other channel implementations:
```bash
# Run all benchmarks
cargo bench
# Run specific benchmark categories
cargo bench congestion
cargo bench realistic_workload
```
See the [benchmark guide](BENCHMARK_GUIDE.md) for detailed performance analysis.
## Design Philosophy
Linch prioritizes:
1. **Simplicity**: Clean, understandable code that's easy to maintain and debug
2. **Cross-Context Communication**: Seamless bridging between sync and async code without complexity
3. **Correctness**: Proper async/await integration and memory safety
4. **Performance**: High throughput and low latency, but not at the expense of simplicity
5. **Flexibility**: Support for both sync and async patterns in the same channel
The goal is to provide a channel implementation that's both **easy to use** and **fast enough** for most applications, with particular focus on making sync/async interoperability effortless.
## API Reference
### Main Channel Functions
- `channel(capacity)` - Create a bounded channel
- `Sender::send(item)` - Send synchronously
- `Sender::send_async(item)` - Send asynchronously
- `Receiver::recv()` - Receive synchronously
- `Receiver::recv_async()` - Receive asynchronously
### SChannel Functions
- `schannel::with_capacity(capacity)` - Create a high-throughput channel
- `Sender::send_async(item)` - Send asynchronously with active polling
- `Receiver::recv_async()` - Receive asynchronously with active polling
- `Receiver::into_stream()` - Convert to async stream
### Select Operations
- `Select::new()` - Create a new select operation
- `Select::recv(receiver)` - Add receiver to select
- `Select::select()` - Wait for any operation to complete
## Error Handling
Both implementations use standard Rust error types:
- `SendError<T>` - Returned when all receivers are dropped
- `RecvError` - Returned when all senders are dropped
- `SendTimeoutError<T>` - Returned on send timeout
- `RecvTimeoutError` - Returned on receive timeout
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request. The project values:
- **Code clarity** over micro-optimizations
- **Comprehensive tests** for all features
- **Good documentation** with examples
- **Benchmark coverage** for performance-critical changes
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Acknowledgments
- Built on top of the excellent [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) library
- Inspired by Go's channels and Rust's async ecosystem
- The concrete-lined channel metaphor reflects the library's goal of providing reliable, efficient data pathways
- Thanks to the Rust community for feedback and contributions