1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! # rate-net
//!
//! A powerful, lock-free rate limiter for Rust. It answers one question as fast
//! as the hardware allows — *"is this key allowed right now?"* — and answers it
//! with a [`Decision`](#) (allow / deny plus a `retry-after`), across multiple
//! algorithms, while tracking per-key state under high contention. Per-key
//! state lives in a sharded concurrent map, so unrelated keys never contend and
//! throughput scales with core count; each key's bucket is lock-free and memory
//! is bounded by eviction, so a flood of unique keys hits a cap instead of
//! growing without limit.
//!
//! rate-net does not reimplement token-bucket accounting. It consumes
//! [`better-bucket`](https://crates.io/crates/better-bucket) for that and reads
//! time from [`clock-lib`](https://crates.io/crates/clock-lib), then adds the
//! per-key, multi-algorithm, retry-after machinery around them. It is the
//! anchor crate of the `-net` domain group and is consumed by gatekeepers (such
//! as `bouncer-io`) through the clean decision API — they call `check` and never
//! reach into its internal state.
//!
//! ## Status
//!
//! Pre-1.0 **beta** (`0.9.0`): the **API is frozen** (since `0.7.0`) and locked
//! in at the *type* level too — every public type is `Send + Sync + 'static`
//! and that is asserted at compile time. The integration shake-out at `0.8.0`
//! confirmed the surface is consumable through the public allow/deny API only,
//! and `0.9.0` widens the concurrency coverage: a single hot key under eight
//! threads against **every** algorithm admits exactly its quota — never more
//! (no over-admit, no torn updates) and never fewer (no lost decrements, no
//! deadlock). The five algorithms sit behind the one [`Limiter`] trait (token
//! bucket by default; the leaky bucket and window algorithms under the
//! `algorithms` feature), with the Tier-2 [`Builder`], an optional `AsyncLimiter`
//! await-until-ready layer (`async` feature), runnable
//! [examples](https://github.com/jamesgober/rate-net/tree/main/examples), and a
//! `criterion` suite. Per-key state lives in a purpose-built **sharded store**
//! (an existing-key [`check`](RateLimiter::check) takes only a shard read lock
//! plus the algorithm's atomic accounting, so unrelated keys never contend),
//! memory is **bounded by eviction**, and the steady-state check is
//! **allocation-free**. From here, the only changes before `1.0` are bug fixes
//! and documentation polish.
//!
//! ```
//! # #[cfg(feature = "std")] {
//! use rate_net::{RateLimiter, Decision};
//!
//! // 100 requests per second, per key.
//! let limiter = RateLimiter::per_second(100);
//!
//! match limiter.check("user:42") {
//! Decision::Allow => {
//! // allowed — serve the request
//! }
//! Decision::Deny { retry_after } => {
//! // denied — return 429 with `Retry-After: retry_after`
//! let _ = retry_after;
//! }
//! _ => {}
//! }
//! # }
//! ```
//!
//! ## Design goals
//!
//! - **Lock-free per key.** Each key's bucket delegates to `better-bucket`'s
//! atomic compare-and-swap core; no lock sits on the check path.
//! - **Sharded state.** Per-key state lives in a sharded concurrent map, so
//! unrelated keys land in different shards and never serialize on each other.
//! Throughput scales with cores; shard count is tunable.
//! - **Zero-allocation steady state.** A `check` on an existing key allocates
//! nothing; allocation happens only the first time a key is seen.
//! - **Bounded memory.** Idle keys are evicted (LRU/TTL) on an amortized,
//! incremental schedule that never stops the world on the hot path. A hostile
//! unique-key flood reaches the eviction cap and stays there.
//! - **Never over-admits.** For any key and window, admitted requests never
//! exceed the configured quota under any concurrent interleaving — proven per
//! algorithm with `loom` and `proptest`.
//! - **Lazy, runtime-free.** Refill and expiry are computed from a monotonic
//! clock on access; there is no background timer thread and the core has no
//! async-runtime dependency.
//!
//! ## Feature flags
//!
//! | Feature | Default | Description |
//! |---------|---------|-------------|
//! | `std` | yes | Standard library. Required for the sharded per-key store and eviction. With it off the crate is `no_std`; the scaffold then exposes only [`VERSION`], and the pared-down single-key mode follows in a later release. |
//! | `algorithms` | no | The full algorithm suite beyond the default token bucket: leaky bucket, fixed window, sliding-window log, sliding-window counter. |
//! | `async` | no | Optional async-friendly wrapper layer. Additive only — the core has no runtime dependency. |
// `no_std` for the library build when `std` is off, but always link `std` under
// `test` so the unit-test harness (and dev-dependencies) have what they need.
// The limiter surface requires the standard library (the concurrent per-key
// store, the clock-driven token bucket, and the domain error type). With `std`
// off the crate is no_std and exposes only `VERSION`.
pub use crateAlgorithm;
pub use crateAsyncLimiter;
pub use crateBuilder;
pub use crateDecision;
pub use crateRateLimiterError;
pub use crate;
pub use crateKey;
pub use crate;
pub use crateQuota;
/// The version of this crate, taken from `Cargo.toml` at compile time.
///
/// Exposed so a consumer can report the exact `rate-net` build it links
/// against — useful in diagnostics and version-skew checks across a dependency
/// tree.
///
/// # Examples
///
/// ```
/// // Reports the current 0.x series and carries a major.minor.patch core.
/// let version = rate_net::VERSION;
/// assert!(version.starts_with("0."));
/// assert_eq!(version.split('.').count(), 3);
/// ```
pub const VERSION: &str = env!;