use crate::queue::FnOnceQueue;
use crate::{task::Task, Stakker};
use std::marker::PhantomData;
use std::mem;
use std::mem::MaybeUninit;
use std::sync::Once;
use std::thread::ThreadId;
static ONCE: Once = Once::new();
static mut LOCKED_TO_THREAD: Option<ThreadId> = None;
static mut QUEUE: MaybeUninit<FnOnceQueue<Stakker>> = MaybeUninit::uninit();
static mut TASK: Option<Task> = None;
#[derive(Clone)]
pub struct DeferrerAux(PhantomData<*const u8>);
impl DeferrerAux {
pub(crate) fn new() -> Self {
let tid = std::thread::current().id();
#[allow(static_mut_refs)]
unsafe {
ONCE.call_once(|| {
LOCKED_TO_THREAD = Some(tid);
QUEUE.write(FnOnceQueue::new());
});
assert_eq!(
LOCKED_TO_THREAD,
Some(tid),
"Attempted to create another Stakker instance on a different thread. {}",
"Enable crate feature `multi-thread` to allow this."
);
}
Self(PhantomData)
}
pub(crate) fn swap_queue(&self, queue: &mut FnOnceQueue<Stakker>) {
unsafe {
#[allow(static_mut_refs)]
mem::swap(queue, QUEUE.assume_init_mut());
}
}
#[inline]
pub fn defer(&self, f: impl FnOnce(&mut Stakker) + 'static) {
unsafe {
#[allow(static_mut_refs)]
QUEUE.assume_init_mut().push(f);
};
}
#[inline]
pub fn task_replace(&self, task: Option<Task>) -> Option<Task> {
unsafe { mem::replace(&mut *std::ptr::addr_of_mut!(TASK), task) }
}
}