use crate::{ShellEvent, WindowId};
#[derive(Debug, Default)]
pub(crate) struct FrameRequests {
windows: Vec<WindowId>,
}
impl FrameRequests {
pub(crate) fn request(&mut self, window: WindowId) {
if !self.windows.contains(&window) {
self.windows.push(window);
}
}
pub(crate) fn is_pending(&self) -> bool {
!self.windows.is_empty()
}
pub(crate) fn contains(&self, window: WindowId) -> bool {
self.windows.contains(&window)
}
pub(crate) fn take_due(
&mut self,
is_live: impl Fn(WindowId) -> bool,
) -> impl Iterator<Item = ShellEvent> {
core::mem::take(&mut self.windows)
.into_iter()
.filter(move |window| is_live(*window))
.map(|window| ShellEvent::FrameReady { window })
}
}
#[cfg(test)]
mod tests {
use super::*;
use crcbl_core::Pool;
fn windows() -> (WindowId, WindowId) {
let mut pool: Pool<u8> = Pool::new();
(pool.insert(0).cast(), pool.insert(1).cast())
}
#[test]
fn requests_before_the_delivery_share_one_answer() {
let (first, second) = windows();
let mut frames = FrameRequests::default();
assert!(!frames.is_pending());
frames.request(first);
frames.request(second);
frames.request(first);
assert!(frames.is_pending());
assert!(frames.contains(first));
let due: Vec<ShellEvent> = frames.take_due(|_| true).collect();
assert_eq!(
due,
[
ShellEvent::FrameReady { window: first },
ShellEvent::FrameReady { window: second },
]
);
assert!(!frames.is_pending(), "a delivery answers every request");
assert!(!frames.contains(first));
assert_eq!(frames.take_due(|_| true).count(), 0);
}
#[test]
fn a_window_gone_before_the_delivery_gets_no_answer() {
let (gone, live) = windows();
let mut frames = FrameRequests::default();
frames.request(gone);
frames.request(live);
let due: Vec<ShellEvent> = frames.take_due(|window| window == live).collect();
assert_eq!(due, [ShellEvent::FrameReady { window: live }]);
assert!(!frames.is_pending(), "the dead window's request is dropped");
}
}