pub(super) struct PendingWork {
pub(super) needs_redraw: bool,
pub(super) subscriptions_dirty: bool,
}
impl PendingWork {
pub(super) const fn new() -> Self {
Self {
needs_redraw: true,
subscriptions_dirty: false,
}
}
pub(super) const fn record_redraw(&mut self, requested: bool) {
self.needs_redraw |= requested;
}
pub(super) const fn mark_subscriptions_dirty(&mut self) {
self.subscriptions_dirty = true;
}
pub(super) const fn has_pending_work(&self) -> bool {
self.needs_redraw || self.subscriptions_dirty
}
pub(super) const fn take_redraw(&mut self) -> bool {
let pending = self.needs_redraw;
self.needs_redraw = false;
pending
}
pub(super) const fn take_subscriptions_dirty(&mut self) -> bool {
let pending = self.subscriptions_dirty;
self.subscriptions_dirty = false;
pending
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_starts_with_a_pending_first_frame() {
let pending = PendingWork::new();
assert!(pending.needs_redraw, "the first frame must render");
assert!(
!pending.subscriptions_dirty,
"initial subscriptions are started outside the frame loop"
);
assert!(pending.has_pending_work());
}
#[test]
fn has_pending_work_is_the_or_of_both_flags() {
for (needs_redraw, subscriptions_dirty, expected) in [
(false, false, false),
(true, false, true),
(false, true, true),
(true, true, true),
] {
let pending = PendingWork {
needs_redraw,
subscriptions_dirty,
};
assert_eq!(
pending.has_pending_work(),
expected,
"needs_redraw={needs_redraw}, subscriptions_dirty={subscriptions_dirty}"
);
}
}
#[test]
fn record_redraw_never_clears_an_existing_request() {
let mut pending = PendingWork::new();
pending.take_redraw();
pending.record_redraw(false);
assert!(!pending.needs_redraw);
pending.record_redraw(true);
assert!(pending.needs_redraw);
pending.record_redraw(false);
assert!(pending.needs_redraw);
}
#[test]
fn mark_subscriptions_dirty_sets_the_flag() {
let mut pending = PendingWork::new();
assert!(!pending.subscriptions_dirty);
pending.mark_subscriptions_dirty();
assert!(pending.subscriptions_dirty);
}
#[test]
fn take_redraw_returns_then_clears() {
let mut pending = PendingWork::new();
assert!(pending.take_redraw(), "initial state has a pending redraw");
assert!(!pending.needs_redraw);
assert!(!pending.take_redraw(), "already taken");
}
#[test]
fn take_subscriptions_dirty_returns_then_clears() {
let mut pending = PendingWork::new();
pending.mark_subscriptions_dirty();
assert!(pending.take_subscriptions_dirty());
assert!(!pending.subscriptions_dirty);
assert!(!pending.take_subscriptions_dirty(), "already taken");
}
#[test]
fn goes_idle_once_pending_work_is_drained() {
let mut pending = PendingWork::new();
pending.mark_subscriptions_dirty();
pending.take_redraw();
pending.take_subscriptions_dirty();
assert!(!pending.has_pending_work());
pending.mark_subscriptions_dirty();
assert!(pending.has_pending_work());
}
}