lasprs 0.14.3

Library for Acoustic Signal Processing (Rust edition, with optional Python bindings via pyo3)
Documentation
use std::sync::LazyLock;

/// Enum representing different thread priorities. Typically the stream threads
/// require high priority, background and computation tasks require low
/// priority.
#[derive(Copy, Debug, Clone)]
pub enum ThreadPriority {
    Low = 0,
    Normal = 1,
    High = 2,
}

/// Allocates three thread pools with different priorities. Threads can be
/// spawned with different priorities. Also builds the global thread pool with
/// lowest priority for the threads.
static THREAD_POOLS_BY_PRIORITY: LazyLock<[rayon::ThreadPool; 3]> = LazyLock::new(|| {
    use thread_priority::{ThreadPriority, ThreadPriorityValue};
    rayon::ThreadPoolBuilder::new()
        .thread_name(move |j| format!("Global thread {}.", j))
        .start_handler(move |_| {
            thread_priority::set_current_thread_priority(ThreadPriority::Crossplatform(
                ThreadPriorityValue::MIN,
            ))
            .expect("Could not set thread priority");
        })
        .build_global()
        .expect("Could not initialize global thread pool");

    array_init::array_init(|i| {
        let tp = match i {
            0 => (Some(ThreadPriority::Min), "Minimal priority thread "),
            1 => (None, "Normal priority thread "),
            2 => (
                Some(ThreadPriority::Crossplatform(
                    ThreadPriorityValue::try_from(48).unwrap(),
                )),
                "High priority thread ",
            ),
            _ => panic!("Only three levels of thread priorities provided."),
        };

        rayon::ThreadPoolBuilder::new()
            .thread_name(move |j| format!("{} {}.", tp.1, j))
            .start_handler(move |_| {
                if let Some(tp) = tp.0 {
                    thread_priority::set_current_thread_priority(tp)
                        .expect("Could not set thread priority");
                }
            })
            .build()
            .expect("Failed to create thread pool")
    })
});

/// Creates the three thread pools with different priorities. Threads can be spawned
/// with different priorities using the `spawn` function.
pub fn create_thread_pool_if_not_created() {
    let _ = *THREAD_POOLS_BY_PRIORITY;
}

/// Spawn a thread in the Rayon thread pool, but with a Joinhandle that is able
/// to return the result generated on the thread. This is a wrapper to give
/// Rayon threads an interface that looks similar to std::threads.
///
#[derive(Debug)]
pub struct JoinHandle<T>
where
    T: Send + Sync + 'static,
{
    rx: oneshot::Receiver<T>,
}
impl<T> JoinHandle<T>
where
    T: Send + Sync + 'static,
{
    /// Wait for the thread to finish and return the result.
    pub fn join(self) -> T {
        self.rx.recv().expect("Failed to receive result")
    }
}

/// Spawn a thread in the a thread pool, but with a Joinhandle that is enforced.
/// The function should return a value of type T. The priority is used to select
/// the thread pools priority.
pub fn spawn<T, F>(function: F, prio: ThreadPriority) -> JoinHandle<T>
where
    F: FnOnce() -> T + Send + 'static,
    T: Send + Sync + 'static,
{
    let (tx, rx) = oneshot::channel();
    let tp = &THREAD_POOLS_BY_PRIORITY[prio as usize];
    tp.spawn(move || {
        let res = function();
        // We try to send the result as the return value on joining the thread.
        // This might result in an errror when the other end has dropped the
        // JoinHandle. In that case, the result is simply lost, but we assume
        // that the other end is not interested in the result anymore.
        let _ = tx.send(res);
    });
    JoinHandle { rx }
}