wavecraft_dev_server/reload/
guard.rs1use std::sync::atomic::{AtomicBool, Ordering};
7
8const STATE_ORDERING: Ordering = Ordering::SeqCst;
9
10pub struct BuildGuard {
15 building: AtomicBool,
16 pending: AtomicBool,
17}
18
19impl BuildGuard {
20 pub fn new() -> Self {
21 Self {
22 building: AtomicBool::new(false),
23 pending: AtomicBool::new(false),
24 }
25 }
26
27 pub fn try_start(&self) -> bool {
29 try_transition(&self.building, false, true)
30 }
31
32 pub fn mark_pending(&self) {
34 store_state(&self.pending, true);
35 }
36
37 pub fn complete(&self) -> bool {
39 store_state(&self.building, false);
40 take_state(&self.pending)
41 }
42}
43
44fn try_transition(flag: &AtomicBool, current: bool, new: bool) -> bool {
45 flag.compare_exchange(current, new, STATE_ORDERING, STATE_ORDERING)
46 .is_ok()
47}
48
49fn store_state(flag: &AtomicBool, value: bool) {
50 flag.store(value, STATE_ORDERING);
51}
52
53fn take_state(flag: &AtomicBool) -> bool {
54 flag.swap(false, STATE_ORDERING)
55}
56
57impl Default for BuildGuard {
58 fn default() -> Self {
59 Self::new()
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn test_build_guard_single_build() {
69 let guard = BuildGuard::new();
70
71 assert!(guard.try_start());
73
74 assert!(!guard.try_start());
76
77 assert!(!guard.complete());
79
80 assert!(guard.try_start());
82 guard.complete();
83 }
84
85 #[test]
86 fn test_build_guard_pending() {
87 let guard = BuildGuard::new();
88
89 assert!(guard.try_start());
91
92 assert!(!guard.try_start());
94
95 guard.mark_pending();
97
98 assert!(guard.complete());
100
101 assert!(guard.try_start());
103 assert!(!guard.complete());
104 }
105
106 #[test]
107 fn test_build_guard_multiple_pending() {
108 let guard = BuildGuard::new();
109
110 assert!(guard.try_start());
112
113 guard.mark_pending();
115 guard.mark_pending();
116 guard.mark_pending();
117
118 assert!(guard.complete());
120
121 assert!(!guard.complete());
123 }
124}