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