1#![doc = include_str!("../README.md")]
2
3use std::collections::VecDeque;
4
5#[derive(Debug, Clone)]
6pub struct PullTimer<T>(VecDeque<(u32, T)>);
7
8impl<T> PullTimer<T> {
9 pub fn new() -> PullTimer<T> {
10 PullTimer(VecDeque::new())
11 }
12
13 pub fn next_in(&self) -> Option<u32> {
14 self.0.front().map(|&(deadline, _)| deadline)
15 }
16
17 pub fn tick(&mut self, elapsed: u32) {
18 let mut remaining = elapsed;
19 for (delta, _) in &mut self.0 {
20 let temp = *delta;
21 *delta = delta.saturating_sub(elapsed);
22 remaining = remaining.saturating_sub(temp);
23
24 if remaining == 0 {
25 break;
26 }
27 }
28 }
29
30 pub fn add(&mut self, deadline: u32, event: T) {
31 let mut sum = 0;
32 let mut insertion_point = 0;
33
34 for (index, &(delta, _)) in self.0.iter().enumerate() {
35 if sum + delta > deadline {
36 break;
37 }
38 insertion_point = index + 1;
39 sum += delta;
40 }
41
42 let insertion_delta = deadline - sum;
43
44 if let Some((delta, _)) = &mut self.0.get_mut(insertion_point) {
45 *delta = delta.saturating_sub(insertion_delta);
46 }
47
48 self.0.insert(insertion_point, (insertion_delta, event));
49 }
50
51 pub fn remove(&mut self, event: T) -> Option<u32>
52 where
53 T: PartialEq,
54 {
55 let mut sum = 0;
56 let mut target = None;
57
58 for (index, &(delta, ref element)) in self.0.iter().enumerate() {
59 sum += delta;
60 if *element == event {
61 target = Some(index);
62 break;
63 }
64 }
65
66 let index = target?;
67 let (delta, _) = self.0.remove(index)?;
68
69 if let Some((next_delta, _)) = self.0.get_mut(index) {
70 *next_delta += delta;
71 }
72
73 Some(sum)
74 }
75
76 pub fn poll(&mut self) -> Option<T> {
77 let &(delta, _) = self.0.front()?;
78
79 if delta == 0 {
80 self.0.pop_front().map(|(_, event)| event)
81 } else {
82 None
83 }
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn timer_preserves_fifo_order() {
93 let mut timer = PullTimer::new();
94
95 timer.add(0, "testing");
96 timer.add(0, "one two three");
97
98 assert_eq!(timer.poll(), Some("testing"));
99 assert_eq!(timer.poll(), Some("one two three"));
100 assert_eq!(timer.poll(), None);
101 }
102
103 #[test]
104 fn timer_fires_in_order() {
105 let mut timer = PullTimer::new();
106
107 timer.add(4, "test");
108 timer.add(3, "a");
109 timer.add(2, "is");
110 timer.add(1, "this");
111
112 timer.tick(4);
113
114 assert_eq!(timer.poll(), Some("this"));
115 assert_eq!(timer.poll(), Some("is"));
116 assert_eq!(timer.poll(), Some("a"));
117 assert_eq!(timer.poll(), Some("test"));
118 assert_eq!(timer.poll(), None);
119 }
120
121 #[test]
122 fn timer_fires_in_time() {
123 let mut timer = PullTimer::new();
124
125 timer.add(40, 40);
126 timer.add(20, 20);
127 timer.add(0, 0);
128 timer.add(30, 30);
129 timer.add(10, 10);
130
131 for i in 0..=41 {
132 if let Some(value) = timer.poll() {
133 assert_eq!(value, i);
134 }
135 timer.tick(1);
136 }
137 }
138
139 #[test]
140 fn timer_next_in() {
141 let mut timer = PullTimer::new();
142
143 timer.add(0, "hi");
144 timer.add(20, "!");
145 timer.add(10, "there");
146
147 assert_eq!(timer.next_in(), Some(0));
148 assert_eq!(timer.poll(), Some("hi"));
149
150 assert_eq!(timer.next_in(), Some(10));
151
152 timer.tick(10);
153 assert_eq!(timer.next_in(), Some(0));
154 assert_eq!(timer.poll(), Some("there"));
155
156 timer.tick(3);
157 assert_eq!(timer.next_in(), Some(7));
158 }
159
160 #[test]
161 fn timer_remove() {
162 let mut timer = PullTimer::new();
163
164 timer.add(100, "boom!");
165 timer.tick(50);
166 assert_eq!(timer.remove("boom!"), Some(50));
167 assert_eq!(timer.next_in(), None);
168 }
169
170 #[test]
171 fn timer_fires_after_remove() {
172 let mut timer = PullTimer::new();
173
174 timer.add(30, 30);
175 timer.add(20, 20);
176 timer.add(40, 40);
177 timer.add(10, 10);
178 timer.add(50, 50);
179
180 assert_eq!(timer.remove(50), Some(50));
181 assert_eq!(timer.remove(10), Some(10));
182
183 for i in 0..=41 {
184 if let Some(value) = timer.poll() {
185 assert_eq!(value, i);
186 }
187 timer.tick(1);
188 }
189 }
190}