thedes_tui_core/panic/restore/
mock.rs

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