ncd 0.1.2

Nate's Central Dispatch. Rust concurrency library.
Documentation
//! General purpose, "Fire 'n Forget", threadpool.

mod pool;
mod queue;

use std::{sync::OnceLock, thread, time::Duration};

use queue::*;

pub use pool::*;

static POOL: OnceLock<ThreadPool> = OnceLock::new();

/// Initialize the global thread pool.
pub fn init(name_pattern: &str, num_threads: usize) -> Result<(), ()> {
    let pool = ThreadPool::new(name_pattern, num_threads);
    POOL.set(pool).map_err(|_| ())
}

/// Spawn a background loop on the global threadpool that repeatedly runs `f()`
/// and sleeps between iterations until `ok()` returns `true`.
///
/// ## Semantics
/// - **Order**: This uses **post-condition** semantics. Each iteration:
///   1) calls `f()`, 2) checks `ok()`, 3) sleeps.
///   That means `f()` will run **at least once**, even if `ok()` would have
///   returned `true` before the first iteration.
/// - **Period**: The effective period is roughly `f()` runtime **plus**
///   `sleep_for` (this is not a precise timer).
/// - **Cancellation / Shared State**: Because the task runs on a background
///   thread, any state observed by `f`/`ok` must be `'static` (e.g. use
///   `Arc<AtomicBool>` for a stop flag).
///
/// ## Panics
/// - A panic inside `f()` or `ok()` aborts the task.
pub fn loop_and_sleep_until<F, P>(f: F, ok: P, sleep_for: Duration)
where
    F: FnMut() + Send + 'static,
    P: FnMut() -> bool + Send + 'static,
{
    submit(move || {
        let mut f = f;
        let mut ok = ok;

        loop {
            f();

            if ok() {
                break;
            }

            thread::sleep(sleep_for);
        }
    });
}

/// Submit a task to the global threadpool.
///
/// # Notes
/// * If `init` was not called, there will be 4 threads.
pub fn submit<F: FnOnce() + Send + 'static>(task: F) {
    let pool = POOL.get_or_init(|| ThreadPool::new("ncd-dsptch", 4));
    pool.submit(task);
}