Don't try to join the input thread

This commit is contained in:
mo8it 2024-04-09 22:04:10 +02:00
parent 4110ae21af
commit ff6c15f9c1

View file

@ -1,4 +1,4 @@
use anyhow::{bail, Context, Result}; use anyhow::Result;
use notify_debouncer_mini::{ use notify_debouncer_mini::{
new_debouncer, new_debouncer,
notify::{self, RecursiveMode}, notify::{self, RecursiveMode},
@ -29,6 +29,7 @@ enum WatchEvent {
Input(InputEvent), Input(InputEvent),
FileChange { exercise_ind: usize }, FileChange { exercise_ind: usize },
NotifyErr(notify::Error), NotifyErr(notify::Error),
StdinErr(io::Error),
TerminalResize, TerminalResize,
} }
@ -64,18 +65,23 @@ impl notify_debouncer_mini::DebounceEventHandler for DebouceEventHandler {
Err(e) => WatchEvent::NotifyErr(e), Err(e) => WatchEvent::NotifyErr(e),
}; };
// An error occurs when the receiver is dropped.
// After dropping the receiver, the debouncer guard should also be dropped.
let _ = self.tx.send(event); let _ = self.tx.send(event);
} }
} }
fn input_handler(tx: Sender<WatchEvent>) -> Result<()> { fn input_handler(tx: Sender<WatchEvent>) {
let mut stdin = io::stdin().lock(); let mut stdin = io::stdin().lock();
let mut stdin_buf = String::with_capacity(8); let mut stdin_buf = String::with_capacity(8);
loop { loop {
stdin if let Err(e) = stdin.read_line(&mut stdin_buf) {
.read_line(&mut stdin_buf) // If `send` returns an error, then the receiver is dropped and
.context("Failed to read the user's input from stdin")?; // a shutdown has been already initialized.
let _ = tx.send(WatchEvent::StdinErr(e));
return;
}
let event = match stdin_buf.trim() { let event = match stdin_buf.trim() {
"h" | "hint" => InputEvent::Hint, "h" | "hint" => InputEvent::Hint,
@ -87,7 +93,8 @@ fn input_handler(tx: Sender<WatchEvent>) -> Result<()> {
stdin_buf.clear(); stdin_buf.clear();
if tx.send(WatchEvent::Input(event)).is_err() { if tx.send(WatchEvent::Input(event)).is_err() {
return Ok(()); // The receiver was dropped.
return;
} }
} }
} }
@ -111,7 +118,7 @@ pub fn watch(state_file: &StateFile, exercises: &'static [Exercise]) -> Result<(
watch_state.run_exercise()?; watch_state.run_exercise()?;
watch_state.render()?; watch_state.render()?;
let input_thread = thread::spawn(move || input_handler(tx)); thread::spawn(move || input_handler(tx));
while let Ok(event) = rx.recv() { while let Ok(event) = rx.recv() {
match event { match event {
@ -131,21 +138,14 @@ pub fn watch(state_file: &StateFile, exercises: &'static [Exercise]) -> Result<(
watch_state.render()?; watch_state.render()?;
} }
WatchEvent::NotifyErr(e) => return Err(e.into()), WatchEvent::NotifyErr(e) => return Err(e.into()),
WatchEvent::StdinErr(e) => return Err(e.into()),
} }
} }
// Drop the receiver for the sender threads to exit.
drop(rx);
watch_state.into_writer().write_all(b" watch_state.into_writer().write_all(b"
We hope you're enjoying learning Rust! We hope you're enjoying learning Rust!
If you want to continue working on the exercises at a later point, you can simply run `rustlings` again. If you want to continue working on the exercises at a later point, you can simply run `rustlings` again.
")?; ")?;
match input_thread.join() {
Ok(res) => res?,
Err(_) => bail!("The input thread panicked"),
}
Ok(()) Ok(())
} }