///|
/// GCRA, the Generic Cell Rate Algorithm, kept in the form that makes its
/// equivalence with the token bucket a theorem rather than a hope: the state
/// is the theoretical arrival time `tat` of the next conforming arrival, and
/// the invariant
///
/// tokens(now) == capacity - rate * max(0, tat - now)
///
/// holds exactly. The equivalence tests below re-derive it on deterministic
/// and pseudo-random schedules by running both limiters side by side.
priv struct Gcra {
rate : Double
capacity : Double
mut tat : Double
}
///|
fn gcra(rate : Double, capacity : Double) -> Gcra {
// tat 0 matches a bucket that starts full at time 0.
{ rate, capacity, tat: 0.0, }
}
///|
fn Gcra::tokens_now(self : Gcra, now : Double) -> Double {
let ahead = self.tat - now
if ahead > 0.0 {
self.capacity - self.rate * ahead
} else {
self.capacity
}
}
///|
fn Gcra::check(self : Gcra, now : Double, weight : Double) -> Admission {
let tokens = self.tokens_now(now)
if weight <= tokens {
let start = if self.tat > now { self.tat } else { now }
self.tat = start + weight / self.rate
{ allowed: true, retry_after: None, tokens: tokens - weight, }
} else {
// Deficit over rate: identical in value to the bucket's arithmetic.
let deficit = weight - tokens
{ allowed: false, retry_after: Some(deficit / self.rate), tokens, }
}
}