tokio-global 0.4.0

Global tokio runtime
Documentation
use core::sync::atomic::{AtomicBool, Ordering};

pub struct Block {
    thread: std::thread::Thread,
    wake: AtomicBool,
}

impl Block {
    pub fn new() -> Self {
        Self {
            thread: std::thread::current(),
            wake: AtomicBool::new(false),
        }
    }

    pub fn split(&self) -> (Signal, Lock<'_>) {
        (Signal(unsafe { core::mem::transmute(self) }), Lock(self))
    }
}

pub struct Signal(&'static Block);

impl Signal {
    pub fn signal(self) -> bool {
        let wake = !self.0.wake.compare_and_swap(false, true, Ordering::SeqCst);

        if wake {
            self.0.thread.unpark();
        }

        wake
    }
}

impl Drop for Signal {
    fn drop(&mut self) {
        //At least guarantee that we signaled
        assert!(self.0.wake.load(Ordering::Relaxed), "UNPARK BEFORE DROPPING!");
    }
}

pub struct Lock<'a>(&'a Block);

impl Lock<'_> {
    pub fn wait(self) {
        //Just in case make sure that current thread is the same as original
        //But we do not expose it to user, so debug only
        debug_assert_eq!(self.0.thread.id(), std::thread::current().id());

        while !self.0.wake.load(Ordering::SeqCst) {
            std::thread::park();
        }
    }
}
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[should_panic]
    fn blocking_panics_when_not_signaled() {
        Block::new().split();

    }

    #[test]
    fn blocking_ok_after_signal() {
        let block = Block::new();
        let (signal, lock) = block.split();

        std::thread::spawn(move || {
            signal.signal();
        });
        lock.wait();
    }
}