ak_vis/viewer/session/
readiness.rs1use std::sync::{Condvar, Mutex};
2use std::time::{Duration, Instant};
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5enum ViewerLifecycleState {
6 Pending,
7 Ready,
8 Closed,
9}
10
11#[derive(Debug)]
12pub struct ViewerReadiness {
13 state: Mutex<ViewerLifecycleState>,
14 changed: Condvar,
15}
16
17impl ViewerReadiness {
18 pub fn new() -> Self {
19 Self {
20 state: Mutex::new(ViewerLifecycleState::Pending),
21 changed: Condvar::new(),
22 }
23 }
24
25 pub fn mark_ready(&self) {
26 let mut state = self.state.lock().expect("viewer readiness mutex poisoned");
27 if *state == ViewerLifecycleState::Pending {
28 *state = ViewerLifecycleState::Ready;
29 self.changed.notify_all();
30 }
31 }
32
33 pub fn mark_closed(&self) {
34 let mut state = self.state.lock().expect("viewer readiness mutex poisoned");
35 if *state != ViewerLifecycleState::Closed {
36 *state = ViewerLifecycleState::Closed;
37 self.changed.notify_all();
38 }
39 }
40
41 pub fn wait(&self, timeout: Option<Duration>) -> bool {
42 let mut state = self.state.lock().expect("viewer readiness mutex poisoned");
43
44 match timeout {
45 Some(timeout) => {
46 let deadline = Instant::now() + timeout;
47 while *state == ViewerLifecycleState::Pending {
48 let now = Instant::now();
49 if now >= deadline {
50 return false;
51 }
52
53 let remaining = deadline.saturating_duration_since(now);
54 let (next_state, result) = self
55 .changed
56 .wait_timeout(state, remaining)
57 .expect("viewer readiness mutex poisoned");
58 state = next_state;
59 if result.timed_out() && *state == ViewerLifecycleState::Pending {
60 return false;
61 }
62 }
63 }
64 None => {
65 while *state == ViewerLifecycleState::Pending {
66 state = self
67 .changed
68 .wait(state)
69 .expect("viewer readiness mutex poisoned");
70 }
71 }
72 }
73
74 *state == ViewerLifecycleState::Ready
75 }
76}
77
78impl Default for ViewerReadiness {
79 fn default() -> Self {
80 Self::new()
81 }
82}