rate-guard-core 0.2.2

Rate limiting library with multiple thread-safe algorithms
Documentation

rate-guard-core

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

Features

  • 5 Rate Limiting Algorithms: Token Bucket, Leaky Bucket, Fixed Window, Sliding Window, 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.2.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:

[dependencies]

rate-guard-core = { version = "0.2.2", default-features = false, features = ["tick_u128"] }

from Github

Add to your Cargo.toml:

[dependencies]

rate-guard-core = { git = "https://github.com/Kuanlin/rate-guard-core", tag = "v0.2.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:

[dependencies]

rate-guard-core = { git = "https://github.com/Kuanlin/rate-guard-core", tag = "v0.2.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::rate_limiters::TokenBucketCore;
// Allow 100 requests, refill 10 every 5 seconds
let limiter = TokenBucketCore::new(100, 5, 10); 
let current_tick = std::time::SystemTime::now() 
    .duration_since(std::time::UNIX_EPOCH)
    .unwrap()
    .as_secs();
match limiter.try_acquire_at(1, current_tick) {
    Ok(()) => println!("Request allowed!"),
    Err(e) => println!("Rate limited: {}", e),
}

Leaky Bucket

Great for maintaining steady traffic flow:

use rate_guard_core::rate_limiters::LeakyBucketCore;
// capacity = 50 tokens, refill = 5 tokens per 10 ticks
let limiter = LeakyBucketCore::new(50, 10, 5);
assert_eq!(limiter.try_acquire_at(10, 0), Ok(()));

Fixed Window Counter

use rate_guard_core::rate_limiters::FixedWindowCounterCore;
// capacity = 100 per fixed window, window size = 60 ticks
let limiter = FixedWindowCounterCore::new(100, 60);
assert_eq!(limiter.try_acquire_at(1, 30), Ok(()));

Sliding Window Counter

use rate_guard_core::rate_limiters::SlidingWindowCounterCore;
// Window of 100 tokens across 6 buckets of 10 ticks each (50 ticks window)
let limiter = SlidingWindowCounterCore::new(100, 10, 6);
assert_eq!(limiter.try_acquire_at(5, 25), Ok(()));

Approximate Sliding Window

(A Memory-Optimized Version: Sliding Window Counter)

formula: UsedCapacities = (1-X%) * lastWindowRequests + currentWindowRequests. (X is the propotion of request time within the current window.)

use rate_guard_core::rate_limiters::ApproximateSlidingWindowCore;
// Create ApproximateSlidingWindow limiter with capacity 100, window size 60 ticks
let limiter = ApproximateSlidingWindowCore::new(100, 60);
assert_eq!(limiter.try_acquire_at(10, 30), Ok(()));

Error Handling

All rate limiters return an AcquireResult:

use rate_guard_core::{RateLimitError, AcquireResult};
match limiter.try_acquire_at(1, tick) {
    Ok(()) => {
        // Request allowed
    },
    Err(RateLimitError::ExceedsCapacity) => {
        // Rate limit exceeded
    },
    Err(RateLimitError::ContentionFailure) => {
        // Lock contention, you can do sleep and retry here.
    },
    Err(RateLimitError::ExpiredTick) => {
        // Time went backwards
    },
}

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::rate_limiters::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(1, get_current_tick()) {
            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.