sbom_tools/tui/viewmodel/
status.rs1use std::time::{Duration, Instant};
7
8#[derive(Debug, Clone, Default)]
27pub struct StatusMessage {
28 message: Option<String>,
30 set_at: Option<Instant>,
32 auto_clear_after: Option<Duration>,
34}
35
36impl StatusMessage {
37 #[must_use]
39 pub fn new() -> Self {
40 Self::default()
41 }
42
43 #[must_use]
45 pub const fn with_auto_clear(duration: Duration) -> Self {
46 Self {
47 message: None,
48 set_at: None,
49 auto_clear_after: Some(duration),
50 }
51 }
52
53 pub fn set(&mut self, msg: impl Into<String>) {
55 self.message = Some(msg.into());
56 self.set_at = Some(Instant::now());
57 }
58
59 pub fn clear(&mut self) {
61 self.message = None;
62 self.set_at = None;
63 }
64
65 pub fn message(&mut self) -> Option<&str> {
67 if let (Some(set_at), Some(duration)) = (self.set_at, self.auto_clear_after)
69 && set_at.elapsed() >= duration
70 {
71 self.message = None;
72 self.set_at = None;
73 }
74 self.message.as_deref()
75 }
76
77 #[must_use]
81 pub fn peek(&self) -> Option<&str> {
82 self.message.as_deref()
83 }
84
85 #[must_use]
87 pub const fn has_message(&self) -> bool {
88 self.message.is_some()
89 }
90
91 #[must_use]
95 pub const fn as_option(&self) -> &Option<String> {
96 &self.message
97 }
98
99 pub const fn take(&mut self) -> Option<String> {
101 self.set_at = None;
102 self.message.take()
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use std::thread;
110
111 #[test]
112 fn test_status_message_set_clear() {
113 let mut status = StatusMessage::new();
114
115 assert!(!status.has_message());
116 assert!(status.peek().is_none());
117
118 status.set("Test message");
119 assert!(status.has_message());
120 assert_eq!(status.peek(), Some("Test message"));
121
122 status.clear();
123 assert!(!status.has_message());
124 assert!(status.peek().is_none());
125 }
126
127 #[test]
128 fn test_status_message_take() {
129 let mut status = StatusMessage::new();
130
131 status.set("Take me");
132 let taken = status.take();
133
134 assert_eq!(taken, Some("Take me".to_string()));
135 assert!(!status.has_message());
136 }
137
138 #[test]
139 fn test_status_message_auto_clear() {
140 let mut status = StatusMessage::with_auto_clear(Duration::from_millis(50));
141
142 status.set("Auto clear message");
143 assert!(status.message().is_some());
144
145 thread::sleep(Duration::from_millis(60));
147 assert!(status.message().is_none());
148 }
149
150 #[test]
151 fn test_status_message_no_auto_clear_default() {
152 let mut status = StatusMessage::new();
153
154 status.set("No auto clear");
155 thread::sleep(Duration::from_millis(10));
156 assert!(status.message().is_some()); }
158}