rate_guard/limits/
mod.rs

1//! Rate limit wrapper abstractions with Duration-based configuration.
2//!
3//! This module provides a unified RateLimit trait that wraps the core rate limiting
4//! algorithms from rate-guard-core. The wrappers provide a consistent interface
5//! while enabling Duration-based configuration and maintaining the diagnostic
6//! capabilities of the underlying implementations.
7//!
8//! The RateLimit trait serves as a thin wrapper around rate-guard-core
9//! implementations. It preserves both simple and verbose error reporting
10//! capabilities while providing a consistent interface that integrates
11//! time sources directly into the rate limiter.
12//!
13//! Available rate limiting algorithms:
14//! - TokenBucket: Allows bursts up to capacity with sustained rate
15//! - FixedWindowCounter: Fixed time windows with capacity limits
16//! - SlidingWindowCounter: Sliding windows with multiple buckets
17//! - ApproximateSlidingWindow: Memory-efficient approximation of sliding windows
18
19use rate_guard_core::types::Uint;
20use crate::{
21    SimpleRateLimitResult, RateLimitResult,
22    SimpleRateLimitError,
23};
24
25pub mod token_bucket;
26pub mod fixed_window_counter;
27pub mod sliding_window_counter;
28pub mod approximate_sliding_window;
29
30// Re-export the main types for convenience
31pub use token_bucket::{TokenBucket, TokenBucketBuilder};
32pub use fixed_window_counter::{FixedWindowCounter, FixedWindowCounterBuilder, PrecisionFixedWindowCounter};
33pub use sliding_window_counter::{SlidingWindowCounter, SlidingWindowCounterBuilder, PrecisionSlidingWindowCounter};
34pub use approximate_sliding_window::{ApproximateSlidingWindow, ApproximateSlidingWindowBuilder, PrecisionApproximateSlidingWindow};
35
36/// Trait for rate limiting operations with integrated time sources.
37///
38/// This trait provides a unified interface for all rate limiting algorithms,
39/// where each implementation contains its own time source and precision configuration.
40/// This eliminates the need for external time management and provides a clean,
41/// self-contained API.
42///
43/// Unlike the previous design that required passing elapsed Duration to each method,
44/// this trait integrates time source management directly into the rate limiter.
45/// Each implementation handles time acquisition and precision conversion internally.
46///
47/// All methods are self-contained and thread-safe, making them suitable for
48/// use in both single-threaded and multi-threaded environments.
49///
50/// # Examples
51///
52/// ```rust
53/// use rate_guard::{TokenBucket, TokenBucketBuilder, Millis, MockTimeSource, RateLimit, RateLimitError};
54/// use std::time::Duration;
55///
56/// // Create a rate limiter with builder pattern
57/// let bucket = TokenBucketBuilder::builder()
58///     .capacity(100)
59///     .refill_amount(10)
60///     .refill_every(Duration::from_millis(100))
61///     .with_time(MockTimeSource::new())
62///     .with_precision::<Millis>()
63///     .build()
64///     .unwrap();
65///
66/// // Use the rate limiter
67/// assert!(bucket.try_acquire(50).is_ok());
68/// assert_eq!(bucket.capacity_remaining().unwrap(), 50);
69/// ```
70pub trait RateLimit {
71    /// Attempts to acquire the specified number of tokens.
72    ///
73    /// This method provides fast-path rate limiting with minimal error information.
74    /// The rate limiter internally manages time acquisition and precision conversion.
75    /// Use this when you only need to know whether the request was allowed or denied.
76    ///
77    /// # Arguments
78    /// * `tokens` - Number of tokens to acquire
79    ///
80    /// # Returns
81    /// * `Ok(())` - Request was allowed and tokens were acquired
82    /// * `Err(SimpleRateLimitError)` - Request was denied with basic error information
83    ///
84    /// # Examples
85    ///
86    /// ```rust
87    /// # use rate_guard::{TokenBucket, TokenBucketBuilder, Nanos, MockTimeSource, RateLimit};
88    /// # use std::time::Duration;
89    /// # let bucket = TokenBucketBuilder::builder()
90    /// #     .capacity(100)
91    /// #     .refill_amount(10)
92    /// #     .refill_every(Duration::from_millis(100))
93    /// #     .with_time(MockTimeSource::new())
94    /// #     .with_precision::<Nanos>()
95    /// #     .build()
96    /// #     .unwrap();
97    /// 
98    /// // Try to acquire 30 tokens
99    /// match bucket.try_acquire(30) {
100    ///     Ok(()) => println!("Acquired 30 tokens successfully"),
101    ///     Err(_) => println!("Rate limited"),
102    /// }
103    /// ```
104    fn try_acquire(&self, tokens: Uint) -> SimpleRateLimitResult;
105
106    /// Attempts to acquire tokens with detailed diagnostic information.
107    ///
108    /// This method provides comprehensive error information including current
109    /// availability, retry timing, and other diagnostic details. The rate limiter
110    /// internally manages time acquisition and precision conversion.
111    /// Use this when you need to implement sophisticated retry logic or provide
112    /// detailed feedback to users.
113    ///
114    /// # Arguments
115    /// * `tokens` - Number of tokens to acquire
116    ///
117    /// # Returns
118    /// * `Ok(())` - Request was allowed and tokens were acquired
119    /// * `Err(RateLimitError)` - Request was denied with detailed diagnostics including Duration-based retry timing
120    ///
121    /// # Examples
122    ///
123    /// ```rust
124    /// # use rate_guard::{TokenBucket, TokenBucketBuilder, Nanos, MockTimeSource, RateLimit, RateLimitError};
125    /// # use std::time::Duration;
126    /// # let bucket = TokenBucketBuilder::builder()
127    /// #     .capacity(10)
128    /// #     .refill_amount(1)
129    /// #     .refill_every(Duration::from_secs(1))
130    /// #     .with_time(MockTimeSource::new())
131    /// #     .with_precision::<Nanos>()
132    /// #     .build()
133    /// #     .unwrap();
134    /// # bucket.try_acquire(10).unwrap(); // Use all tokens
135    /// 
136    /// // Try to acquire more tokens than available
137    /// match bucket.try_acquire_verbose(5) {
138    ///     Ok(()) => println!("Acquired tokens"),
139    ///     Err(RateLimitError::InsufficientCapacity { acquiring, available, retry_after }) => {
140    ///         println!("Need {} tokens, only {} available, retry after {:?}", 
141    ///                  acquiring, available, retry_after);
142    ///     }
143    ///     Err(e) => println!("Other error: {}", e),
144    /// }
145    /// ```
146    fn try_acquire_verbose(&self, tokens: Uint) -> RateLimitResult;
147
148    /// Returns the number of tokens currently available for acquisition.
149    ///
150    /// This method calculates the current remaining capacity of the rate limiter.
151    /// The rate limiter internally manages time acquisition and precision conversion.
152    /// The returned value represents how many tokens could be acquired immediately
153    /// without being rate limited.
154    ///
155    /// # Returns
156    /// The number of tokens currently available for acquisition, or an error
157    /// if the capacity cannot be determined (e.g., due to lock contention).
158    ///
159    /// # Examples
160    ///
161    /// ```rust
162    /// # use rate_guard::{TokenBucket, Nanos, MockTimeSource, RateLimit};
163    /// # use rate_guard::limits::TokenBucketBuilder;
164    /// # use std::time::Duration;
165    /// 
166    /// let bucket = TokenBucketBuilder::builder()
167    ///     .capacity(100)
168    ///     .refill_amount(10)
169    ///     .refill_every(Duration::from_millis(100))
170    ///     .with_time(MockTimeSource::new())
171    ///     .with_precision::<Nanos>()
172    ///     .build()
173    ///     .unwrap();
174    /// 
175    /// println!("Available tokens: {}", bucket.capacity_remaining().unwrap());
176    /// 
177    /// bucket.try_acquire(30).unwrap();
178    /// println!("After acquiring 30: {}", bucket.capacity_remaining().unwrap());
179    /// ```
180    fn capacity_remaining(&self) -> Result<Uint, SimpleRateLimitError>;
181}