thedes_tui_core/runtime/device/
mock.rs1use std::sync::{
2 Arc,
3 atomic::{AtomicBool, Ordering::*},
4};
5
6use crate::{
7 audio::device::{AudioDevice, mock::AudioDeviceMock},
8 geometry::CoordPair,
9 input::device::{InputDevice, mock::InputDeviceMock},
10 panic::restore::{PanicRestoreGuard, mock::PanicRestoreMock},
11 screen::device::{ScreenDevice, mock::ScreenDeviceMock},
12};
13
14use super::{Error, RuntimeDevice};
15
16#[derive(Debug)]
17struct Shared {
18 open: AtomicBool,
19 initialized: AtomicBool,
20}
21
22impl Shared {
23 pub fn new() -> Self {
24 Self {
25 open: AtomicBool::new(false),
26 initialized: AtomicBool::new(false),
27 }
28 }
29
30 pub fn initialized(&self) -> bool {
31 self.initialized.load(Acquire)
32 }
33
34 pub fn initialize(&self) -> bool {
35 !self.initialized.swap(true, AcqRel)
36 }
37
38 pub fn shutdown(&self) -> bool {
39 self.initialized.swap(false, AcqRel)
40 }
41
42 pub fn mark_device_open(&self) -> bool {
43 !self.open.swap(true, AcqRel)
44 }
45}
46
47#[derive(Debug, Clone)]
48pub struct RuntimeDeviceMock {
49 screen: ScreenDeviceMock,
50 input: InputDeviceMock,
51 audio: AudioDeviceMock,
52 panic_restore: PanicRestoreMock,
53 shared: Arc<Shared>,
54}
55
56impl RuntimeDeviceMock {
57 pub fn new(term_size: CoordPair) -> Self {
58 Self {
59 screen: ScreenDeviceMock::new(term_size),
60 input: InputDeviceMock::new(),
61 audio: AudioDeviceMock::new(),
62 panic_restore: PanicRestoreMock::new(),
63 shared: Arc::new(Shared::new()),
64 }
65 }
66
67 pub fn initialized(&self) -> bool {
68 self.shared.initialized()
69 }
70
71 fn initialize(&self) -> bool {
72 self.shared.initialize()
73 }
74
75 fn shutdown(&self) -> bool {
76 self.shared.shutdown()
77 }
78
79 pub fn screen(&self) -> &ScreenDeviceMock {
80 &self.screen
81 }
82
83 pub fn input(&self) -> &InputDeviceMock {
84 &self.input
85 }
86
87 pub fn audio(&self) -> &AudioDeviceMock {
88 &self.audio
89 }
90
91 pub fn panic_restore(&self) -> &PanicRestoreMock {
92 &self.panic_restore
93 }
94
95 pub fn open(&self) -> Box<dyn RuntimeDevice> {
96 if !self.shared.mark_device_open() {
97 panic!("Mocked runtime device was already open for this mock");
98 }
99 Box::new(MockedRuntimeDevice::new(self.clone()))
100 }
101}
102
103#[derive(Debug)]
104struct MockedRuntimeDevice {
105 mock: RuntimeDeviceMock,
106}
107
108impl MockedRuntimeDevice {
109 pub fn new(mock: RuntimeDeviceMock) -> Self {
110 Self { mock }
111 }
112}
113
114impl RuntimeDevice for MockedRuntimeDevice {
115 fn blocking_init(&mut self) -> Result<(), Error> {
116 if self.mock.initialize() { Ok(()) } else { Err(Error::AlreadyInit) }
117 }
118
119 fn blocking_shutdown(&mut self) -> Result<(), Error> {
120 if self.mock.shutdown() { Ok(()) } else { Err(Error::NotInit) }
121 }
122
123 fn open_input_device(&mut self) -> Box<dyn InputDevice> {
124 self.mock.input().open()
125 }
126
127 fn open_screen_device(&mut self) -> Box<dyn ScreenDevice> {
128 self.mock.screen().open()
129 }
130
131 fn open_audio_device(&mut self) -> Box<dyn AudioDevice> {
132 self.mock.audio().open()
133 }
134
135 fn open_panic_restore_guard(&mut self) -> Box<dyn PanicRestoreGuard> {
136 self.mock.panic_restore().open()
137 }
138}