concinnity_core/render/
slot_rewrites.rs1use alloc::vec::Vec;
11
12#[derive(Debug)]
13pub struct SlotRewriteQueue {
15 entries: Vec<(usize, usize)>,
17 frames_in_flight: usize,
18}
19
20impl SlotRewriteQueue {
21 pub fn new(frames_in_flight: usize) -> Self {
23 Self {
24 entries: Vec::new(),
25 frames_in_flight: frames_in_flight.max(1),
26 }
27 }
28
29 pub fn queue(&mut self, slot: usize) {
34 if let Some(entry) = self.entries.iter_mut().find(|(s, _)| *s == slot) {
35 entry.1 = self.frames_in_flight;
36 } else {
37 self.entries.push((slot, self.frames_in_flight));
38 }
39 }
40
41 pub fn begin_frame(&mut self) -> Vec<usize> {
45 let slots: Vec<usize> = self.entries.iter().map(|(s, _)| *s).collect();
46 for entry in &mut self.entries {
47 entry.1 -= 1;
48 }
49 self.entries.retain(|(_, remaining)| *remaining > 0);
50 slots
51 }
52
53 pub fn remove(&mut self, slot: usize) {
56 self.entries.retain(|(s, _)| *s != slot);
57 }
58
59 pub fn is_empty(&self) -> bool {
61 self.entries.is_empty()
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 use alloc::vec;
70 #[test]
71 fn a_slot_is_applied_once_per_frame_copy() {
72 let mut q = SlotRewriteQueue::new(3);
73 q.queue(7);
74 assert_eq!(q.begin_frame(), vec![7]);
75 assert_eq!(q.begin_frame(), vec![7]);
76 assert_eq!(q.begin_frame(), vec![7]);
77 assert!(q.begin_frame().is_empty());
78 assert!(q.is_empty());
79 }
80
81 #[test]
82 fn requeueing_mid_propagation_restarts_the_countdown() {
83 let mut q = SlotRewriteQueue::new(3);
84 q.queue(4);
85 assert_eq!(q.begin_frame(), vec![4]);
86 q.queue(4);
89 assert_eq!(q.begin_frame(), vec![4]);
90 assert_eq!(q.begin_frame(), vec![4]);
91 assert_eq!(q.begin_frame(), vec![4]);
92 assert!(q.begin_frame().is_empty());
93 }
94
95 #[test]
96 fn independent_slots_propagate_independently() {
97 let mut q = SlotRewriteQueue::new(2);
98 q.queue(1);
99 assert_eq!(q.begin_frame(), vec![1]);
100 q.queue(2);
101 let mut slots = q.begin_frame();
102 slots.sort_unstable();
103 assert_eq!(slots, vec![1, 2]);
104 assert_eq!(q.begin_frame(), vec![2]);
105 assert!(q.begin_frame().is_empty());
106 }
107
108 #[test]
109 fn remove_drops_a_queued_slot() {
110 let mut q = SlotRewriteQueue::new(3);
111 q.queue(5);
112 q.queue(6);
113 q.remove(5);
114 assert_eq!(q.begin_frame(), vec![6]);
115 }
116
117 #[test]
118 fn zero_frames_in_flight_is_clamped_to_one() {
119 let mut q = SlotRewriteQueue::new(0);
120 q.queue(9);
121 assert_eq!(q.begin_frame(), vec![9]);
122 assert!(q.is_empty());
123 }
124}