Crate rate_guard_core

Source
Expand description

§rate-guard-core

A comprehensive rate limiting library for Rust applications with multiple thread-safe algorithms.

§Features

  • 4 Rate Limiting Algorithms: Token Bucket, Fixed Window Counter, Sliding Window Counter, and Approximate Sliding Window
  • Thread-Safe: All algorithms use non-blocking locks
  • Zero Dependencies: Lightweight with no external dependencies
  • Flexible Time: Works with any time unit via abstract “ticks”
  • Configurable Tick Precision: Compile-time feature flags allow choosing u64 (default) or u128 for tick units
  • Rust 1.60+: Compatible with older Rust versions

§Quick Start

§from crate.io

Add to your Cargo.toml:

[dependencies]
rate-guard-core = { version = "0.7.2" }

§from Github

Add to your Cargo.toml:

[dependencies]
rate-guard-core = { git = "https://github.com/Kuanlin/rate-guard-core", tag = "v0.7.2" }

§Tick Precision (u64 / u128)

By default, the crate uses u64 as the tick unit, allowing up to ~584 years of nanosecond-resolution time. If your application needs ultra-long durations or ultra-high precision, you can enable u128 support via feature flags:

§from crate.io

[dependencies]
rate-guard-core = { version = "0.7.2", default-features = false, features = ["tick-u128"] }

§from Github

[dependencies]
rate-guard-core = { git = "https://github.com/Kuanlin/rate-guard-core", tag = "v0.7.2", default-features = false, features = ["tick-u128"] }

§Usage Examples

§Token Bucket

Perfect for APIs that allow occasional bursts while maintaining average rate:

use rate_guard_core::cores::{TokenBucketCore, TokenBucketCoreConfig};

let config = TokenBucketCoreConfig {
    capacity: 100,
    refill_interval: 5,
    refill_amount: 10,
};

let limiter: TokenBucketCore = config.into();

§Fixed Window Counter

use rate_guard_core::cores::{FixedWindowCounterCore, FixedWindowCounterCoreConfig};

let config = FixedWindowCounterCoreConfig {
    capacity: 100,
    window_size: 60,
};

let limiter: FixedWindowCounterCore = config.into();

§Sliding Window Counter

use rate_guard_core::cores::{SlidingWindowCounterCore, SlidingWindowCounterCoreConfig};

let config = SlidingWindowCounterCoreConfig {
    capacity: 100,
    bucket_ticks: 10,
    bucket_count: 6,
};

let limiter: SlidingWindowCounterCore = config.into();

§Approximate Sliding Window

A memory-optimized version of sliding window counter.
Formula:
Used = (1 - X%) * lastWindow + currentWindow where X is the proportion of request time within the current window.

use rate_guard_core::cores::{ApproximateSlidingWindowCore, ApproximateSlidingWindowCoreConfig};

let config = ApproximateSlidingWindowCoreConfig {
    capacity: 100,
    window_ticks: 60,
};

let limiter: ApproximateSlidingWindowCore = config.into();

Both into() and from() are functionally equivalent in Rust.
into() is shorter and idiomatic; from() is more explicit and beginner-friendly.
These examples are duplicated to help both Rust newcomers and non-Rust readers understand the conversion logic.


§Error Handling

All limiters’ try_acquire_at returns SimpleRateLimitResult:

use rate_guard_core::{SimpleRateLimitError, SimpleRateLimitResult};
match limiter.try_acquire_at(tick, 1) {
    Ok(()) => {
        // Request allowed
    },
    Err(SimpleRateLimitError::InsufficientCapacity) => {
        // Rate limit exceeded
    },
    Err(SimpleRateLimitError::BeyondCapacity) => {
        // Acquiring too much
    },
    Err(SimpleRateLimitError::ExpiredTick) => {
        // Time went backwards
    },
    Err(SimpleRateLimitError::ContentionFailure) => {
        // Lock contention, you can do sleep and retry here.
    },
}

§Verbose Error Reporting

Each limiter also supports try_acquire_verbose_at(tick, tokens), which returns a VerboseRateLimitError with richer diagnostics:

  • ContentionFailure: Lock was unavailable
  • ExpiredTick { min_acceptable_tick }: Time went backwards
  • BeyondCapacity { acquiring, capacity }: Requested tokens exceed max
  • InsufficientCapacity { acquiring, available, retry_after_ticks }: Not enough tokens now, but suggests how long to wait before retrying
use rate_guard_core::{VerboseRateLimitError, VerboseRateLimitResult};

match limiter.try_acquire_verbose_at(tick, 5) {
    Ok(()) => {
        // Request allowed
    }
    Err(VerboseRateLimitError::InsufficientCapacity { retry_after_ticks, .. }) => {
        println!("Retry after {} ticks", retry_after_ticks);
    }
    Err(e) => {
        println!("Rate limit error: {:?}", e);
    }
}

try_acquire_verbose_at is useful for retry logic, logging, or adaptive throttling.


§Time Management

The library uses abstract “ticks” for time. You can map any time source:

// Seconds
let tick = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
// Milliseconds
let tick = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64;
// Custom time
let tick = my_monotonic_timer.elapsed_ticks();

§Thread Safety

use std::sync::Arc;
use std::thread;
use rate_guard_core::cores::TokenBucketCore;
let limiter = Arc::new(TokenBucketCore::new(100, 1, 10));
for _ in 0..10 {
    let limiter = limiter.clone();
    thread::spawn(move || {
        match limiter.try_acquire_at(get_current_tick(), 1) {
            Ok(()) => println!("Request processed"),
            Err(e) => println!("Rate limited: {}", e),
        }
    });
}

§License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.


§Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Re-exports§

pub use types::Uint;
pub use error::SimpleRateLimitError;
pub use error::VerboseRateLimitError;
pub use error::SimpleRateLimitResult;
pub use error::VerboseRateLimitResult;

Modules§

cores
Core rate limiting algorithm implementations.
error
error.rs Defines both simple and verbose rate limiting error/result types.
rate_limit
Core trait for rate limiter algorithms.
types
Unsigned integer type alias for rate limiter capacities and ticks.

Macros§

other_window
Toggles between window indices 0 and 1.