rate-guard 0.1.0

Thread-safe rate limiting library with multiple algorithms and Duration-based configuration
Documentation
//! Rate limit wrapper abstractions with Duration-based configuration.
//!
//! This module provides a unified RateLimit trait that wraps the core rate limiting
//! algorithms from rate-guard-core. The wrappers provide a consistent interface
//! while enabling Duration-based configuration and maintaining the diagnostic
//! capabilities of the underlying implementations.
//!
//! The RateLimit trait serves as a thin wrapper around rate-guard-core
//! implementations. It preserves both simple and verbose error reporting
//! capabilities while providing a consistent interface that integrates
//! time sources directly into the rate limiter.
//!
//! Available rate limiting algorithms:
//! - TokenBucket: Allows bursts up to capacity with sustained rate
//! - FixedWindowCounter: Fixed time windows with capacity limits
//! - SlidingWindowCounter: Sliding windows with multiple buckets
//! - ApproximateSlidingWindow: Memory-efficient approximation of sliding windows

use rate_guard_core::types::Uint;
use crate::{
    SimpleRateLimitResult, RateLimitResult,
    SimpleRateLimitError,
};

pub mod token_bucket;
pub mod fixed_window_counter;
pub mod sliding_window_counter;
pub mod approximate_sliding_window;

// Re-export the main types for convenience
pub use token_bucket::{TokenBucket, TokenBucketBuilder};
pub use fixed_window_counter::{FixedWindowCounter, FixedWindowCounterBuilder, PrecisionFixedWindowCounter};
pub use sliding_window_counter::{SlidingWindowCounter, SlidingWindowCounterBuilder, PrecisionSlidingWindowCounter};
pub use approximate_sliding_window::{ApproximateSlidingWindow, ApproximateSlidingWindowBuilder, PrecisionApproximateSlidingWindow};

/// Trait for rate limiting operations with integrated time sources.
///
/// This trait provides a unified interface for all rate limiting algorithms,
/// where each implementation contains its own time source and precision configuration.
/// This eliminates the need for external time management and provides a clean,
/// self-contained API.
///
/// Unlike the previous design that required passing elapsed Duration to each method,
/// this trait integrates time source management directly into the rate limiter.
/// Each implementation handles time acquisition and precision conversion internally.
///
/// All methods are self-contained and thread-safe, making them suitable for
/// use in both single-threaded and multi-threaded environments.
///
/// # Examples
///
/// ```rust
/// use rate_guard::{TokenBucket, TokenBucketBuilder, Millis, MockTimeSource, RateLimit, RateLimitError};
/// use std::time::Duration;
///
/// // Create a rate limiter with builder pattern
/// let bucket = TokenBucketBuilder::builder()
///     .capacity(100)
///     .refill_amount(10)
///     .refill_every(Duration::from_millis(100))
///     .with_time(MockTimeSource::new())
///     .with_precision::<Millis>()
///     .build()
///     .unwrap();
///
/// // Use the rate limiter
/// assert!(bucket.try_acquire(50).is_ok());
/// assert_eq!(bucket.capacity_remaining().unwrap(), 50);
/// ```
pub trait RateLimit {
    /// Attempts to acquire the specified number of tokens.
    ///
    /// This method provides fast-path rate limiting with minimal error information.
    /// The rate limiter internally manages time acquisition and precision conversion.
    /// Use this when you only need to know whether the request was allowed or denied.
    ///
    /// # Arguments
    /// * `tokens` - Number of tokens to acquire
    ///
    /// # Returns
    /// * `Ok(())` - Request was allowed and tokens were acquired
    /// * `Err(SimpleRateLimitError)` - Request was denied with basic error information
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rate_guard::{TokenBucket, TokenBucketBuilder, Nanos, MockTimeSource, RateLimit};
    /// # use std::time::Duration;
    /// # let bucket = TokenBucketBuilder::builder()
    /// #     .capacity(100)
    /// #     .refill_amount(10)
    /// #     .refill_every(Duration::from_millis(100))
    /// #     .with_time(MockTimeSource::new())
    /// #     .with_precision::<Nanos>()
    /// #     .build()
    /// #     .unwrap();
    /// 
    /// // Try to acquire 30 tokens
    /// match bucket.try_acquire(30) {
    ///     Ok(()) => println!("Acquired 30 tokens successfully"),
    ///     Err(_) => println!("Rate limited"),
    /// }
    /// ```
    fn try_acquire(&self, tokens: Uint) -> SimpleRateLimitResult;

    /// Attempts to acquire tokens with detailed diagnostic information.
    ///
    /// This method provides comprehensive error information including current
    /// availability, retry timing, and other diagnostic details. The rate limiter
    /// internally manages time acquisition and precision conversion.
    /// Use this when you need to implement sophisticated retry logic or provide
    /// detailed feedback to users.
    ///
    /// # Arguments
    /// * `tokens` - Number of tokens to acquire
    ///
    /// # Returns
    /// * `Ok(())` - Request was allowed and tokens were acquired
    /// * `Err(RateLimitError)` - Request was denied with detailed diagnostics including Duration-based retry timing
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rate_guard::{TokenBucket, TokenBucketBuilder, Nanos, MockTimeSource, RateLimit, RateLimitError};
    /// # use std::time::Duration;
    /// # let bucket = TokenBucketBuilder::builder()
    /// #     .capacity(10)
    /// #     .refill_amount(1)
    /// #     .refill_every(Duration::from_secs(1))
    /// #     .with_time(MockTimeSource::new())
    /// #     .with_precision::<Nanos>()
    /// #     .build()
    /// #     .unwrap();
    /// # bucket.try_acquire(10).unwrap(); // Use all tokens
    /// 
    /// // Try to acquire more tokens than available
    /// match bucket.try_acquire_verbose(5) {
    ///     Ok(()) => println!("Acquired tokens"),
    ///     Err(RateLimitError::InsufficientCapacity { acquiring, available, retry_after }) => {
    ///         println!("Need {} tokens, only {} available, retry after {:?}", 
    ///                  acquiring, available, retry_after);
    ///     }
    ///     Err(e) => println!("Other error: {}", e),
    /// }
    /// ```
    fn try_acquire_verbose(&self, tokens: Uint) -> RateLimitResult;

    /// Returns the number of tokens currently available for acquisition.
    ///
    /// This method calculates the current remaining capacity of the rate limiter.
    /// The rate limiter internally manages time acquisition and precision conversion.
    /// The returned value represents how many tokens could be acquired immediately
    /// without being rate limited.
    ///
    /// # Returns
    /// The number of tokens currently available for acquisition, or an error
    /// if the capacity cannot be determined (e.g., due to lock contention).
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use rate_guard::{TokenBucket, Nanos, MockTimeSource, RateLimit};
    /// # use rate_guard::limits::TokenBucketBuilder;
    /// # use std::time::Duration;
    /// 
    /// let bucket = TokenBucketBuilder::builder()
    ///     .capacity(100)
    ///     .refill_amount(10)
    ///     .refill_every(Duration::from_millis(100))
    ///     .with_time(MockTimeSource::new())
    ///     .with_precision::<Nanos>()
    ///     .build()
    ///     .unwrap();
    /// 
    /// println!("Available tokens: {}", bucket.capacity_remaining().unwrap());
    /// 
    /// bucket.try_acquire(30).unwrap();
    /// println!("After acquiring 30: {}", bucket.capacity_remaining().unwrap());
    /// ```
    fn capacity_remaining(&self) -> Result<Uint, SimpleRateLimitError>;
}