rate_guard_core/lib.rs
1//! # `rate-guard-core`
2//! A comprehensive rate limiting library for Rust applications with multiple thread-safe algorithms.
3//!
4//! ## Features
5//! - **5 Rate Limiting Algorithms**: Token Bucket, Leaky Bucket, Fixed Window Counter, Sliding Window Counter, and Approximate Sliding Window
6//! - **Thread-Safe**: All algorithms use non-blocking locks
7//! - **Zero Dependencies**: Lightweight with no external dependencies
8//! - **Flexible Time**: Works with any time unit via abstract “ticks”
9//! - **Configurable Tick Precision**: Compile-time feature flags allow choosing `u64` (default) or `u128` for tick units
10//! - **Rust 1.60+**: Compatible with older Rust versions
11//!
12//! ---
13//!
14//! ## Quick Start
15//!
16//! ### from crate.io
17//! Add to your `Cargo.toml`:
18//! ```toml
19//! [dependencies]
20//! rate-guard-core = { version = "0.5.2" }
21//! ```
22//!
23//! ### from Github
24//! Add to your `Cargo.toml`:
25//! ```toml
26//! [dependencies]
27//! rate-guard-core = { git = "https://github.com/Kuanlin/rate-guard-core", tag = "v0.5.2" }
28//! ```
29//!
30//! ---
31//!
32//! ## Tick Precision (u64 / u128)
33//! By default, the crate uses `u64` as the tick unit, allowing up to ~584 years of nanosecond-resolution time.
34//! If your application needs ultra-long durations or ultra-high precision, you can enable `u128` support via feature flags:
35//!
36//! ### from crate.io
37//! ```toml
38//! [dependencies]
39//! rate-guard-core = { version = "0.5.2", default-features = false, features = ["tick_u128"] }
40//! ```
41//!
42//! ### from Github
43//! ```toml
44//! [dependencies]
45//! rate-guard-core = { git = "https://github.com/Kuanlin/rate-guard-core", tag = "v0.5.2", default-features = false, features = ["tick_u128"] }
46//! ```
47//!
48//! ---
49//!
50//! ## Usage Examples
51//!
52//! ### Token Bucket
53//! Perfect for APIs that allow occasional bursts while maintaining average rate:
54//!
55//! ```rust
56//! use rate_guard_core::cores::{TokenBucketCore, TokenBucketCoreConfig};
57//!
58//! let config = TokenBucketCoreConfig {
59//! capacity: 100,
60//! refill_interval: 5,
61//! refill_amount: 10,
62//! };
63//!
64//! let limiter: TokenBucketCore = config.into();
65//!
66//! ```
67//!
68//! ---
69//!
70//! ### Leaky Bucket
71//! Great for maintaining steady traffic flow:
72//!
73//! ```rust
74//! use rate_guard_core::cores::{LeakyBucketCore, LeakyBucketCoreConfig};
75//!
76//! let config = LeakyBucketCoreConfig {
77//! capacity: 50,
78//! leak_interval: 10,
79//! leak_amount: 5,
80//! };
81//!
82//! let limiter: LeakyBucketCore = config.into();
83//!
84//! ```
85//!
86//! ---
87//!
88//! ### Fixed Window Counter
89//!
90//! ```rust
91//! use rate_guard_core::cores::{FixedWindowCounterCore, FixedWindowCounterCoreConfig};
92//!
93//! let config = FixedWindowCounterCoreConfig {
94//! capacity: 100,
95//! window_size: 60,
96//! };
97//!
98//! let limiter: FixedWindowCounterCore = config.into();
99//! ```
100//!
101//! ---
102//!
103//! ### Sliding Window Counter
104//!
105//! ```rust
106//! use rate_guard_core::cores::{SlidingWindowCounterCore, SlidingWindowCounterCoreConfig};
107//!
108//! let config = SlidingWindowCounterCoreConfig {
109//! capacity: 100,
110//! bucket_ticks: 10,
111//! bucket_count: 6,
112//! };
113//!
114//! let limiter: SlidingWindowCounterCore = config.into();
115//! ```
116//!
117//! ---
118//!
119//! ### Approximate Sliding Window
120//! A memory-optimized version of sliding window counter.
121//! Formula:
122//! `Used = (1 - X%) * lastWindow + currentWindow` where X is the proportion of request time within the current window.
123//!
124//! ```rust
125//! use rate_guard_core::cores::{ApproximateSlidingWindowCore, ApproximateSlidingWindowCoreConfig};
126//!
127//! let config = ApproximateSlidingWindowCoreConfig {
128//! capacity: 100,
129//! window_ticks: 60,
130//! };
131//!
132//! let limiter: ApproximateSlidingWindowCore = config.into();
133//! ```
134//!
135//! > Both `into()` and `from()` are functionally equivalent in Rust.
136//! > `into()` is shorter and idiomatic; `from()` is more explicit and beginner-friendly.
137//! > These examples are duplicated to help both Rust newcomers and non-Rust readers understand the conversion logic.
138//!
139//!
140//! ---
141//!
142//! ### Approximate Sliding Window
143//! A memory-optimized version of sliding window counter.
144//! Formula:
145//! `Used = (1 - X%) * lastWindow + currentWindow` where X is the proportion of request time within the current window.
146//!
147//! ```rust
148//! use rate_guard_core::cores::{ApproximateSlidingWindowCore, ApproximateSlidingWindowCoreConfig};
149//!
150//! let config = ApproximateSlidingWindowCoreConfig {
151//! capacity: 100,
152//! window_ticks: 60,
153//! };
154//! let limiter: ApproximateSlidingWindowCore = ApproximateSlidingWindowCore::from(config);
155//! ```
156//!
157//! ---
158//!
159//! ## Error Handling
160//! All limiters' try_acquire_at returns `SimpleRateLimitResult`:
161//! ```Rust
162//! use rate_guard_core::{SimpleRateLimitError, SimpleRateLimitResult};
163//! match limiter.try_acquire_at(tick, 1) {
164//! Ok(()) => {
165//! // Request allowed
166//! },
167//! Err(SimpleRateLimitError::InsufficientCapacity) => {
168//! // Rate limit exceeded
169//! },
170//! Err(SimpleRateLimitError::BeyondCapacity) => {
171//! // Acquiring too much
172//! },
173//! Err(SimpleRateLimitError::ExpiredTick) => {
174//! // Time went backwards
175//! },
176//! Err(SimpleRateLimitError::ContentionFailure) => {
177//! // Lock contention, you can do sleep and retry here.
178//! },
179//! }
180//! ```
181//!
182//! ---
183//!
184//! ## Verbose Error Reporting
185//!
186//! Each limiter also supports `try_acquire_verbose_at(tick, tokens)`, which returns a `VerboseRateLimitError` with richer diagnostics:
187//!
188//! - `ContentionFailure`: Lock was unavailable
189//! - `ExpiredTick { min_acceptable_tick }`: Time went backwards
190//! - `BeyondCapacity { acquiring, capacity }`: Requested tokens exceed max
191//! - `InsufficientCapacity { acquiring, available, retry_after_ticks }`: Not enough tokens now, but suggests how long to wait before retrying
192//!
193//! ```Rust
194//! use rate_guard_core::{VerboseRateLimitError, VerboseRateLimitResult};
195//!
196//! match limiter.try_acquire_verbose_at(tick, 5) {
197//! Ok(()) => {
198//! // Request allowed
199//! }
200//! Err(VerboseRateLimitError::InsufficientCapacity { retry_after_ticks, .. }) => {
201//! println!("Retry after {} ticks", retry_after_ticks);
202//! }
203//! Err(e) => {
204//! println!("Rate limit error: {:?}", e);
205//! }
206//! }
207//! ```
208//!
209//! > `try_acquire_verbose_at` is useful for retry logic, logging, or adaptive throttling.
210//!
211//! ---
212//!
213//! ## Time Management
214//! The library uses abstract “ticks” for time. You can map any time source:
215//! ```Rust
216//! // Seconds
217//! let tick = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
218//! // Milliseconds
219//! let tick = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64;
220//! // Custom time
221//! let tick = my_monotonic_timer.elapsed_ticks();
222//! ```
223//!
224//! ---
225//!
226//! ## Thread Safety
227//! ```Rust
228//! use std::sync::Arc;
229//! use std::thread;
230//! use rate_guard_core::cores::TokenBucketCore;
231//! let limiter = Arc::new(TokenBucketCore::new(100, 1, 10));
232//! for _ in 0..10 {
233//! let limiter = limiter.clone();
234//! thread::spawn(move || {
235//! match limiter.try_acquire_at(get_current_tick(), 1) {
236//! Ok(()) => println!("Request processed"),
237//! Err(e) => println!("Rate limited: {}", e),
238//! }
239//! });
240//! }
241//! ```
242//!
243//! ---
244//!
245//! ## License
246//! Licensed under either of Apache License, Version 2.0 or MIT license at your option.
247//!
248//! ---
249//!
250//! ## Contributing
251//! Contributions are welcome! Please feel free to submit a Pull Request.
252
253pub mod types;
254pub mod cores;
255pub mod rate_limit;
256pub mod error; // 新增
257
258pub use types::Uint;
259pub use error::{
260 SimpleRateLimitError, VerboseRateLimitError,
261 SimpleRateLimitResult, VerboseRateLimitResult,
262};