64 lines
1.7 KiB
Rust
64 lines
1.7 KiB
Rust
use std::{
|
|
error::Error,
|
|
sync::mpsc::{channel, Sender, TryRecvError},
|
|
thread::sleep,
|
|
thread::{self, JoinHandle},
|
|
time::Duration,
|
|
};
|
|
|
|
pub struct ControllableThread {
|
|
thread: Option<JoinHandle<Result<(), Box<dyn Error + Send + Sync>>>>,
|
|
sender: Sender<bool>,
|
|
}
|
|
|
|
impl ControllableThread {
|
|
pub fn new<F>(interval: Duration, mut f: F) -> Self
|
|
where
|
|
F: FnMut() -> Result<(), Box<dyn Error + Send + Sync>> + Send + Sync + 'static,
|
|
{
|
|
let (sender, receiver) = channel();
|
|
|
|
Self {
|
|
thread: Some(thread::spawn(move || {
|
|
loop {
|
|
match receiver.try_recv() {
|
|
Ok(b) => {
|
|
if b {
|
|
break;
|
|
}
|
|
}
|
|
Err(err) => {
|
|
if let TryRecvError::Disconnected = err {
|
|
panic!("channel disconnected!");
|
|
}
|
|
}
|
|
}
|
|
|
|
f()?;
|
|
|
|
sleep(interval);
|
|
}
|
|
|
|
Ok(())
|
|
})),
|
|
sender,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for ControllableThread {
|
|
fn drop(&mut self) {
|
|
if let Err(err) = self.sender.send(true) {
|
|
println!("mpsc send error: {}", err);
|
|
}
|
|
|
|
self.thread.take().map(|thread| match thread.join() {
|
|
Ok(res) => {
|
|
if let Err(err) = res {
|
|
println!("callback error inside thread: {}", err);
|
|
}
|
|
}
|
|
Err(err) => println!("thread join error: {:?}", err),
|
|
});
|
|
}
|
|
}
|