use std::{ptr::NonNull, task::Waker};
use crate::{
runtime::Schedule,
task::{
header::Header,
internal::InternalTask,
state::{TransitionToCancelled, TransitionToNotified},
},
};
pub(crate) struct RawTask {
task_ptr: NonNull<Header>,
}
impl Clone for RawTask {
fn clone(&self) -> Self {
*self
}
}
impl Copy for RawTask {}
unsafe impl Send for RawTask {}
unsafe impl Sync for RawTask {}
impl RawTask {
pub(crate) fn new<F: Future, S: Schedule>(future: F, scheduler: S) -> RawTask {
let task_pointer = Box::into_raw(InternalTask::new(future, scheduler));
let header_pointer = unsafe { NonNull::new_unchecked(task_pointer as *mut Header) };
RawTask {
task_ptr: header_pointer,
}
}
pub(super) fn from_raw(task_ptr: NonNull<Header>) -> RawTask {
RawTask { task_ptr }
}
pub(crate) fn header(&self) -> &Header {
unsafe { self.task_ptr.as_ref() }
}
pub(crate) fn task_ptr(self) -> NonNull<Header> {
self.task_ptr
}
pub(crate) fn poll(self) {
let vtable = self.header().vtable;
(vtable.poll)(self.task_ptr)
}
pub(crate) fn dealloc(self) {
let vtable = self.header().vtable;
(vtable.dealloc)(self.task_ptr);
}
pub(crate) fn try_read_output(self, dst: *mut (), waker: &Waker) {
let vtable = self.header().vtable;
(vtable.try_read_output)(self.task_ptr, dst, waker);
}
pub(crate) fn drop_join_handle(self) {
let vtable = self.header().vtable;
(vtable.drop_join_handle)(self.task_ptr);
}
pub(crate) fn cancel(self) {
match self.header().state.transition_to_cancelled() {
TransitionToCancelled::Submit => self.schedule(),
TransitionToCancelled::DoNothing => {}
}
}
pub(super) fn schedule(self) {
let vtable = self.header().vtable;
(vtable.schedule)(self.task_ptr);
}
pub(super) fn drop_reference(self) {
if self.header().state.ref_dec() {
self.dealloc();
}
}
pub(super) fn wake_by_val(&self) {
match self.header().state.transition_to_notified_by_val() {
TransitionToNotified::Submit => {
self.schedule();
self.drop_reference();
}
TransitionToNotified::Dealloc => {
self.dealloc();
}
TransitionToNotified::DoNothing => {}
}
}
pub(super) fn wake_by_ref(&self) {
match self.header().state.transition_to_notified_by_ref() {
TransitionToNotified::Submit => {
self.schedule();
}
TransitionToNotified::DoNothing => {}
TransitionToNotified::Dealloc => {}
}
}
}