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
//! Direct rate limiters (those that can only hold one state). //! //! Rate limiters based on these types are constructed with //! [the `RateLimiter` constructors](../struct.RateLimiter.html#direct-in-memory-rate-limiters---constructors) use std::prelude::v1::*; use std::num::NonZeroU32; use crate::gcra::NotUntil; use crate::{clock, state::InMemoryState, NegativeMultiDecision, Quota}; /// The "this state store does not use keys" key type. /// /// It's possible to use this to create a "direct" rate limiter. It explicitly does not implement /// [`Hash`][std::hash::Hash] so that it is possible to tell apart from "hashable" key types. #[derive(PartialEq, Debug, Eq)] pub enum NotKeyed { /// The value given to state stores' methods. NonKey, } /// A trait for state stores that only keep one rate limiting state. /// /// This is blanket-implemented by all [`StateStore`]s with [`NotKeyed`] key associated types. pub trait DirectStateStore: StateStore<Key = NotKeyed> {} impl<T> DirectStateStore for T where T: StateStore<Key = NotKeyed> {} /// # Direct in-memory rate limiters - Constructors /// /// Here we construct an in-memory rate limiter that makes direct (un-keyed) /// rate-limiting decisions. Direct rate limiters can be used to /// e.g. regulate the transmission of packets on a single connection, /// or to ensure that an API client stays within a service's rate /// limit. #[cfg(feature = "std")] impl RateLimiter<NotKeyed, InMemoryState, clock::DefaultClock> { /// Constructs a new in-memory direct rate limiter for a quota with the default real-time clock. pub fn direct(quota: Quota) -> RateLimiter<NotKeyed, InMemoryState, clock::DefaultClock> { let clock = clock::DefaultClock::default(); Self::direct_with_clock(quota, &clock) } } impl<C> RateLimiter<NotKeyed, InMemoryState, C> where C: clock::Clock, { /// Constructs a new direct rate limiter for a quota with a custom clock. pub fn direct_with_clock(quota: Quota, clock: &C) -> Self { let state: InMemoryState = Default::default(); RateLimiter::new(quota, state, &clock) } } /// # Direct rate limiters - Manually checking cells impl<S, C> RateLimiter<NotKeyed, S, C> where S: DirectStateStore, C: clock::Clock, { /// Allow a single cell through the rate limiter. /// /// If the rate limit is reached, `check` returns information about the earliest /// time that a cell might be allowed through again. pub fn check(&self) -> Result<(), NotUntil<C::Instant>> { self.gcra .test_and_update(self.start, &NotKeyed::NonKey, &self.state, self.clock.now()) } /// Allow *only all* `n` cells through the rate limiter. /// /// This method can succeed in only one way and fail in two ways: /// * Success: If all `n` cells can be accommodated, it returns `Ok(())`. /// * Failure (but ok): Not all cells can make it through at the current time. /// The result is `Err(NegativeMultiDecision::BatchNonConforming(NotUntil))`, which can /// be interrogated about when the batch might next conform. /// * Failure (the batch can never go through): The rate limit quota's burst size is too low /// for the given number of cells to ever be allowed through. /// /// ### Performance /// This method diverges a little from the GCRA algorithm, using /// multiplication to determine the next theoretical arrival time, and so /// is not as fast as checking a single cell. pub fn check_n( &self, n: NonZeroU32, ) -> Result<(), NegativeMultiDecision<NotUntil<C::Instant>>> { self.gcra.test_n_all_and_update( self.start, &NotKeyed::NonKey, n, &self.state, self.clock.now(), ) } } #[cfg(feature = "std")] mod future; #[cfg(feature = "std")] pub use future::*; #[cfg(feature = "std")] mod sinks; #[cfg(feature = "std")] pub use sinks::*; #[cfg(feature = "std")] mod streams; use crate::state::{RateLimiter, StateStore}; #[cfg(feature = "std")] pub use streams::*;