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}