umsh_ux_display_tracker/
boot.rs1#[derive(Clone, Copy, Debug)]
8pub struct BootSplash {
9 active: bool,
10 deadline_ms: Option<u64>,
11}
12
13impl BootSplash {
14 pub const fn new() -> Self {
15 Self {
16 active: true,
17 deadline_ms: None,
18 }
19 }
20
21 pub const fn is_active(&self) -> bool {
22 self.active
23 }
24
25 pub fn shown(&mut self, now_ms: u64) {
27 if self.active && self.deadline_ms.is_none() {
28 self.deadline_ms = Some(now_ms.saturating_add(2_000));
29 }
30 }
31
32 pub const fn next_deadline(&self) -> Option<u64> {
33 self.deadline_ms
34 }
35
36 pub fn dismiss(&mut self) -> bool {
38 self.deadline_ms = None;
39 core::mem::replace(&mut self.active, false)
40 }
41
42 pub fn poll(&mut self, now_ms: u64) -> bool {
44 if self.deadline_ms.is_some_and(|deadline| now_ms >= deadline) {
45 self.dismiss()
46 } else {
47 false
48 }
49 }
50}
51
52impl Default for BootSplash {
53 fn default() -> Self {
54 Self::new()
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn the_two_visible_seconds_start_after_the_refresh() {
64 let mut splash = BootSplash::new();
65 assert!(!splash.poll(2_000));
66 assert_eq!(splash.next_deadline(), None);
67 splash.shown(2_000);
68 assert_eq!(splash.next_deadline(), Some(4_000));
69 assert!(!splash.poll(3_999));
70 splash.shown(3_999);
72 assert!(splash.poll(4_000));
73 assert!(!splash.is_active());
74 assert!(!splash.poll(4_001));
75 splash.shown(5_000);
76 assert_eq!(splash.next_deadline(), None);
77 }
78
79 #[test]
80 fn dismissal_is_final_even_before_the_initial_refresh_finishes() {
81 for shown in [false, true] {
82 let mut splash = BootSplash::new();
83 if shown {
84 splash.shown(100);
85 }
86 assert!(splash.dismiss());
87 assert!(!splash.dismiss());
88 splash.shown(200);
89 assert!(!splash.is_active());
90 assert_eq!(splash.next_deadline(), None);
91 assert!(!splash.poll(10_000));
92 }
93 }
94}