thedes_tui_core/panic/restore/
mock.rs1use std::{
2 sync::{
3 Arc,
4 atomic::{AtomicBool, Ordering::*},
5 },
6 thread,
7};
8
9use super::PanicRestoreGuard;
10
11#[derive(Debug)]
12struct Shared {
13 open: AtomicBool,
14 enabled: AtomicBool,
15 called: AtomicBool,
16 executed: AtomicBool,
17}
18
19impl Shared {
20 pub fn new() -> Self {
21 Self {
22 open: AtomicBool::new(false),
23 enabled: AtomicBool::new(true),
24 called: AtomicBool::new(false),
25 executed: AtomicBool::new(false),
26 }
27 }
28
29 pub fn mark_device_open(&self) -> bool {
30 !self.open.swap(true, AcqRel)
31 }
32
33 pub fn enabled(&self) -> bool {
34 self.enabled.load(Acquire)
35 }
36
37 pub fn disable(&self) -> bool {
38 self.enabled.swap(false, AcqRel)
39 }
40
41 pub fn called(&self) -> bool {
42 self.called.load(Acquire)
43 }
44
45 pub fn mark_called(&self) -> bool {
46 !self.called.swap(true, AcqRel)
47 }
48
49 pub fn executed(&self) -> bool {
50 self.executed.load(Acquire)
51 }
52
53 pub fn mark_executed(&self) -> bool {
54 self.mark_called();
55 !self.executed.swap(true, AcqRel)
56 }
57}
58
59#[derive(Debug, Clone)]
60pub struct PanicRestoreMock {
61 shared: Arc<Shared>,
62}
63
64impl PanicRestoreMock {
65 pub fn new() -> Self {
66 Self { shared: Arc::new(Shared::new()) }
67 }
68
69 pub fn open(&self) -> Box<dyn PanicRestoreGuard> {
70 if !self.shared.mark_device_open() {
71 panic!("Mocked input device was already open for this mock");
72 }
73 Box::new(MockedPanicRestoreGuard::new(self.clone()))
74 }
75
76 pub fn enabled(&self) -> bool {
77 self.shared.enabled()
78 }
79
80 fn disable(&self) -> bool {
81 self.shared.disable()
82 }
83
84 pub fn called(&self) -> bool {
85 self.shared.called()
86 }
87
88 fn mark_called(&self) -> bool {
89 self.shared.mark_called()
90 }
91
92 pub fn executed(&self) -> bool {
93 self.shared.executed()
94 }
95
96 fn mark_executed(&self) -> bool {
97 self.shared.mark_executed()
98 }
99}
100
101#[derive(Debug)]
102struct MockedPanicRestoreGuard {
103 mock: PanicRestoreMock,
104}
105
106impl MockedPanicRestoreGuard {
107 pub fn new(mock: PanicRestoreMock) -> Self {
108 Self { mock }
109 }
110}
111
112impl PanicRestoreGuard for MockedPanicRestoreGuard {
113 fn cancel(self: Box<Self>) {
114 self.mock.disable();
115 }
116}
117
118impl Drop for MockedPanicRestoreGuard {
119 fn drop(&mut self) {
120 self.mock.mark_called();
121 if self.mock.enabled() && thread::panicking() {
122 self.mock.mark_executed();
123 }
124 }
125}