Gardal
A performance-focused token bucket rate limiting and throttling library for Rust with optional async support.
Name Origin: "Gardal" (جردل) is the Egyptian Arabic word for "bucket", reflecting the library's core token bucket algorithm.
Features
- High Performance: Optimized for minimal overhead with pluggable storage strategies
- Flexible Clock Sources: Support for standard, manual, fast (quanta), and Tokio clocks
- Async Support: Optional async/await support with stream rate limiting
- Thread-Safe: Multiple storage options including atomic and shared storage
- Zero-Cost Abstractions: Generic design allows compile-time optimization
- Configurable: Support for different rate limits (per second, minute, hour) and burst sizes
Quick Start
Add this to your Cargo.toml:
[]
= "0.0.1-alpha.9"
# For async support
= { = "0.0.1-alpha.9", = ["async"] }
# For high-performance timing
= { = "0.0.1-alpha.9", = ["quanta"] }
# For high-resolution async timers
= { = "0.0.1-alpha.9", = ["async", "tokio-hrtime"] }
Basic Usage
use ;
use nonzero;
// Create a token bucket: 10 tokens per second, burst of 20
let bucket = new;
// Consume 5 tokens
match bucket.consume
Async Stream Rate Limiting
use ;
use StreamExt as GardalStreamExt;
use ;
use nonzero;
async
If you want to have an unlimited stream in a type-compatible way, you can pass None::<TokenBucket> to rate_limit and that would avoid any overhead from the token bucket logic.
Rate Limit Configuration
Gardal supports various rate limit configurations:
use Limit;
use nonzero;
// 10 requests per second
let limit = per_second;
// 10 requests per second with burst of 20
let limit = per_second_and_burst;
// 100 requests per minute
let limit = per_minute;
// 1000 requests per hour
let limit = per_hour;
Storage Strategies
Choose the appropriate storage strategy for your use case:
AtomicStorage: Basic atomic storage for single-threaded or low-contention scenariosPaddedAtomicStorage: Cache-line padded atomic storage (default) for better performanceAtomicSharedStorage: Optimized for high-contention multi-threaded scenariosLocalStorage: Thread-local storage for single-threaded applications
use ;
use nonzero;
// Explicitly specify storage type
let bucket = new;
Clock Sources
Gardal supports multiple clock implementations:
FastClock: High-performance quanta-based clock (requiresquantafeature)StdClock: Standard library clock (default)TokioClock: Tokio-based clock for async applications (requiresasyncfeature)ManualClock: Manual clock for testing
High-Resolution Async Timers
For applications requiring precise timing in async contexts, enable the tokio-hrtime feature:
use ;
use StreamExt as GardalStreamExt;
use ;
use nonzero;
async
The tokio-hrtime feature provides:
- Microsecond precision: More accurate timing than standard Tokio timers
- Better performance: Optimized for high-frequency rate limiting scenarios
- Reduced jitter: More consistent timing behavior under load
Performance
Gardal is designed for high-performance scenarios:
- Zero-allocation token consumption in the fast path
- Lock-free atomic operations
- Pluggable storage strategies for different contention patterns
- Optional high-resolution timing with quanta
- Compile-time optimizations through generics
Run benchmarks with:
Features
async: Enables async/await support and stream rate limitingtokio: Enables Tokio clock integrationquanta: Enables high-performance timing with the quanta cratetokio-hrtime: Enables high-resolution async timers for microsecond-precision rate limiting
Examples
See the examples/ directory for more usage patterns:
basic.rs: Basic token bucket usagefast_clock.rs: Using high-performance clocksstreams.rs: Async stream rate limiting
Minimum Supported Rust Version (MSRV)
Gardal requires Rust 1.87.0 or later.
License
Apache License, Version 2.0 (LICENSE-APACHE)
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.