input/thread/
mod.rs

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
15/// The name of the input thread.
16pub const THREAD_NAME: &str = "input";
17const MINIMUM_PAUSE_RATE: Duration = Duration::from_millis(250);
18
19/// A thread for reading and handling input events.
20#[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	/// Create a new instance of a thread.
85	#[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	/// Get a cloned copy of the state of the thread.
94	#[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}