tabiew 0.14.0

A lightweight TUI application to view and query tabular data files, such as CSV, TSV, and parquet.
use std::{
    sync::{
        Arc, Mutex,
        atomic::{AtomicBool, Ordering},
    },
    thread::JoinHandle,
};

#[derive(Debug)]
pub struct BackgroundHandle<P: Clone, T> {
    alive: SetIsAlive,
    progress: GetProgress<P>,
    hndl: JoinHandle<T>,
}

impl<P, T> BackgroundHandle<P, T>
where
    P: Clone,
{
    pub fn cancel(&self) {
        self.alive.set(false);
    }

    pub fn progress(&self) -> P {
        self.progress.get()
    }

    pub fn result(self) -> Option<T> {
        self.hndl.join().unwrap().into()
    }

    pub fn is_running(&self) -> bool {
        self.hndl.is_finished()
    }
}

#[derive(Debug)]
pub struct GetIsAlive {
    is_alive: Arc<AtomicBool>,
}

impl GetIsAlive {
    pub fn get(&self) -> bool {
        self.is_alive.load(Ordering::Relaxed)
    }
}

#[derive(Debug)]
struct SetIsAlive {
    is_alive: Arc<AtomicBool>,
}

impl SetIsAlive {
    fn set(&self, val: bool) {
        self.is_alive.store(val, Ordering::Relaxed);
    }
}

fn is_alive() -> (GetIsAlive, SetIsAlive) {
    let is_alive = Arc::new(AtomicBool::new(true));
    (
        GetIsAlive {
            is_alive: is_alive.clone(),
        },
        SetIsAlive { is_alive },
    )
}

#[derive(Debug)]
struct GetProgress<T: Clone> {
    val: Arc<Mutex<T>>,
}

impl<T> GetProgress<T>
where
    T: Clone,
{
    pub fn get(&self) -> T {
        self.val.lock().unwrap().clone()
    }
}

#[derive(Debug)]
pub struct SetProgress<T: Clone> {
    val: Arc<Mutex<T>>,
}

impl<T> SetProgress<T>
where
    T: Clone,
{
    pub fn set(&self, new_val: T) {
        *self.val.lock().unwrap() = new_val;
    }
}

fn progress<T: Clone + Default>() -> (GetProgress<T>, SetProgress<T>) {
    let val = Arc::new(Mutex::new(T::default()));
    (GetProgress { val: val.clone() }, SetProgress { val })
}

pub fn run_in_background<P, T>(
    closure: impl FnOnce(GetIsAlive, SetProgress<P>) -> T + Send + 'static,
) -> BackgroundHandle<P, T>
where
    T: Send + 'static,
    P: Clone + Default + Send + 'static,
{
    let (get_alive, set_alive) = is_alive();
    let (get_prog, set_prog) = progress();
    BackgroundHandle {
        alive: set_alive,
        progress: get_prog,
        hndl: std::thread::spawn(move || closure(get_alive, set_prog)),
    }
}