From 0142066d729189fd74c713dc7002b6c6573491c9 Mon Sep 17 00:00:00 2001 From: Ahmed Farghal Date: Fri, 5 Sep 2025 15:07:29 +0100 Subject: [PATCH] API name from rate-limiting streams to throttling --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 34 ++++++++-------- benches/throughput.rs | 10 ++--- examples/basic.rs | 4 +- examples/fast_clock.rs | 4 +- examples/streams.rs | 13 +++--- examples/weighted_stream.rs | 16 ++++---- src/bucket.rs | 71 ++++++++++++++++----------------- src/clock.rs | 20 +++++----- src/error.rs | 8 ++-- src/futures/mod.rs | 76 +++++++++++++++++------------------- src/futures/stream.rs | 72 +++++++++++++++++----------------- src/lib.rs | 10 ++--- src/limit.rs | 34 ++++++++-------- src/storage/atomic.rs | 8 ++-- src/storage/local.rs | 4 +- src/storage/padded_atomic.rs | 8 ++-- src/tokens.rs | 4 +- 19 files changed, 196 insertions(+), 204 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f11bfcc..a1fd4b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,7 +275,7 @@ dependencies = [ [[package]] name = "gardal" -version = "0.0.1-alpha.3" +version = "0.0.1-alpha.5" dependencies = [ "criterion", "futures", diff --git a/Cargo.toml b/Cargo.toml index fda1036..879ffba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gardal" -version = "0.0.1-alpha.4" +version = "0.0.1-alpha.5" edition = "2024" license = "Apache-2.0 OR MIT" authors = ["Ahmed Farghal "] diff --git a/README.md b/README.md index 32e3f27..c21cea7 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,11 @@ gardal = { version = "0.0.1-alpha.4", features = ["async", "tokio-hrtime"] } ### Basic Usage ```rust -use gardal::{RateLimit, TokenBucket}; +use gardal::{Limit, TokenBucket}; use nonzero_ext::nonzero; // Create a token bucket: 10 tokens per second, burst of 20 -let bucket = TokenBucket::new(RateLimit::per_second_and_burst( +let bucket = TokenBucket::new(Limit::per_second_and_burst( nonzero!(10u32), nonzero!(20u32), )); @@ -60,20 +60,20 @@ match bucket.consume(nonzero!(5u32)) { ```rust use futures::{StreamExt, stream}; -use gardal::futures::RateLimitedStreamExt; -use gardal::{RateLimit, TokenBucket, AtomicSharedStorage, QuantaClock}; +use gardal::futures::StreamExt as GardalStreamExt; +use gardal::{Limit, TokenBucket, AtomicSharedStorage, QuantaClock}; use nonzero_ext::nonzero; #[tokio::main] async fn main() { - let limit = RateLimit::per_second(nonzero!(5u32)); + let limit = Limit::per_second(nonzero!(5u32)); let bucket = TokenBucket::::from_parts( limit, QuantaClock::default() ); let mut stream = stream::iter(1..=100) - .rate_limit(bucket) + .throttle(bucket) .boxed(); while let Some(item) = stream.next().await { @@ -89,20 +89,20 @@ If you want to have an unlimited stream in a type-compatible way, you can pass ` Gardal supports various rate limit configurations: ```rust -use gardal::RateLimit; +use gardal::Limit; use nonzero_ext::nonzero; // 10 requests per second -let limit = RateLimit::per_second(nonzero!(10u32)); +let limit = Limit::per_second(nonzero!(10u32)); // 10 requests per second with burst of 20 -let limit = RateLimit::per_second_and_burst(nonzero!(10u32), nonzero!(20u32)); +let limit = Limit::per_second_and_burst(nonzero!(10u32), nonzero!(20u32)); // 100 requests per minute -let limit = RateLimit::per_minute(nonzero!(100u32)); +let limit = Limit::per_minute(nonzero!(100u32)); // 1000 requests per hour -let limit = RateLimit::per_hour(nonzero!(1000u32)); +let limit = Limit::per_hour(nonzero!(1000u32)); ``` ## Storage Strategies @@ -115,12 +115,12 @@ Choose the appropriate storage strategy for your use case: - **`LocalStorage`**: Thread-local storage for single-threaded applications ```rust -use gardal::{TokenBucket, AtomicSharedStorage, RateLimit}; +use gardal::{TokenBucket, AtomicSharedStorage, Limit}; use nonzero_ext::nonzero; // Explicitly specify storage type let bucket = TokenBucket::::from_parts( - RateLimit::per_second(nonzero!(10u32)), + Limit::per_second(nonzero!(10u32)), gardal::StdClock::default() ); ``` @@ -140,17 +140,17 @@ For applications requiring precise timing in async contexts, enable the `tokio-h ```rust use futures::{StreamExt, stream}; -use gardal::futures::RateLimitedStreamExt; -use gardal::{RateLimit, TokenBucket}; +use gardal::futures::StreamExt as GardalStreamExt; +use gardal::{Limit, TokenBucket}; use nonzero_ext::nonzero; #[tokio::main] async fn main() { - let limit = RateLimit::per_second(nonzero!(1000u32)); // High-frequency rate limiting + let limit = Limit::per_second(nonzero!(1000u32)); // High-frequency rate limiting let bucket = TokenBucket::new(limit); let mut stream = stream::iter(1..=10000) - .rate_limit(bucket) + .throttle(bucket) .boxed(); // Uses tokio-hrtime for microsecond-precision delays diff --git a/benches/throughput.rs b/benches/throughput.rs index d99efeb..45eb9cb 100644 --- a/benches/throughput.rs +++ b/benches/throughput.rs @@ -3,14 +3,14 @@ use std::time::Duration; use criterion::{Criterion, Throughput, criterion_group, criterion_main}; use gardal::{ - AtomicStorage, FastClock, LocalStorage, ManualClock, PaddedAtomicStorage, QuantaClock, - RateLimit, StdClock, TokenBucket, + AtomicStorage, FastClock, Limit, LocalStorage, ManualClock, PaddedAtomicStorage, QuantaClock, + StdClock, TokenBucket, }; use nonzero_ext::nonzero; fn bench_consume(c: &mut Criterion) { let clock = quanta::Clock::new(); - let limit = RateLimit::per_second(nonzero!(10_000u32)); + let limit = Limit::per_second(nonzero!(10_000u32)); let _quanta_thread = quanta::Upkeep::new_with_clock(Duration::from_micros(10), clock.clone()) .start() .unwrap(); @@ -80,7 +80,7 @@ fn multi_threaded(c: &mut Criterion) { .start() .unwrap(); let clock = FastClock::new(clock); - let limit = RateLimit::per_second(nonzero!(10_000u32)); + let limit = Limit::per_second(nonzero!(10_000u32)); let mut group = c.benchmark_group("multi_threaded"); group .throughput(Throughput::Elements(1)) @@ -138,7 +138,7 @@ fn multi_threaded2(c: &mut Criterion) { .start() .unwrap(); let clock = FastClock::new(clock); - let limit = RateLimit::per_second(nonzero!(50u32)); + let limit = Limit::per_second(nonzero!(50u32)); let mut group = c.benchmark_group("multi_threaded2"); group .throughput(Throughput::Elements(1)) diff --git a/examples/basic.rs b/examples/basic.rs index 1eeb223..7537a9b 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -1,10 +1,10 @@ use std::time::Duration; -use gardal::{RateLimit, TokenBucket}; +use gardal::{Limit, TokenBucket}; use nonzero_ext::nonzero; fn main() { - let tb = TokenBucket::new(RateLimit::per_second_and_burst( + let tb = TokenBucket::new(Limit::per_second_and_burst( nonzero!(10u32), nonzero!(20u32), )); diff --git a/examples/fast_clock.rs b/examples/fast_clock.rs index 1ed0945..d03cb01 100644 --- a/examples/fast_clock.rs +++ b/examples/fast_clock.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use gardal::{FastClock, RateLimit, TokenBucket}; +use gardal::{FastClock, Limit, TokenBucket}; use nonzero_ext::nonzero; fn main() { @@ -10,7 +10,7 @@ fn main() { .start() .unwrap(); let clock = FastClock::new(clock); - let limit = RateLimit::per_second_and_burst(nonzero!(10u32), nonzero!(20u32)); + let limit = Limit::per_second_and_burst(nonzero!(10u32), nonzero!(20u32)); let tb = TokenBucket::with_clock(limit, clock); // after two seconds bucket should be full println!("sleeping for 2 seconds..."); diff --git a/examples/streams.rs b/examples/streams.rs index 03cbe91..1c1a529 100644 --- a/examples/streams.rs +++ b/examples/streams.rs @@ -2,15 +2,16 @@ use std::sync::Arc; use std::sync::atomic::AtomicU64; use std::time::Duration; -use futures::{StreamExt, stream}; -use gardal::futures::RateLimitedStreamExt; -use gardal::{PaddedAtomicSharedStorage, RateLimit, TokenBucket, TokioClock}; +use futures::StreamExt; +use futures::stream; +use gardal::futures::StreamExt as GardalStreamExt; +use gardal::{Limit, PaddedAtomicSharedStorage, TokenBucket, TokioClock}; use nonzero_ext::nonzero; use tokio::task::JoinSet; #[tokio::main(flavor = "multi_thread")] async fn main() { - let limit = RateLimit::per_second_and_burst(nonzero!(1000000u32), nonzero!(100u32)); + let limit = Limit::per_second_and_burst(nonzero!(1000000u32), nonzero!(100u32)); let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); @@ -23,9 +24,9 @@ async fn main() { let bucket = bucket.clone(); let global_processed = global_processed.clone(); async move { - let mut stream1 = std::pin::pin!(stream::repeat(1).rate_limit(bucket)); + let mut stream1 = std::pin::pin!(stream::repeat(1).throttle(bucket)); // for unthrottled stream those have identical performance. - // let mut stream1 = std::pin::pin!(stream::repeat(1).rate_limit(None::)); + // let mut stream1 = std::pin::pin!(stream::repeat(1).throttle(None::)); // let mut stream1 = std::pin::pin!(stream::iter(1..=1000000000)); let mut iter_start = tokio::time::Instant::now(); let mut processed = 0; diff --git a/examples/weighted_stream.rs b/examples/weighted_stream.rs index ef6607e..8139953 100644 --- a/examples/weighted_stream.rs +++ b/examples/weighted_stream.rs @@ -1,6 +1,6 @@ use futures::stream; -use gardal::futures::{RateLimitedStreamExt, WeightedStream}; -use gardal::{LocalStorage, RateLimit, TokenBucket, TokioClock}; +use gardal::futures::{StreamExt as GardalStreamExt, WeightedStream}; +use gardal::{Limit, LocalStorage, TokenBucket, TokioClock}; use nonzero_ext::nonzero; use std::num::NonZeroU32; use tokio_stream::StreamExt; @@ -36,8 +36,8 @@ async fn main() { let stream = stream::iter(tasks); - // Create a rate limit: 5 tokens per second with a burst of 25 - let limit = RateLimit::per_second_and_burst(nonzero!(5u32), nonzero!(25u32)); + // Create a throttling limit: 5 tokens per second with a burst of 25 + let limit = Limit::per_second_and_burst(nonzero!(5u32), nonzero!(25u32)); let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); // Create a weighted stream where each task consumes tokens based on its size @@ -46,8 +46,8 @@ async fn main() { NonZeroU32::new(task.size as u32).unwrap_or(nonzero!(1u32)) }); - println!("Processing tasks with weighted rate limiting..."); - println!("Rate limit: 5 tokens/second, burst: 25 tokens"); + println!("Processing tasks with weighted throttling..."); + println!("Throttling: 5 tokens/second, burst: 25 tokens"); println!(); let start = std::time::Instant::now(); @@ -75,11 +75,11 @@ async fn main() { let tasks2 = vec!["short", "medium_length", "very_long_string_here", "x"]; let stream2 = stream::iter(tasks2); - let limit2 = RateLimit::per_second_and_burst(nonzero!(3u32), nonzero!(25u32)); + let limit2 = Limit::per_second_and_burst(nonzero!(3u32), nonzero!(25u32)); let bucket2 = TokenBucket::::from_parts(limit2, TokioClock::default()); // Use the extension trait to create a weighted stream - let weighted_stream2 = stream2.rate_limit_weighted(bucket2, |text: &&str| { + let weighted_stream2 = stream2.throttle_weighted(bucket2, |text: &&str| { // Consume tokens based on string length NonZeroU32::new(text.len() as u32).unwrap_or(nonzero!(1u32)) }); diff --git a/src/bucket.rs b/src/bucket.rs index d2e0075..f790230 100644 --- a/src/bucket.rs +++ b/src/bucket.rs @@ -8,7 +8,7 @@ use crate::error::{ExceededBurstCapacity, RateLimited}; use crate::storage::atomic::AtomicStorage; use crate::storage::padded_atomic::PaddedAtomicStorage; use crate::storage::{TimeStorage, TokenAcquisition, TokenBucketStorage}; -use crate::{Clock, RateLimit, StdClock, Tokens}; +use crate::{Clock, Limit, StdClock, Tokens}; pub const UNLIMITED_BUCKET: Option = const { None }; @@ -26,10 +26,10 @@ pub const UNLIMITED_BUCKET: Option = const { None }; /// # Examples /// /// ```rust -/// use gardal::{TokenBucket, RateLimit}; +/// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// -/// let limit = RateLimit::per_second_and_burst( +/// let limit = Limit::per_second_and_burst( /// NonZeroU32::new(10).unwrap(), /// NonZeroU32::new(20).unwrap() /// ); @@ -44,7 +44,7 @@ pub const UNLIMITED_BUCKET: Option = const { None }; pub struct TokenBucket { bucket: TokenBucketStorage, clock: C, - limit: RateLimit, + limit: Limit, } impl TokenBucket { @@ -59,13 +59,13 @@ impl TokenBucket { /// # Examples /// /// ```rust - /// use gardal::{TokenBucket, RateLimit}; + /// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second(NonZeroU32::new(100).unwrap()); + /// let limit = Limit::per_second(NonZeroU32::new(100).unwrap()); /// let bucket = TokenBucket::new(limit); /// ``` - pub fn new(limit: RateLimit) -> Self { + pub fn new(limit: Limit) -> Self { TokenBucket::::from_parts(limit, StdClock::default()) } } @@ -84,14 +84,14 @@ impl TokenBucket { /// # Examples /// /// ```rust - /// use gardal::{TokenBucket, RateLimit, ManualClock}; + /// use gardal::{TokenBucket, Limit, ManualClock}; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second(NonZeroU32::new(10).unwrap()); + /// let limit = Limit::per_second(NonZeroU32::new(10).unwrap()); /// let clock = ManualClock::new(0.0); /// let bucket = TokenBucket::with_clock(limit, clock); /// ``` - pub fn with_clock(limit: RateLimit, clock: C) -> Self { + pub fn with_clock(limit: Limit, clock: C) -> Self { let storage = PaddedAtomicStorage::new(clock.now()); Self { bucket: TokenBucketStorage::::new(storage), @@ -111,7 +111,7 @@ impl TokenBucket { /// /// * `limit` - The rate and burst configuration for the bucket /// * `clock` - The clock implementation to use for timing - pub fn from_parts(limit: RateLimit, clock: C) -> Self { + pub fn from_parts(limit: Limit, clock: C) -> Self { // let storage = S::new(clock.now()); let storage = S::new(0.0); Self { @@ -128,7 +128,7 @@ impl TokenBucket { /// # Arguments /// /// * `limit` - The new rate and burst configuration - pub fn reset(&mut self, limit: RateLimit) { + pub fn reset(&mut self, limit: Limit) { let now = self.clock.now(); let available = self .bucket @@ -149,7 +149,7 @@ impl TokenBucket { /// # Returns /// /// A new token bucket with the updated configuration - pub fn update_limit(self, limit: RateLimit) -> Self { + pub fn update_limit(self, limit: Limit) -> Self { let now = self.clock.now(); let available = self .bucket @@ -188,10 +188,10 @@ impl TokenBucket { /// # Examples /// /// ```rust - /// use gardal::{TokenBucket, RateLimit}; + /// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second(NonZeroU32::new(10).unwrap()); + /// let limit = Limit::per_second(NonZeroU32::new(10).unwrap()); /// let bucket = TokenBucket::new(limit); /// /// if let Some(tokens) = bucket.consume(NonZeroU32::new(5).unwrap()) { @@ -254,10 +254,10 @@ impl TokenBucket { /// # Examples /// /// ```rust - /// use gardal::{TokenBucket, RateLimit}; + /// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second(NonZeroU32::new(10).unwrap()); + /// let limit = Limit::per_second(NonZeroU32::new(10).unwrap()); /// let bucket = TokenBucket::new(limit); /// /// match bucket.try_consume(NonZeroU32::new(5).unwrap()) { @@ -306,10 +306,10 @@ impl TokenBucket { /// # Examples /// /// ```rust - /// use gardal::{TokenBucket, RateLimit}; + /// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second(NonZeroU32::new(10).unwrap()); + /// let limit = Limit::per_second(NonZeroU32::new(10).unwrap()); /// let bucket = TokenBucket::new(limit); /// /// // Request 100 tokens, but only get what's available @@ -336,10 +336,10 @@ impl TokenBucket { /// # Examples /// /// ```rust - /// use gardal::{TokenBucket, RateLimit}; + /// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second(NonZeroU32::new(10).unwrap()); + /// let limit = Limit::per_second(NonZeroU32::new(10).unwrap()); /// let bucket = TokenBucket::new(limit); /// /// // Return 5 tokens to the bucket @@ -369,10 +369,10 @@ impl TokenBucket { /// # Examples /// /// ```rust - /// use gardal::{TokenBucket, RateLimit}; + /// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second_and_burst( + /// let limit = Limit::per_second_and_burst( /// NonZeroU32::new(10).unwrap(), /// NonZeroU32::new(20).unwrap() /// ); @@ -479,8 +479,8 @@ impl TokenBucket { /// /// # Returns /// - /// Reference to the [`RateLimit`] configuration - pub fn limit(&self) -> &RateLimit { + /// Reference to the [`Limit`] configuration + pub fn limit(&self) -> &Limit { &self.limit } @@ -507,7 +507,7 @@ mod tests { fn basics() { let clock = Arc::new(ManualClock::default()); // initially, the bucket is empty - let limit = RateLimit::per_second_and_burst(nonzero!(10u32), nonzero!(20u32)); + let limit = Limit::per_second_and_burst(nonzero!(10u32), nonzero!(20u32)); let tb = TokenBucket::::with_clock(limit, Arc::clone(&clock)); // initially empty assert!(tb.consume(nonzero!(1u32)).is_none()); @@ -535,7 +535,7 @@ mod tests { fn basics_dynamic() { let clock = Arc::new(ManualClock::default()); // initially, the bucket is empty - let limit = RateLimit::per_second_and_burst(nonzero!(10u32), nonzero!(20u32)); + let limit = Limit::per_second_and_burst(nonzero!(10u32), nonzero!(20u32)); let mut tb = TokenBucket::::with_clock(limit, Arc::clone(&clock)); // initially empty assert!(tb.consume(nonzero!(1u32)).is_none()); @@ -545,10 +545,7 @@ mod tests { assert_eq!(10.0, tb.available()); assert_eq!(tb.balance(), tb.available()); // change the rate, burst, and reset the available tokens in the bucket - tb.reset(RateLimit::per_second_and_burst( - nonzero!(1u32), - nonzero!(50u32), - )); + tb.reset(Limit::per_second_and_burst(nonzero!(1u32), nonzero!(50u32))); assert_eq!(10.0, tb.available()); assert_eq!(10.0, tb.balance()); assert_eq!(1.0, tb.limit().rate_per_second()); @@ -562,7 +559,7 @@ mod tests { fn fractional() { let clock = Arc::new(ManualClock::default()); // initially, the bucket is empty - let limit = RateLimit::per_minute(nonzero!(30u32)).with_burst(nonzero!(20u32)); + let limit = Limit::per_minute(nonzero!(30u32)).with_burst(nonzero!(20u32)); let tb = TokenBucket::::with_clock(limit, Arc::clone(&clock)); // initially empty assert!(tb.consume(nonzero!(1u32)).is_none()); @@ -591,7 +588,7 @@ mod tests { #[test] fn saturating_consume() { let clock = Arc::new(ManualClock::default()); - let limit = RateLimit::per_second_and_burst(nonzero!(5u32), nonzero!(10u32)); + let limit = Limit::per_second_and_burst(nonzero!(5u32), nonzero!(10u32)); let tb = TokenBucket::::with_clock(limit, Arc::clone(&clock)); clock.set(1.0); // after one second, we have 5 tokens available, so that's what we can consume, but we can @@ -609,7 +606,7 @@ mod tests { #[test] fn wait_to_consume() { let clock = Arc::new(ManualClock::default()); - let limit = RateLimit::per_minute(nonzero!(30u32)).with_burst(nonzero!(10u32)); + let limit = Limit::per_minute(nonzero!(30u32)).with_burst(nonzero!(10u32)); let tb = TokenBucket::::with_clock(limit, Arc::clone(&clock)); // at t=0 bucket empty; borrow 5 tokens should require waiting for 10.0 seconds. Note that // we didn't consume anything as a result. @@ -626,7 +623,7 @@ mod tests { #[test] fn borrow_future() { let clock = Arc::new(ManualClock::default()); - let limit = RateLimit::per_minute(nonzero!(30u32)).with_burst(nonzero!(10u32)); + let limit = Limit::per_minute(nonzero!(30u32)).with_burst(nonzero!(10u32)); let tb = TokenBucket::::with_clock(limit, Arc::clone(&clock)); // at t=0 bucket empty; borrow 5 tokens should require waiting for 10.0 seconds let maybe_wait = tb.consume_with_borrow(nonzero!(5u32)); @@ -677,7 +674,7 @@ mod tests { fn concurrent_consume_owned() { // shared with arc and atomic (owned) let clock = Arc::new(ManualClock::default()); - let limit = RateLimit::per_second_and_burst(nonzero!(1000u32), nonzero!(10_000u32)); + let limit = Limit::per_second_and_burst(nonzero!(1000u32), nonzero!(10_000u32)); let tb = TokenBucket::::with_clock(limit, Arc::clone(&clock)); clock.set(10.0); let tb = std::sync::Arc::new(tb); @@ -701,7 +698,7 @@ mod tests { fn concurrent_consume() { // shared with atomic (reference) let clock = Arc::new(ManualClock::default()); - let limit = RateLimit::per_second_and_burst(nonzero!(1000u32), nonzero!(10_000u32)); + let limit = Limit::per_second_and_burst(nonzero!(1000u32), nonzero!(10_000u32)); let tb = TokenBucket::::with_clock(limit, Arc::clone(&clock)); std::thread::scope(|s| { clock.set(10.0); diff --git a/src/clock.rs b/src/clock.rs index 9739339..b82145e 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -70,10 +70,10 @@ pub trait Clock { /// # Examples /// /// ```rust -/// use gardal::{TokenBucket, RateLimit, StdClock}; +/// use gardal::{TokenBucket, Limit, StdClock}; /// use std::num::NonZeroU32; /// -/// let limit = RateLimit::per_second(NonZeroU32::new(100).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(100).unwrap()); /// let clock = StdClock::default(); /// let bucket = TokenBucket::with_clock(limit, clock); /// ``` @@ -108,10 +108,10 @@ impl Clock for StdClock { /// ```rust /// # #[cfg(feature = "quanta")] /// # { -/// use gardal::{TokenBucket, RateLimit, QuantaClock}; +/// use gardal::{TokenBucket, Limit, QuantaClock}; /// use std::num::NonZeroU32; /// -/// let limit = RateLimit::per_second(NonZeroU32::new(100).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(100).unwrap()); /// let clock = QuantaClock::default(); /// let bucket = TokenBucket::with_clock(limit, clock); /// # } @@ -158,10 +158,10 @@ impl Clock for QuantaClock { /// ```rust /// # #[cfg(feature = "tokio")] /// # { -/// use gardal::{TokenBucket, RateLimit, TokioClock}; +/// use gardal::{TokenBucket, Limit, TokioClock}; /// use std::num::NonZeroU32; /// -/// let limit = RateLimit::per_second(NonZeroU32::new(100).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(100).unwrap()); /// let clock = TokioClock::default(); /// let bucket = TokenBucket::with_clock(limit, clock); /// # } @@ -204,10 +204,10 @@ impl Clock for TokioClock { /// ```rust /// # #[cfg(feature = "quanta")] /// # { -/// use gardal::{TokenBucket, RateLimit, FastClock}; +/// use gardal::{TokenBucket, Limit, FastClock}; /// use std::num::NonZeroU32; /// -/// let limit = RateLimit::per_second(NonZeroU32::new(1000).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(1000).unwrap()); /// let clock = FastClock::default(); /// let bucket = TokenBucket::with_clock(limit, clock); /// # } @@ -261,11 +261,11 @@ impl Clock for FastClock { /// # Examples /// /// ```rust -/// use gardal::{TokenBucket, RateLimit, ManualClock}; +/// use gardal::{TokenBucket, Limit, ManualClock}; /// use std::num::NonZeroU32; /// use std::sync::Arc; /// -/// let limit = RateLimit::per_second(NonZeroU32::new(10).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(10).unwrap()); /// let clock = Arc::new(ManualClock::new(0.0)); /// let bucket = TokenBucket::with_clock(limit, Arc::clone(&clock)); /// diff --git a/src/error.rs b/src/error.rs index 861039c..f56ae89 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,10 +10,10 @@ use crate::clock::Nanos; /// # Examples /// /// ```rust -/// use gardal::{TokenBucket, RateLimit}; +/// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// -/// let limit = RateLimit::per_second(NonZeroU32::new(1).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(1).unwrap()); /// let bucket = TokenBucket::new(limit); /// /// match bucket.try_consume_one() { @@ -36,10 +36,10 @@ pub struct RateLimited { /// # Examples /// /// ```rust -/// use gardal::{TokenBucket, RateLimit}; +/// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// -/// let limit = RateLimit::per_second_and_burst( +/// let limit = Limit::per_second_and_burst( /// NonZeroU32::new(10).unwrap(), /// NonZeroU32::new(20).unwrap() /// ); diff --git a/src/futures/mod.rs b/src/futures/mod.rs index 6042730..a363e61 100644 --- a/src/futures/mod.rs +++ b/src/futures/mod.rs @@ -1,29 +1,29 @@ -//! Async utilities for rate limiting with futures and streams. +//! Async utilities for throttling with futures and streams. //! -//! This module provides async-friendly wrappers and utilities for rate limiting +//! This module provides async-friendly wrappers and utilities for throttling //! in async contexts. It requires the "async" feature to be enabled. //! //! # Features //! -//! - [`RateLimitedStream`] - Rate limit any stream -//! - [`RateLimitedStreamExt`] - Extension trait for easy stream rate limiting +//! - [`ThrottledStream`] - Throttle any stream +//! - [`StreamExt`] - Extension trait for easy stream throttling //! //! # Examples //! //! ```rust //! # #[cfg(feature = "async")] //! # { -//! use gardal::{TokenBucket, RateLimit}; -//! use gardal::futures::RateLimitedStreamExt; +//! use gardal::{TokenBucket, Limit}; +//! use gardal::futures::StreamExt; //! use futures::stream; //! use std::num::NonZeroU32; //! //! # async fn example() { -//! let limit = RateLimit::per_second(NonZeroU32::new(10).unwrap()); +//! let limit = Limit::per_second(NonZeroU32::new(10).unwrap()); //! let bucket = TokenBucket::new(limit); //! //! let stream = stream::iter(0..100) -//! .rate_limit(Some(bucket)); +//! .throttle(Some(bucket)); //! # } //! # } //! ``` @@ -31,7 +31,7 @@ mod stream; mod timer; -pub use stream::{RateLimitedStream, WeightedStream}; +pub use stream::{ThrottledStream, WeightedStream}; use futures::Stream; use std::num::NonZeroU32; @@ -39,9 +39,9 @@ use std::num::NonZeroU32; use crate::storage::TimeStorage; use crate::{Clock, TokenBucket}; -/// Extension trait for adding rate limiting to any stream. +/// Extension trait for adding throttling to any stream. /// -/// This trait provides a convenient way to apply rate limiting to existing streams +/// This trait provides a convenient way to apply throttling to existing streams /// without having to manually wrap them. /// /// # Examples @@ -49,77 +49,74 @@ use crate::{Clock, TokenBucket}; /// ```rust /// # #[cfg(feature = "async")] /// # { -/// use gardal::{TokenBucket, RateLimit}; -/// use gardal::futures::RateLimitedStreamExt; +/// use gardal::{TokenBucket, Limit}; +/// use gardal::futures::StreamExt; /// use futures::stream; /// use std::num::NonZeroU32; /// /// # async fn example() { -/// let limit = RateLimit::per_second(NonZeroU32::new(5).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(5).unwrap()); /// let bucket = TokenBucket::new(limit); /// -/// let rate_limited = stream::iter(1..=10) -/// .rate_limit(Some(bucket)); +/// let throttled = stream::iter(1..=10) +/// .throttle(Some(bucket)); /// # } /// # } /// ``` -pub trait RateLimitedStreamExt +pub trait StreamExt where S: Stream, ST: TimeStorage, C: Clock, { - /// Applies rate limiting to this stream using the provided token bucket. + /// Applies throttling to this stream using the provided token bucket. /// /// # Arguments /// - /// * `bucket` - The token bucket to use for rate limiting. Pass `None` to disable rate limiting. + /// * `bucket` - The token bucket to use for throttling. Pass `None` to disable throttling. /// /// # Returns /// - /// A [`RateLimitedStream`] that wraps this stream with rate limiting - fn rate_limit( - self, - bucket: impl Into>>, - ) -> RateLimitedStream; + /// A [`ThrottledStream`] that wraps this stream with throttling + fn throttle(self, bucket: impl Into>>) -> ThrottledStream; - /// Applies weighted rate limiting to this stream using the provided token bucket. + /// Applies weighted throttling to this stream using the provided token bucket. /// /// Each item in the stream can consume a different number of tokens based on the - /// weight function. This allows for more sophisticated rate limiting where different + /// weight function. This allows for more sophisticated throttling where different /// items have different costs. /// /// # Arguments /// - /// * `bucket` - The token bucket to use for rate limiting + /// * `bucket` - The token bucket to use for throttling /// * `weight_fn` - A function that determines how many tokens each item consumes /// /// # Returns /// - /// A [`WeightedStream`] that wraps this stream with weighted rate limiting + /// A [`WeightedStream`] that wraps this stream with weighted throttling /// /// # Examples /// /// ```rust /// # #[cfg(feature = "async")] /// # { - /// use gardal::{TokenBucket, RateLimit}; - /// use gardal::futures::RateLimitedStreamExt; + /// use gardal::{TokenBucket, Limit}; + /// use gardal::futures::StreamExt; /// use futures::stream; /// use std::num::NonZeroU32; /// /// # async fn example() { - /// let limit = RateLimit::per_second(NonZeroU32::new(10).unwrap()); + /// let limit = Limit::per_second(NonZeroU32::new(10).unwrap()); /// let bucket = TokenBucket::new(limit); /// - /// let rate_limited = stream::iter(vec!["small", "large", "medium"]) - /// .rate_limit_weighted(bucket, |item: &&str| { + /// let throttled = stream::iter(vec!["small", "large", "medium"]) + /// .throttle_weighted(bucket, |item: &&str| { /// NonZeroU32::new(item.len() as u32).unwrap_or(NonZeroU32::new(1).unwrap()) /// }); /// # } /// # } /// ``` - fn rate_limit_weighted( + fn throttle_weighted( self, bucket: TokenBucket, weight_fn: F, @@ -128,20 +125,17 @@ where F: Fn(&S::Item) -> NonZeroU32; } -impl RateLimitedStreamExt for S +impl StreamExt for S where S: Stream, ST: TimeStorage, C: Clock, { - fn rate_limit( - self, - bucket: impl Into>>, - ) -> RateLimitedStream { - RateLimitedStream::new(self, bucket) + fn throttle(self, bucket: impl Into>>) -> ThrottledStream { + ThrottledStream::new(self, bucket) } - fn rate_limit_weighted( + fn throttle_weighted( self, bucket: TokenBucket, weight_fn: F, diff --git a/src/futures/stream.rs b/src/futures/stream.rs index 9785847..285fcb2 100644 --- a/src/futures/stream.rs +++ b/src/futures/stream.rs @@ -7,14 +7,14 @@ use futures::Stream; use pin_project_lite::pin_project; use super::timer::{Sleep, sleep}; -use crate::RateLimit; +use crate::Limit; use crate::storage::TimeStorage; use crate::{bucket::TokenBucket, clock::Clock}; #[cfg(not(feature = "tokio-hrtime"))] use tokio::time::Instant; pin_project! { - /// A stream wrapper that applies rate limiting using a token bucket. + /// A stream wrapper that applies throttling using a token bucket. /// /// This stream consumes one token per item and will delay items when /// tokens are not available. It uses borrowing from future capacity @@ -23,18 +23,18 @@ pin_project! { /// # Examples /// /// ```rust - /// use gardal::{TokenBucket, RateLimit}; - /// use gardal::futures::RateLimitedStream; + /// use gardal::{TokenBucket, Limit}; + /// use gardal::futures::ThrottledStream; /// use futures::stream; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second(NonZeroU32::new(10).unwrap()); + /// let limit = Limit::per_second(NonZeroU32::new(10).unwrap()); /// let bucket = TokenBucket::new(limit); /// let stream = stream::iter(0..100); /// - /// let rate_limited = RateLimitedStream::new(stream, bucket); + /// let throttled = ThrottledStream::new(stream, bucket); /// ``` - pub struct RateLimitedStream + pub struct ThrottledStream where S: Stream, ST: TimeStorage, @@ -48,7 +48,7 @@ pin_project! { } } -impl RateLimitedStream +impl ThrottledStream where S: Stream, ST: TimeStorage, @@ -58,8 +58,8 @@ where /// /// # Arguments /// - /// * `stream` - The underlying stream to rate limit - /// * `bucket` - The token bucket to use for rate limiting + /// * `stream` - The underlying stream to throttle + /// * `bucket` - The token bucket to use for throttling pub fn new(stream: S, bucket: impl Into>>) -> Self { Self { stream, @@ -68,8 +68,8 @@ where } } - /// Returns a reference to the current rate limit configuration. - pub fn limit(&self) -> Option<&RateLimit> { + /// Returns a reference to the current throttling configuration. + pub fn limit(&self) -> Option<&Limit> { self.bucket.as_ref().map(|b| b.limit()) } @@ -99,7 +99,7 @@ where } } -impl Stream for RateLimitedStream +impl Stream for ThrottledStream where S: Stream, ST: TimeStorage, @@ -155,7 +155,7 @@ where } pin_project! { - /// A stream that is rate limited by a token bucket with weighted consumption. + /// A stream that is throttled by a token bucket with weighted consumption. /// Each item can consume a different number of tokens based on a weight function. pub struct WeightedStream where @@ -185,19 +185,19 @@ where /// /// # Arguments /// - /// * `stream` - The underlying stream to rate limit - /// * `bucket` - The token bucket for rate limiting + /// * `stream` - The underlying stream to throttle + /// * `bucket` - The token bucket for throttling /// * `weight_fn` - A function that determines how many tokens each item consumes /// /// # Examples /// /// ```rust /// use gardal::futures::WeightedStream; - /// use gardal::{LocalStorage, RateLimit, TokioClock, TokenBucket}; + /// use gardal::{LocalStorage, Limit, TokioClock, TokenBucket}; /// use futures::stream; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second_and_burst(NonZeroU32::new(10).unwrap(), NonZeroU32::new(10).unwrap()); + /// let limit = Limit::per_second_and_burst(NonZeroU32::new(10).unwrap(), NonZeroU32::new(10).unwrap()); /// let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); /// /// let stream = stream::iter(vec!["small", "large", "medium"]); @@ -215,8 +215,8 @@ where } } - /// Returns the current rate limit. - pub fn limit(&self) -> &RateLimit { + /// Returns the current throttling limit. + pub fn limit(&self) -> &Limit { self.bucket.limit() } @@ -298,7 +298,7 @@ where #[cfg(all(test, not(feature = "tokio-hrtime")))] mod tests { use super::*; - use crate::RateLimit; + use crate::Limit; use crate::clock::TokioClock; use crate::storage::local::LocalStorage; use std::time::Duration; @@ -311,10 +311,10 @@ mod tests { async fn test_throttled_stream() { let start = tokio::time::Instant::now(); let stream = stream::iter(vec![1, 2, 3, 4, 5]); - let limit = RateLimit::per_second_and_burst(nonzero!(1u32), nonzero!(1u32)); + let limit = Limit::per_second_and_burst(nonzero!(1u32), nonzero!(1u32)); let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); - let mut throttled_stream = std::pin::pin!(RateLimitedStream::new(stream, bucket)); + let mut throttled_stream = std::pin::pin!(ThrottledStream::new(stream, bucket)); let mut results = vec![]; while let Some(item) = throttled_stream.next().await { @@ -329,10 +329,10 @@ mod tests { #[tokio::test(start_paused = true)] async fn test_throttled_stream_burst() { let stream = stream::iter(vec![1, 2, 3, 4, 5]); - let limit = RateLimit::per_second_and_burst(nonzero!(1u32), nonzero!(3u32)); + let limit = Limit::per_second_and_burst(nonzero!(1u32), nonzero!(3u32)); let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); - let mut throttled_stream = std::pin::pin!(RateLimitedStream::new(stream, bucket)); + let mut throttled_stream = std::pin::pin!(ThrottledStream::new(stream, bucket)); let mut results = vec![]; let start = tokio::time::Instant::now(); @@ -348,10 +348,10 @@ mod tests { #[tokio::test(start_paused = true)] async fn test_throttled_stream_all_ready() { let stream = stream::iter(vec![1, 2, 3, 4, 5]); - let limit = RateLimit::per_second(nonzero!(100000u32)).with_burst(nonzero!(1u32)); + let limit = Limit::per_second(nonzero!(100000u32)).with_burst(nonzero!(1u32)); let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); - let mut throttled_stream = std::pin::pin!(RateLimitedStream::new(stream, bucket)); + let mut throttled_stream = std::pin::pin!(ThrottledStream::new(stream, bucket)); let mut results = vec![]; let start = tokio::time::Instant::now(); @@ -369,10 +369,10 @@ mod tests { let stream = stream::iter(vec![1, 2, 3, 4, 5]) .throttle(Duration::from_secs(2)) .chain(stream::iter(vec![6, 7, 8, 9])); - let limit = RateLimit::per_second_and_burst(nonzero!(1u32), nonzero!(3u32)); + let limit = Limit::per_second_and_burst(nonzero!(1u32), nonzero!(3u32)); let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); - let mut throttled_stream = std::pin::pin!(RateLimitedStream::new(stream, bucket)); + let mut throttled_stream = std::pin::pin!(ThrottledStream::new(stream, bucket)); let mut results = vec![]; let start = tokio::time::Instant::now(); @@ -389,7 +389,7 @@ mod tests { async fn test_weighted_stream_uniform_weight() { let start = tokio::time::Instant::now(); let stream = stream::iter(vec![1, 2, 3, 4, 5]); - let limit = RateLimit::per_second_and_burst(nonzero!(1u32), nonzero!(1u32)); + let limit = Limit::per_second_and_burst(nonzero!(1u32), nonzero!(1u32)); let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); let mut weighted_stream = @@ -409,7 +409,7 @@ mod tests { async fn test_weighted_stream_variable_weight() { let start = tokio::time::Instant::now(); let stream = stream::iter(vec![1, 2, 3, 4, 5]); - let limit = RateLimit::per_second_and_burst(nonzero!(2u32), nonzero!(2u32)); + let limit = Limit::per_second_and_burst(nonzero!(2u32), nonzero!(2u32)); let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); let mut weighted_stream = std::pin::pin!(WeightedStream::new(stream, bucket, |&item| { @@ -435,7 +435,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn test_weighted_stream_with_burst() { let stream = stream::iter(vec![1, 2, 3, 4, 5]); - let limit = RateLimit::per_second_and_burst(nonzero!(1u32), nonzero!(5u32)); + let limit = Limit::per_second_and_burst(nonzero!(1u32), nonzero!(5u32)); let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); let mut weighted_stream = std::pin::pin!(WeightedStream::new(stream, bucket, |&item| { @@ -458,7 +458,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn test_weighted_stream_empty() { let stream = stream::iter(Vec::::new()); - let limit = RateLimit::per_second_and_burst(nonzero!(1u32), nonzero!(1u32)); + let limit = Limit::per_second_and_burst(nonzero!(1u32), nonzero!(1u32)); let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); let mut weighted_stream = @@ -475,7 +475,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn test_weighted_stream_single_item() { let stream = stream::iter(vec![42]); - let limit = RateLimit::per_second_and_burst(nonzero!(10u32), nonzero!(10u32)); + let limit = Limit::per_second_and_burst(nonzero!(10u32), nonzero!(10u32)); let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); let mut weighted_stream = @@ -497,7 +497,7 @@ mod tests { async fn test_weighted_stream_expensive_item_delayed() { // This test verifies that expensive items are properly delayed before being returned let stream = stream::iter(vec![10]); // Single expensive item - let limit = RateLimit::per_second_and_burst(nonzero!(1u32), nonzero!(10u32)); // Enough burst for the item + let limit = Limit::per_second_and_burst(nonzero!(1u32), nonzero!(10u32)); // Enough burst for the item let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); let mut weighted_stream = std::pin::pin!(WeightedStream::new(stream, bucket, |&item| { @@ -524,7 +524,7 @@ mod tests { async fn test_weighted_stream_mixed_items_correct_timing() { // Test that cheap items come quickly and expensive items are delayed appropriately let stream = stream::iter(vec![1, 5, 1]); // cheap, expensive, cheap - let limit = RateLimit::per_second_and_burst(nonzero!(2u32), nonzero!(10u32)); // Enough burst capacity + let limit = Limit::per_second_and_burst(nonzero!(2u32), nonzero!(10u32)); // Enough burst capacity let bucket = TokenBucket::::from_parts(limit, TokioClock::default()); let mut weighted_stream = std::pin::pin!(WeightedStream::new(stream, bucket, |&item| { diff --git a/src/lib.rs b/src/lib.rs index 539db9e..1ce4d22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ //! # Core Components //! //! - [`TokenBucket`] - The main token bucket implementation with pluggable storage and clock -//! - [`RateLimit`] - Configuration for rate and burst limits +//! - [`Limit`] - Configuration for rate and burst limits //! - [`Clock`] trait and implementations for time sources //! - Storage implementations for different concurrency needs //! @@ -12,10 +12,10 @@ //! ```rust //! use std::num::NonZeroU32; //! -//! use gardal::{TokenBucket, RateLimit}; +//! use gardal::{TokenBucket, Limit}; //! //! // Create a rate limit: 10 tokens per second, burst of 20 -//! let limit = RateLimit::per_second_and_burst( +//! let limit = Limit::per_second_and_burst( //! NonZeroU32::new(10).unwrap(), //! NonZeroU32::new(20).unwrap() //! ); @@ -46,8 +46,8 @@ pub use clock::{Clock, ManualClock, StdClock}; pub use clock::{FastClock, QuantaClock}; pub use error::*; #[cfg(feature = "async")] -pub use futures::RateLimitedStreamExt; -pub use limit::RateLimit; +pub use futures::StreamExt; +pub use limit::Limit; pub use tokens::Tokens; pub use storage::{ diff --git a/src/limit.rs b/src/limit.rs index c5131ba..f1352e7 100644 --- a/src/limit.rs +++ b/src/limit.rs @@ -11,36 +11,36 @@ const SECONDS_PER_HOUR: f64 = 3600.0; /// # Examples /// /// ```rust -/// use gardal::RateLimit; +/// use gardal::Limit; /// use std::num::NonZeroU32; /// /// // 100 requests per second, burst of 200 -/// let limit = RateLimit::per_second_and_burst( +/// let limit = Limit::per_second_and_burst( /// NonZeroU32::new(100).unwrap(), /// NonZeroU32::new(200).unwrap() /// ); /// /// // 60 requests per minute (1 per second), burst equals rate -/// let limit = RateLimit::per_minute(NonZeroU32::new(60).unwrap()); +/// let limit = Limit::per_minute(NonZeroU32::new(60).unwrap()); /// ``` #[derive(Clone, Copy)] -pub struct RateLimit { +pub struct Limit { pub(crate) rate: f64, pub(crate) burst: f64, } -impl std::fmt::Debug for RateLimit { +impl std::fmt::Debug for Limit { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "RateLimit(rate_per_second={}, burst={})", + "Limit(rate_per_second={}, burst={})", self.rate_per_second(), self.burst() ) } } -impl RateLimit { +impl Limit { /// Creates a rate limit with the specified tokens per second. /// /// The burst capacity is set equal to the rate, allowing for one second's @@ -53,10 +53,10 @@ impl RateLimit { /// # Examples /// /// ```rust - /// use gardal::RateLimit; + /// use gardal::Limit; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second(NonZeroU32::new(100).unwrap()); + /// let limit = Limit::per_second(NonZeroU32::new(100).unwrap()); /// assert_eq!(limit.rate_per_second(), 100.0); /// assert_eq!(limit.burst(), NonZeroU32::new(100).unwrap()); /// ``` @@ -77,10 +77,10 @@ impl RateLimit { /// # Examples /// /// ```rust - /// use gardal::RateLimit; + /// use gardal::Limit; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second_and_burst( + /// let limit = Limit::per_second_and_burst( /// NonZeroU32::new(10).unwrap(), /// NonZeroU32::new(50).unwrap() /// ); @@ -105,10 +105,10 @@ impl RateLimit { /// # Examples /// /// ```rust - /// use gardal::RateLimit; + /// use gardal::Limit; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_minute(NonZeroU32::new(60).unwrap()); + /// let limit = Limit::per_minute(NonZeroU32::new(60).unwrap()); /// assert_eq!(limit.rate_per_second(), 1.0); /// assert_eq!(limit.rate_per_minute(), 60.0); /// ``` @@ -130,10 +130,10 @@ impl RateLimit { /// # Examples /// /// ```rust - /// use gardal::RateLimit; + /// use gardal::Limit; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_hour(NonZeroU32::new(3600).unwrap()); + /// let limit = Limit::per_hour(NonZeroU32::new(3600).unwrap()); /// assert_eq!(limit.rate_per_second(), 1.0); /// assert_eq!(limit.rate_per_hour(), 3600.0); /// ``` @@ -153,10 +153,10 @@ impl RateLimit { /// # Examples /// /// ```rust - /// use gardal::RateLimit; + /// use gardal::Limit; /// use std::num::NonZeroU32; /// - /// let limit = RateLimit::per_second(NonZeroU32::new(10).unwrap()) + /// let limit = Limit::per_second(NonZeroU32::new(10).unwrap()) /// .with_burst(NonZeroU32::new(100).unwrap()); /// assert_eq!(limit.rate_per_second(), 10.0); /// assert_eq!(limit.burst(), NonZeroU32::new(100).unwrap()); diff --git a/src/storage/atomic.rs b/src/storage/atomic.rs index fd2bd6d..72ab925 100644 --- a/src/storage/atomic.rs +++ b/src/storage/atomic.rs @@ -56,10 +56,10 @@ impl Debug for AtomicF64 { /// # Examples /// /// ```rust -/// use gardal::{TokenBucket, RateLimit, AtomicStorage, StdClock}; +/// use gardal::{TokenBucket, Limit, AtomicStorage, StdClock}; /// use std::num::NonZeroU32; /// -/// let limit = RateLimit::per_second(NonZeroU32::new(100).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(100).unwrap()); /// let bucket = TokenBucket::::from_parts(limit, StdClock::default()); /// ``` #[derive(Debug)] @@ -95,11 +95,11 @@ impl TimeStorage for AtomicStorage { /// # Examples /// /// ```rust -/// use gardal::{TokenBucket, RateLimit, AtomicSharedStorage, ManualClock}; +/// use gardal::{TokenBucket, Limit, AtomicSharedStorage, ManualClock}; /// use std::num::NonZeroU32; /// use std::sync::Arc; /// -/// let limit = RateLimit::per_second(NonZeroU32::new(100).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(100).unwrap()); /// let clock = Arc::new(ManualClock::new(0.0)); /// let bucket1 = TokenBucket::::from_parts(limit, Arc::clone(&clock)); /// let bucket2 = bucket1.clone(); // Shares the same token state diff --git a/src/storage/local.rs b/src/storage/local.rs index 4fbe483..65d0557 100644 --- a/src/storage/local.rs +++ b/src/storage/local.rs @@ -16,10 +16,10 @@ use super::TimeStorage; /// # Examples /// /// ```rust -/// use gardal::{TokenBucket, RateLimit, LocalStorage, StdClock}; +/// use gardal::{TokenBucket, Limit, LocalStorage, StdClock}; /// use std::num::NonZeroU32; /// -/// let limit = RateLimit::per_second(NonZeroU32::new(100).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(100).unwrap()); /// let bucket = TokenBucket::::from_parts(limit, StdClock::default()); /// ``` #[derive(Debug)] diff --git a/src/storage/padded_atomic.rs b/src/storage/padded_atomic.rs index e95d362..3876869 100644 --- a/src/storage/padded_atomic.rs +++ b/src/storage/padded_atomic.rs @@ -20,11 +20,11 @@ use super::cache_padded::CachePadded; /// # Examples /// /// ```rust -/// use gardal::{TokenBucket, RateLimit}; +/// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// /// // PaddedAtomicStorage is the default storage type -/// let limit = RateLimit::per_second(NonZeroU32::new(100).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(100).unwrap()); /// let bucket = TokenBucket::new(limit); /// ``` pub struct PaddedAtomicStorage(CachePadded); @@ -65,11 +65,11 @@ impl TimeStorage for PaddedAtomicStorage { /// # Examples /// /// ```rust -/// use gardal::{TokenBucket, RateLimit}; +/// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// /// // PaddedAtomicStorage is the default storage type -/// let limit = RateLimit::per_second(NonZeroU32::new(100).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(100).unwrap()); /// let bucket = TokenBucket::new(limit); /// ``` #[derive(Clone)] diff --git a/src/tokens.rs b/src/tokens.rs index df0ffc0..3558b4f 100644 --- a/src/tokens.rs +++ b/src/tokens.rs @@ -8,10 +8,10 @@ use std::num::NonZero; /// # Examples /// /// ```rust -/// use gardal::{TokenBucket, RateLimit}; +/// use gardal::{TokenBucket, Limit}; /// use std::num::NonZeroU32; /// -/// let limit = RateLimit::per_second(NonZeroU32::new(10).unwrap()); +/// let limit = Limit::per_second(NonZeroU32::new(10).unwrap()); /// let bucket = TokenBucket::new(limit); /// /// if let Some(tokens) = bucket.consume_one() {