async-local-executor 0.4.0

Lightweight executor for building single-threaded async runtimes.
Documentation
use crate::executor::Executor;
use std::cell::Cell;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::{mem, ptr};

thread_local! {
     static EXECUTOR: Cell<Option<&'static mut Executor>> = const { Cell::new(None) };
}

#[must_use = "deref in order to access the executor"]
#[derive(Debug)]
pub struct ExecutorGuard {
    executor: &'static mut Executor,
}

impl Drop for ExecutorGuard {
    fn drop(&mut self) {
        let executor = unsafe { ptr::read(&raw const self.executor) };
        EXECUTOR.set(Some(executor));
    }
}

impl Deref for ExecutorGuard {
    type Target = Executor;

    fn deref(&self) -> &Self::Target {
        self.executor
    }
}

impl DerefMut for ExecutorGuard {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.executor
    }
}

pub fn try_executor() -> Option<ExecutorGuard> {
    Some(ExecutorGuard {
        executor: EXECUTOR.try_with(Cell::take).ok()??,
    })
}

#[cold]
const fn no_executor<T>() -> T {
    panic!("no executor present");
}

pub fn executor() -> ExecutorGuard {
    try_executor().unwrap_or_else(no_executor)
}

pub struct EnterGuard<'a> {
    marker: PhantomData<&'a mut Executor>,
}

impl Drop for EnterGuard<'_> {
    fn drop(&mut self) {
        let _ = EXECUTOR.try_with(Cell::take);
    }
}

impl Executor {
    #[inline]
    pub fn enter(&mut self) -> EnterGuard<'_> {
        let prev = EXECUTOR.replace(Some(unsafe { mem::transmute(self) }));
        assert!(prev.is_none(), "there can only be one executor present");
        EnterGuard {
            marker: PhantomData,
        }
    }

    #[inline]
    pub fn run_in<O, F: FnOnce() -> O>(&mut self, fun: F) -> O {
        let guard = self.enter();
        let ret = fun();
        drop(guard);
        ret
    }
}