use std::time::{Duration, Instant};
use super::error::McsdError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Limits {
pub pages: usize,
pub bytes: usize,
pub entries: usize,
}
impl Default for Limits {
fn default() -> Self {
Self {
pages: 200,
bytes: 64 << 20,
entries: 50_000,
}
}
}
#[derive(Debug, Clone)]
pub struct Budget {
deadline: Instant,
limits: Limits,
pages: usize,
bytes: usize,
entries: usize,
}
impl Budget {
#[must_use]
pub fn new(deadline: Instant, limits: Limits) -> Self {
Self {
deadline,
limits,
pages: 0,
bytes: 0,
entries: 0,
}
}
pub(crate) fn remaining(&self) -> Result<Duration, McsdError> {
let left = self.deadline.saturating_duration_since(Instant::now());
if left.is_zero() {
Err(McsdError::Timeout)
} else {
Ok(left)
}
}
pub(crate) fn page(&mut self) -> Result<(), McsdError> {
if self.pages >= self.limits.pages {
return Err(McsdError::TooManyPages {
limit: self.limits.pages,
});
}
self.pages = self.pages.saturating_add(1);
Ok(())
}
pub(crate) fn bytes(&mut self, bytes: usize) -> Result<(), McsdError> {
let total = self.bytes.saturating_add(bytes);
if total > self.limits.bytes {
return Err(McsdError::TooLarge {
limit: self.limits.bytes,
});
}
self.bytes = total;
Ok(())
}
pub(crate) fn entries(&mut self, entries: usize) -> Result<(), McsdError> {
let total = self.entries.saturating_add(entries);
if total > self.limits.entries {
return Err(McsdError::TooManyEntries {
limit: self.limits.entries,
});
}
self.entries = total;
Ok(())
}
}