| Crates.io | gardal |
| lib.rs | gardal |
| version | 0.0.1-alpha.7 |
| created_at | 2025-07-05 20:54:31.112977+00 |
| updated_at | 2025-09-09 16:42:44.621345+00 |
| description | A WIP performance-focused token-bucket rate limiting and throttling library |
| homepage | |
| repository | https://github.com/AhmedSoliman/gardal |
| max_upload_size | |
| id | 1739460 |
| size | 157,654 |
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.
Add this to your Cargo.toml:
[dependencies]
gardal = "0.0.1-alpha.4"
# For async support
gardal = { version = "0.0.1-alpha.4", features = ["async"] }
# For high-performance timing
gardal = { version = "0.0.1-alpha.4", features = ["quanta"] }
# For high-resolution async timers
gardal = { version = "0.0.1-alpha.4", features = ["async", "tokio-hrtime"] }
use gardal::{Limit, TokenBucket};
use nonzero_ext::nonzero;
// Create a token bucket: 10 tokens per second, burst of 20
let bucket = TokenBucket::new(Limit::per_second_and_burst(
nonzero!(10u32),
nonzero!(20u32),
));
// Consume 5 tokens
match bucket.consume(nonzero!(5u32)) {
Some(tokens) => println!("Consumed {} tokens", tokens.as_u64()),
None => println!("Not enough tokens available"),
}
use futures::{StreamExt, stream};
use gardal::futures::StreamExt as GardalStreamExt;
use gardal::{Limit, TokenBucket, AtomicSharedStorage, QuantaClock};
use nonzero_ext::nonzero;
#[tokio::main]
async fn main() {
let limit = Limit::per_second(nonzero!(5u32));
let bucket = TokenBucket::<AtomicSharedStorage, _>::from_parts(
limit,
QuantaClock::default()
);
let mut stream = stream::iter(1..=100)
.throttle(bucket)
.boxed();
while let Some(item) = stream.next().await {
println!("Processed item: {}", item);
}
}
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.
Gardal supports various rate limit configurations:
use gardal::Limit;
use nonzero_ext::nonzero;
// 10 requests per second
let limit = Limit::per_second(nonzero!(10u32));
// 10 requests per second with burst of 20
let limit = Limit::per_second_and_burst(nonzero!(10u32), nonzero!(20u32));
// 100 requests per minute
let limit = Limit::per_minute(nonzero!(100u32));
// 1000 requests per hour
let limit = Limit::per_hour(nonzero!(1000u32));
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 applicationsuse gardal::{TokenBucket, AtomicSharedStorage, Limit};
use nonzero_ext::nonzero;
// Explicitly specify storage type
let bucket = TokenBucket::<AtomicSharedStorage>::from_parts(
Limit::per_second(nonzero!(10u32)),
gardal::StdClock::default()
);
Gardal supports multiple clock implementations:
FastClock: High-performance quanta-based clock (requires quanta feature)StdClock: Standard library clock (default)TokioClock: Tokio-based clock for async applications (requires async feature)ManualClock: Manual clock for testingFor applications requiring precise timing in async contexts, enable the tokio-hrtime feature:
use futures::{StreamExt, stream};
use gardal::futures::StreamExt as GardalStreamExt;
use gardal::{Limit, TokenBucket};
use nonzero_ext::nonzero;
#[tokio::main]
async fn main() {
let limit = Limit::per_second(nonzero!(1000u32)); // High-frequency rate limiting
let bucket = TokenBucket::new(limit);
let mut stream = stream::iter(1..=10000)
.throttle(bucket)
.boxed();
// Uses tokio-hrtime for microsecond-precision delays
while let Some(item) = stream.next().await {
println!("Processed item: {}", item);
}
}
The tokio-hrtime feature provides:
Gardal is designed for high-performance scenarios:
Run benchmarks with:
cargo bench
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 limitingSee the examples/ directory for more usage patterns:
basic.rs: Basic token bucket usagefast_clock.rs: Using high-performance clocksstreams.rs: Async stream rate limitingGardal requires Rust 1.87.0 or later.
Apache License, Version 2.0 (LICENSE-APACHE)
Contributions are welcome! Please feel free to submit a Pull Request.