use std::num::NonZeroU32;
use nautilus_network::ratelimiter::quota::Quota;
pub const DERIVE_MATCHING_RATE_KEY: &str = "derive:matching";
pub const DERIVE_NON_MATCHING_RATE_KEY: &str = "derive:non-matching";
pub const DERIVE_DEFAULT_MATCHING_TPS: u32 = 1;
pub const DERIVE_NON_MATCHING_TPS: u32 = 10;
pub const DERIVE_RATE_BURST_MULTIPLIER: u32 = 5;
#[must_use]
pub fn matching_quota(max_requests_per_second: Option<u32>) -> Quota {
let tps = max_requests_per_second
.filter(|&v| v > 0)
.unwrap_or(DERIVE_DEFAULT_MATCHING_TPS);
quota_with_burst(tps)
}
#[must_use]
pub fn non_matching_quota() -> Quota {
quota_with_burst(DERIVE_NON_MATCHING_TPS)
}
fn quota_with_burst(tps: u32) -> Quota {
let rate = NonZeroU32::new(tps).expect("tps must be non-zero");
let burst = NonZeroU32::new(tps.saturating_mul(DERIVE_RATE_BURST_MULTIPLIER))
.expect("burst must be non-zero");
Quota::per_second(rate)
.expect("per-second quota replenish interval must be non-zero")
.allow_burst(burst)
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use rstest::rstest;
use super::*;
#[rstest]
fn test_non_matching_quota_is_ten_per_second_with_five_second_burst() {
let quota = non_matching_quota();
assert_eq!(quota.burst_size().get(), 50);
assert_eq!(quota.replenish_interval(), Duration::from_millis(100));
}
#[rstest]
fn test_matching_quota_defaults_to_trader_tier() {
let quota = matching_quota(None);
assert_eq!(quota.burst_size().get(), 5);
assert_eq!(quota.replenish_interval(), Duration::from_secs(1));
}
#[rstest]
fn test_matching_quota_treats_zero_as_unset() {
assert_eq!(matching_quota(Some(0)).burst_size().get(), 5);
}
#[rstest]
fn test_matching_quota_honors_market_maker_override() {
let quota = matching_quota(Some(500));
assert_eq!(quota.burst_size().get(), 2500);
assert_eq!(quota.replenish_interval(), Duration::from_millis(2));
}
}