use std::{
num::NonZeroUsize,
time::{Duration, Instant},
};
#[derive(Debug, Clone, Default)]
pub struct PruneLimiter {
deleted_entries_limit: Option<PruneDeletedEntriesLimit>,
time_limit: Option<PruneTimeLimit>,
}
#[derive(Debug, Clone)]
struct PruneDeletedEntriesLimit {
limit: usize,
deleted: usize,
}
impl PruneDeletedEntriesLimit {
const fn new(limit: usize) -> Self {
Self { limit, deleted: 0 }
}
const fn is_limit_reached(&self) -> bool {
self.deleted >= self.limit
}
}
#[derive(Debug, Clone)]
struct PruneTimeLimit {
limit: Duration,
start: Instant,
}
impl PruneTimeLimit {
fn new(limit: Duration) -> Self {
Self { limit, start: Instant::now() }
}
fn is_limit_reached(&self) -> bool {
self.start.elapsed() > self.limit
}
}
impl PruneLimiter {
pub fn set_deleted_entries_limit(mut self, limit: usize) -> Self {
if let Some(deleted_entries_limit) = self.deleted_entries_limit.as_mut() {
deleted_entries_limit.limit = limit;
} else {
self.deleted_entries_limit = Some(PruneDeletedEntriesLimit::new(limit));
}
self
}
pub fn floor_deleted_entries_limit_to_multiple_of(mut self, denominator: NonZeroUsize) -> Self {
if let Some(deleted_entries_limit) = self.deleted_entries_limit.as_mut() {
deleted_entries_limit.limit =
(deleted_entries_limit.limit / denominator) * denominator.get();
}
self
}
pub fn is_deleted_entries_limit_reached(&self) -> bool {
self.deleted_entries_limit.as_ref().map_or(false, |limit| limit.is_limit_reached())
}
pub fn increment_deleted_entries_count_by(&mut self, entries: usize) {
if let Some(limit) = self.deleted_entries_limit.as_mut() {
limit.deleted += entries;
}
}
pub fn increment_deleted_entries_count(&mut self) {
self.increment_deleted_entries_count_by(1)
}
pub fn deleted_entries_limit_left(&self) -> Option<usize> {
self.deleted_entries_limit.as_ref().map(|limit| limit.limit - limit.deleted)
}
pub fn deleted_entries_limit(&self) -> Option<usize> {
self.deleted_entries_limit.as_ref().map(|limit| limit.limit)
}
pub fn set_time_limit(mut self, limit: Duration) -> Self {
self.time_limit = Some(PruneTimeLimit::new(limit));
self
}
pub fn is_time_limit_reached(&self) -> bool {
self.time_limit.as_ref().map_or(false, |limit| limit.is_limit_reached())
}
pub fn is_limit_reached(&self) -> bool {
self.is_deleted_entries_limit_reached() || self.is_time_limit_reached()
}
}