gamesense 0.1.2

SteelSeries GameSenseā„¢ client written in Rust
Documentation
use anyhow::{Context, Result};
use std::sync::{Arc, atomic::AtomicBool, atomic::Ordering};
use std::thread;
use std::time::{Duration, Instant};

pub struct Timer {
    delay: Arc<Duration>,
    handle: Option<thread::JoinHandle<()>>,
    active: Arc<AtomicBool>
}

impl Timer {
    pub fn new(delay: Duration) -> Timer {
        Timer {
            delay: Arc::new(delay),
            handle: None,
            active: Arc::new(AtomicBool::new(false))
        }
    }

    pub fn start<F>(&mut self, func: F)
        where
            F: Fn(),
            F: Send + 'static {
        self.active.store(true, Ordering::Relaxed);

        let delay = self.delay.clone();
        let active = Arc::clone(&self.active);

        self.handle = Some(
            thread::spawn(move || {
                loop {
                    func();

                    let start_time = Instant::now();

                    loop {
                        thread::sleep(Duration::from_millis(500));
                        if !active.load(Ordering::Relaxed) {
                            return;
                        } else if *delay <= Instant::now().duration_since(start_time) {
                            break;
                        }
                    }
                }
            })
        );
    }

    pub fn stop(&mut self) -> Result<()> {
        self.active.store(false, Ordering::Relaxed);
        Ok(
            self.handle
                .take().context("Trying to stop uninitialized thread")?
                .join().unwrap()
        )
    }
}

impl Drop for Timer {
    fn drop(&mut self) {
        self.stop().ok();
    }
}