Skip to main content

wowlab_engine_domain/pool/
expiry.rs

1use std::hash::Hash;
2
3use wowlab_types::sim::SimTime;
4
5use super::base::Pool;
6
7/// Independently expiring stack deadlines, ordered from earliest to latest.
8#[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;