use core::fmt;
use core::future::Future;
use core::marker::PhantomData;
use core::mem;
use core::ptr::NonNull;
use crate::task::header::Header;
use crate::task::raw::RawTask;
use crate::task::state::*;
use crate::task::JoinHandle;
pub(crate) fn spawn_local<F, R, S>(future: F, schedule: S) -> (Task, JoinHandle<R>)
where
F: Future<Output = R>,
S: Fn(Task),
{
let raw_task = if mem::size_of::<F>() >= 2048 {
let future = alloc::boxed::Box::pin(future);
RawTask::<_, R, S>::allocate(future, schedule)
} else {
RawTask::<_, R, S>::allocate(future, schedule)
};
let task = Task { raw_task };
let handle = JoinHandle {
raw_task,
_marker: PhantomData,
};
(task, handle)
}
pub struct Task {
pub(crate) raw_task: NonNull<()>,
}
impl Task {
pub fn schedule(self) {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
mem::forget(self);
unsafe {
((*header).vtable.schedule)(ptr);
}
}
pub fn run(self) -> bool {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
mem::forget(self);
unsafe { ((*header).vtable.run)(ptr) }
}
}
impl Drop for Task {
fn drop(&mut self) {
let ptr = self.raw_task.as_ptr();
let header = ptr as *mut Header;
unsafe {
(*header).cancel();
((*header).vtable.drop_future)(ptr);
let state = (*header).state;
(*header).state &= !SCHEDULED;
if state & AWAITER != 0 {
(*header).notify(None);
}
((*header).vtable.drop_task)(ptr);
}
}
}
impl fmt::Debug for Task {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
f.debug_struct("Task")
.field("header", unsafe { &(*header) })
.finish()
}
}