Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: boinkor-net/governor
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.8.1
Choose a base ref
...
head repository: boinkor-net/governor
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.9.0
Choose a head ref
  • 9 commits
  • 19 files changed
  • 4 contributors

Commits on Mar 17, 2025

  1. Update tynm requirement in the cargo group across 1 directory

    Updates the requirements on [tynm](https://github.com/azriel91/tynm) to permit the latest version.
    
    Updates `tynm` to 0.2.0
    - [Release notes](https://github.com/azriel91/tynm/releases)
    - [Changelog](https://github.com/azriel91/tynm/blob/main/CHANGELOG.md)
    - [Commits](azriel91/tynm@0.1.4...0.2.0)
    
    ---
    updated-dependencies:
    - dependency-name: tynm
      dependency-type: direct:production
      dependency-group: cargo
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Mar 17, 2025

    Verified

    This commit was signed with the committer’s verified signature.
    lukekarrys Luke Karrys
    Copy the full SHA
    f0e4f18 View commit details

Commits on Mar 18, 2025

  1. Merge pull request #263 from boinkor-net/dependabot/cargo/cargo-b1a73…

    …fe371
    
    Update tynm requirement from 0.1.4 to 0.2.0 in the cargo group across 1 directory
    antifuchs authored Mar 18, 2025
    Copy the full SHA
    5f77a94 View commit details

Commits on Mar 21, 2025

  1. Get rid of no_std_compat

    It's super outdated, pulls in an ancient version of hashbrown and that blocks #262. Let's get rid of this.
    antifuchs committed Mar 21, 2025
    Copy the full SHA
    97e21db View commit details
  2. Merge pull request #264 from boinkor-net/no_no_std_compat

    Get rid of no_std_compat
    antifuchs authored Mar 21, 2025
    Copy the full SHA
    40f8b24 View commit details

Commits on Mar 24, 2025

  1. make hasher configurable for KeyedStateStore

    0xdeafbeef committed Mar 24, 2025
    Copy the full SHA
    2f047cb View commit details
  2. Merge pull request #262 from 0xdeafbeef/0xdeafbeef/push-slkomxylzuym

    make hasher configurable for `KeyedStateStore`
    antifuchs authored Mar 24, 2025
    Copy the full SHA
    5d3de7b View commit details
  3. Release 0.9.0 🎉🎉

    github-actions committed Mar 24, 2025
    Copy the full SHA
    b98be83 View commit details
  4. CL updates

    antifuchs committed Mar 24, 2025
    Copy the full SHA
    ea7e59f View commit details
  5. Merge pull request #265 from boinkor-net/release/governor/0.9.0

    release: governor v0.9.0
    antifuchs authored Mar 24, 2025
    Copy the full SHA
    e850a9d View commit details
1 change: 1 addition & 0 deletions deny.toml
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ allow = [
"BSD-2-Clause",
"MIT",
"Unicode-DFS-2016",
"Zlib",
]
confidence-threshold = 0.8

13 changes: 13 additions & 0 deletions governor/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -4,6 +4,19 @@

## [Unreleased] - ReleaseDate

## [[0.9.0](https://docs.rs/governor/0.9.0/governor/)] - 2025-03-24

## Changed

- Governor no longer uses the
[`no_std_compat` crate](https://crates.io/crates/no-std-compat),
eliminating a very outdated transitive dependency (on `hashbrown`
version 0.8).

- Keyed state stores now allow specifying the hasher.
([#262](https://github.com/boinkor-net/governor/pull/262) -
thanks, @0xdeafbeef!)

## [[0.8.1](https://docs.rs/governor/0.8.1/governor/)] - 2025-02-25

## Changed
10 changes: 5 additions & 5 deletions governor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "governor"
version = "0.8.1"
version = "0.9.0"
authors = ["Andreas Fuchs <asf@boinkor.net>"]
edition = "2018"
license = "MIT"
@@ -30,7 +30,7 @@ rustdoc-args = ["--cfg", "docsrs"]

[dev-dependencies]
criterion = {version = "0.5.1", features = ["html_reports"]}
tynm = "0.1.4"
tynm = "0.2.0"
crossbeam = "0.8.0"
libc = "0.2.70"
futures-executor = "0.3.31"
@@ -40,9 +40,9 @@ assertables = "9.5.0"
[features]
default = ["std", "dashmap", "jitter", "quanta"]
quanta = ["dep:quanta"]
std = ["no-std-compat/std", "nonzero_ext/std", "dep:futures-timer", "dep:futures-util", "dep:futures-sink", "dep:parking_lot"]
std = ["nonzero_ext/std", "dep:futures-timer", "dep:futures-util", "dep:futures-sink", "dep:parking_lot"]
jitter = ["rand"]
no_std = ["no-std-compat/compat_hash"]
no_std = ["hashbrown/alloc"]

[dependencies]
nonzero_ext = { version = "0.3.0", default-features = false }
@@ -56,9 +56,9 @@ rand = { version = "0.9.0", optional = true }
getrandom = { version = "0.3", features = ["wasm_js"] }
dashmap = { version = "6.1.0", optional = true }
quanta = { version = "0.12.0", optional = true }
no-std-compat = { version = "0.4.1", features = [ "alloc" ] }
cfg-if = "1.0"

# To ensure we don't pull in vulnerable smallvec, see https://github.com/antifuchs/governor/issues/60
smallvec = "1.6.1"
web-time = "1.1.0"
hashbrown = "0.15.2"
16 changes: 8 additions & 8 deletions governor/src/clock.rs
Original file line number Diff line number Diff line change
@@ -44,14 +44,14 @@
//! }
//! ```
use std::prelude::v1::*;

use std::convert::TryInto;
use std::fmt::Debug;
use std::ops::Add;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::Duration;
use core::prelude::v1::*;

use alloc::sync::Arc;
use core::convert::TryInto;
use core::fmt::Debug;
use core::ops::Add;
use core::sync::atomic::Ordering;
use core::time::Duration;

use portable_atomic::AtomicU64;

2 changes: 1 addition & 1 deletion governor/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::fmt;
use core::fmt;

/// Error indicating that the number of cells tested (the first
/// argument) is larger than the bucket's capacity.
8 changes: 4 additions & 4 deletions governor/src/gcra.rs
Original file line number Diff line number Diff line change
@@ -2,9 +2,9 @@ use crate::state::StateStore;
use crate::InsufficientCapacity;
use crate::{clock, middleware::StateSnapshot, Quota};
use crate::{middleware::RateLimitingMiddleware, nanos::Nanos};
use std::num::NonZeroU32;
use std::time::Duration;
use std::{cmp, fmt};
use core::num::NonZeroU32;
use core::time::Duration;
use core::{cmp, fmt};

#[cfg(feature = "std")]
use crate::Jitter;
@@ -181,7 +181,7 @@ impl Gcra {
mod test {
use super::*;
use crate::Quota;
use std::num::NonZeroU32;
use core::num::NonZeroU32;

use proptest::prelude::*;

6 changes: 2 additions & 4 deletions governor/src/jitter.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use std::prelude::v1::*;

use crate::nanos::Nanos;
use core::ops::Add;
use core::time::Duration;
#[cfg(feature = "jitter")]
use rand::distr::uniform::{SampleBorrow, SampleUniform, UniformInt, UniformSampler};
#[cfg(feature = "jitter")]
use rand::distr::{Distribution, Uniform};
#[cfg(feature = "jitter")]
use rand::{rng, Rng};
use std::ops::Add;
use std::time::Duration;

#[cfg(feature = "std")]
use std::time::Instant;
5 changes: 3 additions & 2 deletions governor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -35,7 +35,7 @@
// Unfortunately necessary, otherwise features aren't supported in doctests:
#![allow(clippy::needless_doctest_main)]

extern crate no_std_compat as std;
extern crate alloc;

pub mod r#_guide;
pub mod clock;
@@ -83,4 +83,5 @@ pub type DefaultDirectRateLimiter<
pub type DefaultKeyedRateLimiter<
K,
MW = middleware::NoOpMiddleware<<clock::DefaultClock as clock::Clock>::Instant>,
> = RateLimiter<K, state::keyed::DefaultKeyedStateStore<K>, clock::DefaultClock, MW>;
S = state::keyed::DefaultHasher,
> = RateLimiter<K, state::keyed::DefaultKeyedStateStore<K, S>, clock::DefaultClock, MW>;
4 changes: 2 additions & 2 deletions governor/src/middleware.rs
Original file line number Diff line number Diff line change
@@ -64,7 +64,7 @@
//!
//! You can define your own middleware by `impl`ing [`RateLimitingMiddleware`].
use core::fmt;
use std::{cmp, marker::PhantomData};
use core::{cmp, marker::PhantomData};

use crate::{clock, nanos::Nanos, NotUntil, Quota};

@@ -219,7 +219,7 @@ pub struct NoOpMiddleware<P: clock::Reference = <clock::DefaultClock as clock::C
phantom: PhantomData<P>,
}

impl<P: clock::Reference> std::fmt::Debug for NoOpMiddleware<P> {
impl<P: clock::Reference> core::fmt::Debug for NoOpMiddleware<P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "NoOpMiddleware")
}
9 changes: 4 additions & 5 deletions governor/src/nanos.rs
Original file line number Diff line number Diff line change
@@ -2,11 +2,10 @@
use crate::clock;

use std::convert::TryInto;
use std::fmt;
use std::ops::{Add, Div, Mul};
use std::prelude::v1::*;
use std::time::Duration;
use core::convert::TryInto;
use core::fmt;
use core::ops::{Add, Div, Mul};
use core::time::Duration;

/// A number of nanoseconds from a reference point.
///
6 changes: 2 additions & 4 deletions governor/src/quota.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::prelude::v1::*;

use core::num::NonZeroU32;
use core::time::Duration;
use nonzero_ext::nonzero;
use std::num::NonZeroU32;
use std::time::Duration;

use crate::nanos::Nanos;

2 changes: 1 addition & 1 deletion governor/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! State stores for rate limiters
use std::{marker::PhantomData, prelude::v1::*};
use core::marker::PhantomData;

pub mod direct;
mod in_memory;
4 changes: 1 addition & 3 deletions governor/src/state/direct.rs
Original file line number Diff line number Diff line change
@@ -3,9 +3,7 @@
//! 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 core::num::NonZeroU32;

use crate::{
clock,
13 changes: 6 additions & 7 deletions governor/src/state/in_memory.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use std::prelude::v1::*;

use crate::nanos::Nanos;
use crate::state::{NotKeyed, StateStore};
use std::fmt;
use std::fmt::Debug;
use std::num::NonZeroU64;
use std::sync::atomic::Ordering;
use std::time::Duration;
use core::fmt;
use core::fmt::Debug;
use core::num::NonZeroU64;
use core::sync::atomic::Ordering;
use core::time::Duration;

use portable_atomic::AtomicU64;

@@ -135,6 +133,7 @@ mod test {

#[test]
fn in_memory_state_impls() {
use alloc::format;
let state = InMemoryState(AtomicU64::new(0));
assert_gt!(format!("{:?}", state).len(), 0);
}
68 changes: 60 additions & 8 deletions governor/src/state/keyed.rs
Original file line number Diff line number Diff line change
@@ -7,9 +7,9 @@
//! Rate limiters based on these types are constructed with
//! [the `RateLimiter` constructors](../struct.RateLimiter.html#keyed-rate-limiters---default-constructors)
use std::hash::Hash;
use std::num::NonZeroU32;
use std::prelude::v1::*;
use core::hash::Hash;
use core::num::NonZeroU32;
use core::prelude::v1::*;

use crate::state::StateStore;
use crate::{
@@ -20,6 +20,11 @@ use crate::{
Quota, RateLimiter,
};

#[cfg(feature = "std")]
pub type DefaultHasher = std::hash::RandomState;
#[cfg(not(feature = "std"))]
pub type DefaultHasher = hashbrown::DefaultHashBuilder;

/// A trait for state stores with one rate limiting state per key.
///
/// This is blanket-implemented by all [`StateStore`]s with hashable (`Eq + Hash + Clone`) key
@@ -64,20 +69,67 @@ where
}
}

#[cfg(any(all(feature = "std", not(feature = "dashmap")), not(feature = "std")))]
/// # Keyed rate limiters with custom hashers for std HashMap
impl<K, S> RateLimiter<K, DefaultKeyedStateStore<K, S>, clock::DefaultClock>
where
K: Clone + Hash + Eq,
S: core::hash::BuildHasher + Default,
{
/// Constructs a new keyed rate limiter explicitly backed by a
/// [`HashMap`][hashmap::HashMap] with a custom hasher.
pub fn hashmap_with_hasher(quota: Quota, hasher: S) -> Self {
let state = HashMapStateStore::new(hashmap::HashMap::with_hasher(hasher));
let clock = clock::DefaultClock::default();
RateLimiter::new(quota, state, clock)
}
}

#[cfg(all(feature = "std", feature = "dashmap"))]
/// # Keyed rate limiters with custom hashers
impl<K, S> RateLimiter<K, DefaultKeyedStateStore<K, S>, clock::DefaultClock>
where
K: Clone + Hash + Eq,
S: core::hash::BuildHasher + Clone + Default,
{
/// Constructs a new keyed rate limiter explicitly backed by a
/// [`DashMap`][::dashmap::DashMap] with a custom hasher.
pub fn dashmap_with_hasher(quota: Quota, hasher: S) -> Self {
let state = DashMapStateStore::with_hasher(hasher);
let clock = clock::DefaultClock::default();
RateLimiter::new(quota, state, clock)
}
}

#[cfg(all(feature = "std", feature = "dashmap"))]
impl<K> RateLimiter<K, HashMapStateStore<K>, clock::DefaultClock>
where
K: Clone + Hash + Eq,
{
/// Constructs a new keyed rate limiter explicitly backed by a
/// [`HashMap`][std::collections::HashMap].
/// [`HashMap`][hashmap::HashMap].
pub fn hashmap(quota: Quota) -> Self {
let state = HashMapStateStore::default();
let clock = clock::DefaultClock::default();
RateLimiter::new(quota, state, clock)
}
}

#[cfg(all(feature = "std", feature = "dashmap"))]
impl<K, S> RateLimiter<K, HashMapStateStore<K, S>, clock::DefaultClock>
where
K: Clone + Hash + Eq,
S: core::hash::BuildHasher + Default + Clone,
{
/// Constructs a new keyed rate limiter explicitly backed by a
/// [`HashMap`][hashmap::HashMap].
pub fn hashmap_with_hasher(quota: Quota, hasher: S) -> Self {
let state = HashMapStateStore::new(hashmap::HashMap::with_hasher(hasher));
let clock = clock::DefaultClock::default();
RateLimiter::new(quota, state, clock)
}
}

/// # Keyed rate limiters - Manually checking cells
impl<K, S, C, MW> RateLimiter<K, S, C, MW>
where
@@ -224,16 +276,16 @@ pub use self::dashmap::DashMapStateStore;
mod future;

#[cfg(any(all(feature = "std", not(feature = "dashmap")), not(feature = "std")))]
/// The default keyed rate limiter type: a mutex-wrapped [`HashMap`][std::collections::HashMap].
pub type DefaultKeyedStateStore<K> = HashMapStateStore<K>;
/// The default keyed rate limiter type: a mutex-wrapped [`HashMap`][hashmap::Hashmap].
pub type DefaultKeyedStateStore<K, S = DefaultHasher> = HashMapStateStore<K, S>;

#[cfg(all(feature = "std", feature = "dashmap"))]
/// The default keyed rate limiter type: the concurrent [`DashMap`][::dashmap::DashMap].
pub type DefaultKeyedStateStore<K> = DashMapStateStore<K>;
pub type DefaultKeyedStateStore<K, S = DefaultHasher> = DashMapStateStore<K, S>;

#[cfg(test)]
mod test {
use std::marker::PhantomData;
use core::marker::PhantomData;

use nonzero_ext::nonzero;

Loading