tui-lipan 0.1.0

Opinionated, component-based TUI framework for Rust - declarative components, reconciliation, layout engine, focus, overlays, and rich widgets on top of ratatui.
Documentation
use std::cell::RefCell;
use std::sync::Arc;

#[cfg(feature = "web")]
use wasm_bindgen_futures::spawn_local;

use super::TaskPolicy;
use super::task_policy::{KeyedTaskState, Task};

pub(super) struct TaskExecutor {
    keyed: RefCell<KeyedTaskState>,
}

thread_local! {
    static EXECUTOR: &'static TaskExecutor = Box::leak(Box::new(TaskExecutor::new()));
}

impl TaskExecutor {
    pub(super) fn global() -> &'static Self {
        EXECUTOR.with(|executor| *executor)
    }

    fn new() -> Self {
        Self {
            keyed: RefCell::new(KeyedTaskState::default()),
        }
    }

    pub(super) fn execute(&self, task: Task) {
        #[cfg(feature = "web")]
        {
            spawn_local(async move {
                task.run();
            });
        }
        #[cfg(not(feature = "web"))]
        {
            task.run();
        }
    }

    pub(super) fn execute_keyed(&self, key: Arc<str>, policy: TaskPolicy, task: Task) {
        match policy {
            TaskPolicy::QueueAll => self.execute(task),
            TaskPolicy::DropIfRunning => {
                if let Some(task) = self.keyed.borrow_mut().submit_drop_if_running(&key, task) {
                    let wrapped = self.wrap_keyed_task(key, task);
                    self.execute(wrapped);
                }
            }
            TaskPolicy::LatestOnly => {
                if let Some(task) = self.keyed.borrow_mut().submit_latest_only(&key, task) {
                    let wrapped = self.wrap_keyed_task(key, task);
                    self.execute(wrapped);
                }
            }
        }
    }

    fn wrap_keyed_task(&self, key: Arc<str>, task: Task) -> Task {
        let token = task.cancellation_token();
        Task::with_token(
            move || {
                task.run();
                TaskExecutor::global().on_keyed_task_complete(key);
            },
            token,
        )
    }

    fn on_keyed_task_complete(&self, key: Arc<str>) {
        if let Some(task) = self.keyed.borrow_mut().on_keyed_task_complete(&key) {
            let wrapped = self.wrap_keyed_task(key, task);
            self.execute(wrapped);
        }
    }
}