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
77impl<T> Iterator for PullTimer<T> {
78 type Item = T;
79
80 fn next(&mut self) -> Option<T> {
81 let &(delta, _) = self.0.front()?;
82
83 if delta == 0 {
84 self.0.pop_front().map(|(_, event)| event)
85 } else {
86 None
87 }
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn timer_preserves_fifo_order() {
97 let mut timer = PullTimer::new();
98
99 timer.add(0, "testing");
100 timer.add(0, "one two three");
101
102 assert_eq!(timer.next(), Some("testing"));
103 assert_eq!(timer.next(), Some("one two three"));
104 assert_eq!(timer.next(), None);
105 }
106
107 #[test]
108 fn timer_fires_in_order() {
109 let mut timer = PullTimer::new();
110
111 timer.add(4, "test");
112 timer.add(3, "a");
113 timer.add(2, "is");
114 timer.add(1, "this");
115
116 timer.tick(4);
117
118 assert_eq!(timer.next(), Some("this"));
119 assert_eq!(timer.next(), Some("is"));
120 assert_eq!(timer.next(), Some("a"));
121 assert_eq!(timer.next(), Some("test"));
122 assert_eq!(timer.next(), None);
123 }
124
125 #[test]
126 fn timer_fires_in_time() {
127 let mut timer = PullTimer::new();
128
129 timer.add(40, 40);
130 timer.add(20, 20);
131 timer.add(0, 0);
132 timer.add(30, 30);
133 timer.add(10, 10);
134
135 for i in 0..=41 {
136 if let Some(value) = timer.next() {
137 assert_eq!(value, i);
138 }
139 timer.tick(1);
140 }
141 }
142
143 #[test]
144 fn timer_next_in() {
145 let mut timer = PullTimer::new();
146
147 timer.add(0, "hi");
148 timer.add(20, "!");
149 timer.add(10, "there");
150
151 assert_eq!(timer.next_in(), Some(0));
152 assert_eq!(timer.next(), Some("hi"));
153
154 assert_eq!(timer.next_in(), Some(10));
155
156 timer.tick(10);
157 assert_eq!(timer.next_in(), Some(0));
158 assert_eq!(timer.next(), Some("there"));
159
160 timer.tick(3);
161 assert_eq!(timer.next_in(), Some(7));
162 }
163
164 #[test]
165 fn timer_remove() {
166 let mut timer = PullTimer::new();
167
168 timer.add(100, "boom!");
169 timer.tick(50);
170 assert_eq!(timer.remove("boom!"), Some(50));
171 assert_eq!(timer.next_in(), None);
172 }
173
174 #[test]
175 fn timer_fires_after_remove() {
176 let mut timer = PullTimer::new();
177
178 timer.add(30, 30);
179 timer.add(20, 20);
180 timer.add(40, 40);
181 timer.add(10, 10);
182 timer.add(50, 50);
183
184 assert_eq!(timer.remove(50), Some(50));
185 assert_eq!(timer.remove(10), Some(10));
186
187 for i in 0..=41 {
188 if let Some(value) = timer.next() {
189 assert_eq!(value, i);
190 }
191 timer.tick(1);
192 }
193 }
194}