use std::{ time::Duration, sync::{Arc, atomic::{AtomicBool, Ordering::*}}, thread::{Builder, JoinHandle, sleep}, }; #[cfg(feature = "term")] use ::crossterm::event::poll; use crate::time::PerfModel; #[derive(Debug)] pub struct Task { /// Exit flag. pub exit: Arc, /// Performance counter. pub perf: Arc, /// Use this to wait for the thread to finish. pub join: JoinHandle<()>, } impl Task { /// Spawn a TUI thread that runs `callt least one, then repeats until `exit`. pub fn new (exit: Arc, mut call: F) -> Result where F: FnMut(&PerfModel)->() + Send + Sync + 'static { let perf = Arc::new(PerfModel::default()); Ok(Self { exit: exit.clone(), perf: perf.clone(), join: Builder::new().name("tengri tui output".into()).spawn(move || { while !exit.fetch_and(true, Relaxed) { let _ = perf.cycle(&mut call); } })?.into() }) } /// Spawn a thread that runs `call` least one, then repeats /// until `exit`, sleeping for `time` msec after every iteration. pub fn new_sleep ( exit: Arc, time: Duration, mut call: F ) -> Result where F: FnMut(&PerfModel)->() + Send + Sync + 'static { Self::new(exit, move |perf| { let _ = call(perf); sleep(time); }) } /// Spawn a thread that uses [crossterm::event::poll] /// to run `call` every `time` msec. #[cfg(feature = "term")] pub fn new_poll ( exit: Arc, time: Duration, mut call: F ) -> Result where F: FnMut(&PerfModel)->() + Send + Sync + 'static { Self::new(exit, move |perf| { if poll(time).is_ok() { let _ = call(perf); } }) } pub fn join (self) -> Result<(), Box> { self.join.join() } }