Thanks to visit codestin.com
Credit goes to lib.rs

8 releases

Uses new Rust 2024

0.0.1-alpha.9 Dec 8, 2025
0.0.1-alpha.7 Sep 9, 2025
0.0.1-alpha.2 Jul 13, 2025

#106 in Asynchronous

Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App

2,117 downloads per month

Apache-2.0 OR MIT

115KB
1.5K SLoC

Gardal

Crates.io Documentation CI License

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:

[dependencies]
gardal = "0.0.1-alpha.9"

# For async support
gardal = { version = "0.0.1-alpha.9", features = ["async"] }

# For high-performance timing
gardal = { version = "0.0.1-alpha.9", features = ["quanta"] }

# For high-resolution async timers
gardal = { version = "0.0.1-alpha.9", features = ["async", "tokio-hrtime"] }

Basic Usage

use gardal::{Limit, LocalTokenBucket, StdClock};
use nonzero_ext::nonzero;

// Create a token bucket: 10 tokens per second, burst of 20
let bucket = LocalTokenBucket::new(Limit::per_second_and_burst(
    nonzero!(10u32),
    nonzero!(20u32),
), StdClock);

// Consume 5 tokens
match bucket.consume(nonzero!(5u32)) {
    Some(tokens) => println!("Consumed {} tokens", tokens.as_u64()),
    None => println!("Not enough tokens available"),
}

Async Stream Rate Limiting

use futures::{StreamExt, stream};
use gardal::futures::StreamExt as GardalStreamExt;
use gardal::{Limit, SharedTokenBucket, QuantaClock};
use nonzero_ext::nonzero;

#[tokio::main]
async fn main() {
    let limit = Limit::per_second(nonzero!(5u32));
    let bucket = SharedTokenBucket::new(
        limit, 
        QuantaClock,
    );

    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.

Rate Limit Configuration

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));

Storage Strategies

Choose the appropriate storage strategy for your use case:

  • AtomicStorage: Basic atomic storage for single-threaded or low-contention scenarios
  • PaddedAtomicStorage: Cache-line padded atomic storage (default) for better performance
  • AtomicSharedStorage: Optimized for high-contention multi-threaded scenarios
  • LocalStorage: Thread-local storage for single-threaded applications
use gardal::{TokenBucket, StdClock, AtomicSharedStorage, Limit};
use nonzero_ext::nonzero;

// Explicitly specify storage type
let bucket = TokenBucket::<AtomicSharedStorage, _>::new(
    Limit::per_second(nonzero!(10u32)),
    StdClock
);

Clock Sources

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 testing

High-Resolution Async Timers

For 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, SharedTokenBucket, TokioClock};
use nonzero_ext::nonzero;

#[tokio::main]
async fn main() {
    let limit = Limit::per_second(nonzero!(1000u32)); // High-frequency rate limiting
    let bucket = SharedTokenBucket::new(limit, TokioClock);

    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:

  • 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:

cargo bench

Features

  • async: Enables async/await support and stream rate limiting
  • tokio: Enables Tokio clock integration
  • quanta: Enables high-performance timing with the quanta crate
  • tokio-hrtime: Enables high-resolution async timers for microsecond-precision rate limiting

Examples

See the examples/ directory for more usage patterns:

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.

Dependencies

~0–29MB
~353K SLoC