1mod state;
2
3use std::{
4 sync::Arc,
5 thread::sleep,
6 time::{Duration, Instant},
7};
8
9use captur::capture;
10use runtime::{Installer, Threadable};
11pub use state::State;
12
13use crate::{event::Event, event_provider::EventReaderFn};
14
15pub const THREAD_NAME: &str = "input";
17const MINIMUM_PAUSE_RATE: Duration = Duration::from_millis(250);
18
19#[derive(Debug)]
21pub struct Thread<EventProvider, CustomEvent>
22where
23 EventProvider: EventReaderFn,
24 CustomEvent: crate::CustomEvent + 'static,
25{
26 event_provider: Arc<EventProvider>,
27 state: State<CustomEvent>,
28}
29
30impl<EventProvider, CustomEvent> Threadable for Thread<EventProvider, CustomEvent>
31where
32 EventProvider: EventReaderFn,
33 CustomEvent: crate::CustomEvent + Send + Sync + 'static,
34{
35 #[inline]
36 fn install(&self, installer: &Installer) {
37 let state = self.state();
38 let event_provider = Arc::clone(&self.event_provider);
39
40 installer.spawn(THREAD_NAME, |notifier| {
41 move || {
42 capture!(notifier, state, event_provider);
43 let mut time = Instant::now();
44 notifier.busy();
45 while !state.is_ended() {
46 while state.is_paused() {
47 notifier.wait();
48 sleep(time.saturating_duration_since(Instant::now()));
49 time += MINIMUM_PAUSE_RATE;
50 }
51 notifier.busy();
52 if let Ok(Some(event)) = (event_provider)() {
53 state.enqueue_event(Event::from(event));
54 }
55 }
56
57 notifier.end();
58 notifier.request_end();
59 }
60 });
61 }
62
63 #[inline]
64 fn pause(&self) {
65 self.state.pause();
66 }
67
68 #[inline]
69 fn resume(&self) {
70 self.state.resume();
71 }
72
73 #[inline]
74 fn end(&self) {
75 self.state.end();
76 }
77}
78
79impl<EventProvider, CustomEvent> Thread<EventProvider, CustomEvent>
80where
81 EventProvider: EventReaderFn,
82 CustomEvent: crate::CustomEvent + 'static,
83{
84 #[inline]
86 pub fn new(event_provider: EventProvider) -> Self {
87 Self {
88 event_provider: Arc::new(event_provider),
89 state: State::new(),
90 }
91 }
92
93 #[inline]
95 #[must_use]
96 pub fn state(&self) -> State<CustomEvent> {
97 self.state.clone()
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use anyhow::anyhow;
104 use crossterm::event::{KeyCode, KeyModifiers};
105 use runtime::{testutils::ThreadableTester, Status};
106
107 use super::*;
108 use crate::{
109 testutil::local::{create_event_reader, TestEvent},
110 KeyEvent,
111 };
112
113 #[test]
114 fn set_pause_resume() {
115 let event_provider = create_event_reader(|| Ok(None));
116 let thread: Thread<_, TestEvent> = Thread::new(event_provider);
117 let state = thread.state();
118 thread.pause();
119 assert!(state.is_paused());
120 thread.resume();
121 assert!(!state.is_paused());
122 }
123
124 #[test]
125 fn set_end() {
126 let event_provider = create_event_reader(|| Ok(None));
127 let thread: Thread<_, TestEvent> = Thread::new(event_provider);
128 let state = thread.state();
129 thread.end();
130 assert!(state.is_ended());
131 }
132
133 #[test]
134 fn read_event_from_event_provider() {
135 let event_provider = create_event_reader(|| {
136 Ok(Some(Event::Key(KeyEvent::new(
137 KeyCode::Char('a'),
138 KeyModifiers::empty(),
139 ))))
140 });
141 let thread: Thread<_, TestEvent> = Thread::new(event_provider);
142 let state = thread.state();
143
144 let tester = ThreadableTester::new();
145 tester.start_threadable(&thread, THREAD_NAME);
146
147 let event_received;
148 loop {
149 let event = state.read_event();
150 if event != Event::None {
151 event_received = event;
152 break;
153 }
154 }
155 state.end();
156
157 assert_eq!(event_received, Event::from('a'));
158 }
159
160 #[test]
161 fn read_none_event() {
162 let event_provider = create_event_reader(|| Ok(None));
163 let thread: Thread<_, TestEvent> = Thread::new(event_provider);
164 let state = thread.state();
165
166 let tester = ThreadableTester::new();
167 tester.start_threadable(&thread, THREAD_NAME);
168 tester.wait_for_status(&Status::Busy);
169 let event_received = state.read_event();
170 state.end();
171 tester.wait_for_finished();
172 assert_eq!(event_received, Event::None);
173 }
174
175 #[test]
176 fn read_error() {
177 let event_provider = create_event_reader(|| Err(anyhow!("Err")));
178 let thread: Thread<_, TestEvent> = Thread::new(event_provider);
179 let state = thread.state();
180
181 let tester = ThreadableTester::new();
182 tester.start_threadable(&thread, THREAD_NAME);
183 tester.wait_for_status(&Status::Busy);
184 let event_received = state.read_event();
185 state.end();
186 tester.wait_for_finished();
187 assert_eq!(event_received, Event::None);
188 }
189
190 #[test]
191 fn pause_resume() {
192 let event_provider = create_event_reader(|| Ok(None));
193 let thread: Thread<_, TestEvent> = Thread::new(event_provider);
194 let state = thread.state();
195
196 let tester = ThreadableTester::new();
197 tester.start_threadable(&thread, THREAD_NAME);
198 tester.wait_for_status(&Status::Busy);
199 state.pause();
200 tester.wait_for_status(&Status::Waiting);
201 state.resume();
202 tester.wait_for_status(&Status::Busy);
203 state.end();
204 tester.wait_for_finished();
205 }
206}