1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum Readiness {
10 Pending,
12 Ready,
15 OnCapture,
18}
19
20#[derive(Clone, Default)]
24pub struct Fence(std::rc::Rc<std::cell::RefCell<State>>);
25#[derive(Default)]
26struct State {
27 revision: Option<u32>,
28 result: Option<Result<(), String>>,
29}
30impl Fence {
31 pub fn begin(&self, revision: u32) -> bool {
33 let mut s = self.0.borrow_mut();
34 if s.revision == Some(revision) {
35 return false;
36 }
37 *s = State {
38 revision: Some(revision),
39 result: None,
40 };
41 true
42 }
43 pub fn complete(&self, revision: u32, result: Result<(), String>) {
44 let mut s = self.0.borrow_mut();
45 if s.revision == Some(revision) && s.result.is_none() {
46 s.result = Some(result);
47 }
48 }
49 pub fn poll(&self) -> Result<Readiness, String> {
50 match self.0.borrow().result.as_ref() {
51 None => Ok(Readiness::Pending),
52 Some(Ok(())) => Ok(Readiness::Ready),
53 Some(Err(e)) => Err(e.clone()),
54 }
55 }
56}
57
58pub type Hold = fn() -> bool;
68
69static HOLDS: std::sync::Mutex<Vec<Hold>> = std::sync::Mutex::new(Vec::new());
70
71pub fn register_hold(hold: Hold) {
74 HOLDS
75 .lock()
76 .unwrap_or_else(|poisoned| poisoned.into_inner())
77 .push(hold);
78}
79
80pub fn holds_settled() -> bool {
83 let holds = HOLDS
84 .lock()
85 .unwrap_or_else(|poisoned| poisoned.into_inner())
86 .clone();
87 holds.iter().all(|hold| hold())
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 #[test]
94 fn checkpoints_do_not_rearm_or_accept_late_completions() {
95 let f = Fence::default();
96 assert!(f.begin(1));
97 assert!(!f.begin(1));
98 assert_eq!(f.poll(), Ok(Readiness::Pending));
99 assert!(f.begin(2));
100 f.clone().complete(1, Ok(()));
101 assert_eq!(f.poll(), Ok(Readiness::Pending));
102 f.complete(2, Ok(()));
103 assert_eq!(f.poll(), Ok(Readiness::Ready));
104 assert!(!f.begin(2));
105 }
106 #[test]
107 fn a_hold_defers_captures_until_it_settles() {
108 use std::sync::atomic::{AtomicBool, Ordering};
109 static SETTLED: AtomicBool = AtomicBool::new(false);
110 assert!(holds_settled());
112 register_hold(|| SETTLED.load(Ordering::Relaxed));
113 assert!(!holds_settled());
114 SETTLED.store(true, Ordering::Relaxed);
115 assert!(holds_settled());
116 }
117 #[test]
118 fn errors_and_windows_are_independent() {
119 let a = Fence::default();
120 let b = Fence::default();
121 a.begin(7);
122 b.begin(7);
123 a.complete(7, Err("window closed".into()));
124 a.complete(7, Ok(()));
125 assert_eq!(a.poll(), Err("window closed".into()));
126 assert_eq!(b.poll(), Ok(Readiness::Pending));
127 a.begin(8);
128 a.complete(8, Ok(()));
129 assert_eq!(a.poll(), Ok(Readiness::Ready));
130 }
131}