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
//! # A more in-depth guide to `governor`
//!
//! Governor is a fork/rewrite/rebranding of the
//! [`ratelimit_meter`](https://crates.io/crates/ratelimit_meter) and
//! [`ratelimit_futures`](https://crates.io/crates/ratelimit_futures)
//! crates. Many of the things that worked there still work here, and
//! this guide's aim is to help you accomplish them.
//!
//! # Constructing a rate limiter
//!
//! Currently, only "direct" rate-limiters are supported - that is,
//! rate limiters that keep only a single state (most rate limiters in
//! the wild expose a "keyed" interface, keeping one state per key).
//!
//! Construction of rate limiters is designed to be mostly infallible,
//! given correctly-constructed parameters. To that end, `governor`
//! makes heavy use of the [`NonZeroU32`][std::num::NonZeroU32] type.
//!
//! To conveniently construct these nonzero numbers, use the
//! [`nonzero!`](../../nonzero_ext/macro.nonzero.html) macro.
//!
//! #### Quotas
//!
//! Each rate limiter has a quota: A rate of elements (could be API
//! requests, emails, phone calls... anything really) per unit of time (second,
//! minute, hour). Specify these in a [`Quota`][crate::Quota] object like so:
//!
//! ```rust
//! # use nonzero_ext::*;
//! use governor::Quota;
//! Quota::per_second(nonzero!(20u32));
//! ```
//!
//! #### Constructing a direct rate limiter
//!
//! To make a direct rate limiter, you have to construct a quota, as
//! above; and then use this to construct the rate limiter itself. In
//! `std` mode, this is easily accomplished like so:
//!
//! ```rust
//! # #[cfg(feature = "std")] fn main() {
//! # use nonzero_ext::*;
//! # use governor::{DirectRateLimiter, Quota};
//! DirectRateLimiter::new(Quota::per_second(nonzero!(50u32)));
//! # } #[cfg(not(feature = "std"))] fn main() {}
//! ```
//!
//! In `no_std` mode, there are is no default monotonic (or system)
//! clock available. To effectively limit rates, you will have to
//! either use the provided "fake" clock (which must be manually
//! advanced, and is mainly useful for tests), or implement the
//! `Clock` trait for your platform. Once that decision is made,
//! constructing a rate limiter with an explicit clock works like
//! this:
//!
//! ```rust
//! # use nonzero_ext::*;
//! # use governor::{clock::FakeRelativeClock, DirectRateLimiter, Quota};
//! let clock = FakeRelativeClock::default();
//! DirectRateLimiter::new_with_clock(Quota::per_second(nonzero!(50u32)), &clock);
//! ```
//!
//! # Data ownership and references to rate limiters
//!
//! `governor`'s rate limiter state is not hidden behind an [interior
//! mutability](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html)
//! pattern, and so it is perfectly valid to have multiple references
//! to a rate limiter in a program. Since its state lives in
//! [`AtomicU64`][std::sync::atomic::AtomicU64] integers (which do not
//! implement [`Clone`]), the rate limiters themselves can not be
//! cloned.
//!
//! # Usage in multiple threads
//!
//! Sharing references to a rate limiter across threads is completely
//! OK (rate limiters are Send and Sync by default), but there is a
//! problem: A rate limiter's lifetime might be up before a thread
//! ends, which would invalidate the reference.
//!
//! So, to use a rate limiter in multiple threads without lifetime
//! issues, there are two equally valid strategies:
//!
//! #### `crossbeam` scoped tasks
//!
//! The `crossbeam` crate's
//! [scopes](https://docs.rs/crossbeam/0.7.3/crossbeam/thread/struct.Scope.html#method.spawn)
//! allow code to guarantee that a thread spawned in a scope
//! terminates before the scope terminates. This allows using
//! stack-allocated variables. Here is an example test using crossbeam
//! scopes:
//!
//! ```rust
//! # use crossbeam;
//! # use nonzero_ext::*;
//! # use governor::{clock::FakeRelativeClock, DirectRateLimiter, Quota};
//! # use std::time::Duration;
//!
//! let mut clock = FakeRelativeClock::default();
//! let lim = DirectRateLimiter::new_with_clock(Quota::per_second(nonzero!(20u32)), &clock);
//! let ms = Duration::from_millis(1);
//!
//! crossbeam::scope(|scope| {
//!     for _i in 0..20 {
//!         scope.spawn(|_| {
//!             assert_eq!(Ok(()), lim.check());
//!         });
//!     }
//! })
//! .unwrap();
//! ```
//!
//! #### Wrapping the limiter in an [`Arc`][std::sync::Arc]
//!
//! The other method uses only the standard library: Wrapping the rate
//! limiter in an [`Arc`][std::sync::Arc] will keep the limiter alive
//! for as long as there exist references to it - perfect for passing
//! to threads.
//!
//! In this example, note that we're cloning what looks like the
//! limiter, once per thread -- but that is only what it looks
//! like. The thing that actually gets cloned is the `Arc`; the rate
//! limiter stays identical, only its references are duplicated (and
//! refcounts incremented).
//!
//! ```rust
//! # #[cfg(feature = "std")] fn main() {
//! # use nonzero_ext::*;
//! # use governor::{DirectRateLimiter, Quota};
//! # use std::time::Duration;
//! # use std::sync::Arc;
//! # use std::thread;
//! let bucket = Arc::new(DirectRateLimiter::new(Quota::per_second(nonzero!(20u32))));
//! for _i in 0..20 {
//!     let bucket = bucket.clone();
//!     thread::spawn(move || {
//!         assert_eq!(Ok(()), bucket.check());
//!     })
//!     .join()
//!     .unwrap();
//! }
//! # } #[cfg(not(feature = "std"))] fn main() {}
//! ```
//!