Skip to main content

ak_vis/viewer/session/
readiness.rs

1use 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}