hreads 0.14.0

Multithreading primitives.
Documentation
use std::sync::atomic::{AtomicU64, Ordering};

use log::error;

static NEXT_THREAD_ID: AtomicU64 = AtomicU64::new(1);
static MAIN_THREAD_ID: AtomicU64 = AtomicU64::new(0);

thread_local! {
    static THREAD_ID: u64 = NEXT_THREAD_ID.fetch_add(1, Ordering::Relaxed);
}

#[inline]
pub fn current_thread_id() -> u64 {
    THREAD_ID.with(|id| *id)
}

pub fn assert_main_thread() {
    let is_main = is_main_thread();

    if !is_main {
        error!("This operation can be called only from main thread");
    }

    assert!(is_main, "This operation can be called only from main thread");
}

#[inline]
pub fn is_main_thread() -> bool {
    current_thread_id() == supposed_main_id()
}

pub fn set_current_thread_as_main() {
    MAIN_THREAD_ID.store(current_thread_id(), Ordering::Relaxed);
}

#[inline]
fn supposed_main_id() -> u64 {
    let id = MAIN_THREAD_ID.load(Ordering::Relaxed);

    assert_ne!(id, 0, "Main thread is not set. Call set_current_thread_as_main() first.");

    id
}

#[cfg(test)]
mod test {
    use std::sync::atomic::Ordering;

    use pretty_assertions::assert_eq;
    use serial_test::serial;
    use wasm_bindgen_test::wasm_bindgen_test;

    use crate::{
        is_main_thread,
        main_thread::{MAIN_THREAD_ID, supposed_main_id},
        set_current_thread_as_main,
    };

    #[test]
    #[serial]
    #[should_panic(expected = "Main thread is not set")]
    fn unset_main_panics() {
        MAIN_THREAD_ID.store(0, Ordering::Relaxed);
        is_main_thread();
    }

    #[serial]
    #[wasm_bindgen_test(unsupported = test)]
    fn test() {
        MAIN_THREAD_ID.store(5, Ordering::Relaxed);
        assert_eq!(supposed_main_id(), 5);

        set_current_thread_as_main();
        assert!(is_main_thread());
    }

    #[test]
    #[serial]
    fn other_thread_is_not_main() {
        set_current_thread_as_main();
        assert!(is_main_thread());

        std::thread::spawn(|| {
            assert!(!is_main_thread());
        })
        .join()
        .unwrap();

        assert!(is_main_thread());
    }

    #[test]
    #[serial]
    fn thread_ids_are_unique() {
        let current = crate::current_thread_id();
        assert_ne!(current, 0);

        let other = std::thread::spawn(crate::current_thread_id).join().unwrap();

        assert_ne!(other, 0);
        assert_ne!(current, other);
    }
}