Rate Limiting

Schubert's RateLimiter uses a token-bucket algorithm scaled by Schubert intersection numbers — higher-trust principals get proportionally more throughput.

Basic Rate Limiter

#![allow(unused)]
fn main() {
use schubert::RateLimiter;

// 10 tokens per second, burst capacity of 20 tokens
let mut rl = RateLimiter::new(10.0, 1.0);

// Per-request rate check
if rl.try_consume("alice").is_err() {
    return Err("rate limit exceeded");
}
}

Configure from Access Decision

#![allow(unused)]
fn main() {
let granted = acl.check(&alice, &["read", "write"])?;
let mut rl = RateLimiter::new(10.0, 1.0);

// Scale the rate limiter based on access decision:
// Higher intersection numbers → more tokens
rl.configure_from_decision("alice", &granted)?;
}

Bucket State Queries

#![allow(unused)]
fn main() {
let available = rl.tokens_available("alice");
let capacity = rl.capacity("alice");
let fill_rate = rl.refill_rate();
}

How It Works

The token bucket is parameterized by the Schubert intersection number from the access decision. A principal with more valid configurations (higher intersection number) gets a larger token bucket — this models the principle that higher-trust, multi-capability access should have proportionally more throughput.

When trust degrades and the intersection number drops, the rate limit tightens automatically.