pub(crate) const IDLE_FRAMES: u64 = 120;
pub(crate) struct IdlePool<T> {
available: Vec<(T, u64)>,
frame: u64,
}
impl<T> Default for IdlePool<T> {
fn default() -> Self {
Self {
available: Vec::new(),
frame: 0,
}
}
}
impl<T> IdlePool<T> {
pub(crate) fn take(&mut self, matches: impl Fn(&T) -> bool) -> Option<T> {
let index = self.available.iter().position(|(item, _)| matches(item))?;
Some(self.available.remove(index).0)
}
pub(crate) fn take_min_by_key<K: Ord>(
&mut self,
matches: impl Fn(&T) -> bool,
key: impl Fn(&T) -> K,
) -> Option<T> {
let index = self
.available
.iter()
.enumerate()
.filter(|(_, (item, _))| matches(item))
.min_by_key(|(_, (item, _))| key(item))
.map(|(index, _)| index)?;
Some(self.available.remove(index).0)
}
pub(crate) fn put(
&mut self,
item: T,
max_len: usize,
max_bytes: u64,
bytes: impl Fn(&T) -> u64,
) {
self.available.push((item, self.frame));
let mut held: u64 = self.iter().map(&bytes).sum();
while self.available.len() > max_len || (held > max_bytes && self.available.len() > 1) {
let (dropped, _) = self.available.remove(0);
held = held.saturating_sub(bytes(&dropped));
}
}
pub(crate) fn end_frame(&mut self) {
self.frame += 1;
let oldest_kept = self.frame.saturating_sub(IDLE_FRAMES);
self.available
.retain(|(_, returned)| *returned >= oldest_kept);
}
pub(crate) fn iter(&self) -> impl Iterator<Item = &T> {
self.available.iter().map(|(item, _)| item)
}
pub(crate) fn len(&self) -> usize {
self.available.len()
}
}
#[cfg(test)]
#[path = "tests/idle_pool_tests.rs"]
mod tests;