use alloc::boxed::Box;
use core::cell::UnsafeCell;
pub trait Job {
unsafe fn execute(this: *const ());
}
pub struct JobRef {
pointer: *const (),
execute_fn: unsafe fn(*const ()),
}
impl JobRef {
pub unsafe fn new<J>(job: *const J) -> JobRef
where
J: Job,
{
JobRef {
pointer: job.cast(),
execute_fn: <J as Job>::execute,
}
}
pub unsafe fn new_raw(pointer: *const (), execute_fn: unsafe fn(*const ())) -> JobRef {
JobRef {
pointer,
execute_fn,
}
}
#[inline]
pub fn id(&self) -> impl Eq {
(self.pointer, self.execute_fn)
}
#[inline]
pub fn execute(self) {
unsafe { (self.execute_fn)(self.pointer) }
}
}
unsafe impl Send for JobRef {}
unsafe impl Sync for JobRef {}
pub struct StackJob<F>
where
F: FnOnce() + Send,
{
job: UnsafeCell<Option<F>>,
}
impl<F> StackJob<F>
where
F: FnOnce() + Send,
{
pub fn new(job: F) -> StackJob<F> {
StackJob {
job: UnsafeCell::new(Some(job)),
}
}
pub fn run_inline(self) {
let job = self.job.into_inner().unwrap();
job();
}
pub unsafe fn as_job_ref(&self) -> JobRef {
unsafe { JobRef::new(self) }
}
}
impl<F> Job for StackJob<F>
where
F: FnOnce() + Send,
{
unsafe fn execute(this: *const ()) {
let this = unsafe { &*(this.cast::<Self>()) };
let job = unsafe { (*this.job.get()).take().unwrap() };
job();
}
}
pub struct HeapJob<F>
where
F: FnOnce() + Send,
{
job: F,
}
impl<F> HeapJob<F>
where
F: FnOnce() + Send,
{
pub fn new(job: F) -> Box<HeapJob<F>> {
Box::new(HeapJob { job })
}
pub unsafe fn into_static_job_ref(self: Box<Self>) -> JobRef
where
F: 'static,
{
unsafe { self.into_job_ref() }
}
pub unsafe fn into_job_ref(self: Box<Self>) -> JobRef {
unsafe { JobRef::new(Box::into_raw(self)) }
}
}
impl<F> Job for HeapJob<F>
where
F: FnOnce() + Send,
{
unsafe fn execute(this: *const ()) {
unsafe {
let this = Box::from_raw(this as *mut Self);
(this.job)();
};
}
}