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
//! # 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
//!
//! **Stable (`1.0.0`).** The public API is frozen until `2.0`. 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**. Every public type is `Send + Sync + 'static`, asserted
//! at compile time. The safety invariants — never over-admit, bounded memory —
//! are proved by `proptest` (per algorithm), `loom`, a multi-threaded stress
//! suite across every algorithm, an allocation audit, and an adversarial-traffic
//! suite, and the surface is validated through a representative gatekeeper
//! consumer.
//!
//! ```
//! # #[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
///
/// ```
/// // Carries a `major.minor.patch` SemVer core.
/// let version = rate_net::VERSION;
/// assert_eq!(version.split('.').count(), 3);
/// assert!(version.split('.').all(|part| !part.is_empty()));
/// ```
pub const VERSION: &str = env!;