rate-guard 0.1.0

Thread-safe rate limiting library with multiple algorithms and Duration-based configuration
Documentation
#![cfg(feature = "std-time")]

//! Requires: --features=std-time

use rate_guard::{
    Nanos, StdTimeSource, RateLimit, RateLimitError,
    limits::TokenBucketBuilder,
};
use std::time::Duration;
use std::thread::sleep;

/// Simple sync example using StdTimeSource.
/// Attempts to acquire tokens and prints result every 50ms.
fn main() {
    let bucket = TokenBucketBuilder::builder()
        .capacity(100)
        .refill_amount(10)
        .refill_every(Duration::from_millis(300))
        .with_time(StdTimeSource::new())
        .with_precision::<Nanos>()
        .build()
        .unwrap();

    println!("Starting token bucket (sync)");

    for i in 0..20 {
        match acquire_with_retry(&bucket, 20, 5) {
            Ok(()) => println!("[{:02}] Allowed", i),
            Err(e) => println!("[{:02}] Failed: {}", i, e),
        }
        sleep(Duration::from_millis(50));
    }

    println!("Done.");
}

/// Retry logic for sync environment
fn acquire_with_retry(
    limiter: &impl RateLimit,
    tokens: u64,
    max_retries: usize,
) -> Result<(), RateLimitError> {
    for attempt in 0..max_retries {
        match limiter.try_acquire_verbose(tokens) {
            Ok(()) => return Ok(()),
            Err(RateLimitError::InsufficientCapacity { retry_after, .. }) => {
                if attempt < max_retries - 1 {
                    println!(
                        "Attempt {}: Insufficient capacity, retrying in {:?}...",
                        attempt + 1,
                        retry_after.as_nanos()
                    );
                    sleep(retry_after);
                } else {
                    return Err(RateLimitError::InsufficientCapacity {
                        acquiring: tokens,
                        available: 0,
                        retry_after,
                    });
                }
            }
            Err(RateLimitError::ContentionFailure) => {
                std::thread::yield_now(); // Give up CPU slice
            }
            Err(e) => return Err(e),
        }
    }

    Err(RateLimitError::ContentionFailure)
}