wowlab_engine_domain/pool/
expiry.rs1use std::hash::Hash;
2
3use wowlab_types::sim::SimTime;
4
5use super::base::Pool;
6
7#[derive(Clone, Debug)]
9pub struct ExpiryPool<K> {
10 state: Pool<K, Vec<SimTime>>,
11}
12
13impl<K> ExpiryPool<K>
14where
15 K: Eq + Hash,
16{
17 #[must_use]
18 pub fn new() -> Self {
19 Self::default()
20 }
21
22 pub fn push_capped(&mut self, key: K, expiry: SimTime, capacity: usize) -> (usize, bool) {
23 let deadlines = self.state.value_mut(key);
24 let was_empty = deadlines.is_empty();
25 let capacity = capacity.max(1);
26
27 if deadlines.len() >= capacity {
28 deadlines.remove(0);
29 }
30
31 let index = deadlines.partition_point(|deadline| *deadline <= expiry);
32
33 deadlines.insert(index, expiry);
34
35 (deadlines.len(), was_empty)
36 }
37
38 pub fn expire_due(&mut self, key: &K, now: SimTime) -> Option<(usize, usize)> {
39 let deadlines = self.state.get_mut(key)?;
40 let due = deadlines.partition_point(|deadline| *deadline <= now);
41
42 deadlines.drain(..due);
43
44 Some((due, deadlines.len()))
45 }
46
47 pub fn remove_oldest(&mut self, key: &K) -> bool {
48 self.state.get_mut(key).is_some_and(|deadlines| {
49 !deadlines.is_empty() && {
50 deadlines.remove(0);
51
52 true
53 }
54 })
55 }
56
57 pub fn is_empty(&self, key: &K) -> bool {
58 self.state.get(key).is_none_or(Vec::is_empty)
59 }
60
61 pub fn len(&self, key: &K) -> usize {
62 self.state.get(key).map_or(0, Vec::len)
63 }
64
65 pub fn remove(&mut self, key: &K) {
66 self.state.remove(key);
67 }
68
69 pub fn clear(&mut self) {
70 self.state.clear();
71 }
72}
73
74impl<K> Default for ExpiryPool<K> {
75 fn default() -> Self {
76 Self {
77 state: Pool::default(),
78 }
79 }
80}
81
82#[cfg(test)]
83#[path = "expiry/tests.rs"]
84mod tests;