use std::{
cell::{Cell, RefCell},
fmt,
mem::ManuallyDrop,
rc::Rc,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};
use futures::future::LocalBoxFuture;
use crate::platform::dart::executor::task_wake;
struct Inner {
future: LocalBoxFuture<'static, ()>,
waker: Waker,
}
impl fmt::Debug for Inner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Inner")
.field("waker", &self.waker)
.finish_non_exhaustive()
}
}
#[derive(Debug)]
pub struct Task {
inner: RefCell<Option<Inner>>,
is_scheduled: Cell<bool>,
}
impl Task {
pub fn spawn(future: LocalBoxFuture<'static, ()>) {
let this = Rc::new(Self {
inner: RefCell::new(None),
is_scheduled: Cell::new(false),
});
let waker =
unsafe { Waker::from_raw(Self::into_raw_waker(Rc::clone(&this))) };
drop(this.inner.borrow_mut().replace(Inner { future, waker }));
Self::wake_by_ref(&this);
}
pub fn poll(&self) -> Poll<()> {
let mut borrow = self.inner.borrow_mut();
let Some(inner) = borrow.as_mut() else {
return Poll::Ready(());
};
let poll = {
let mut cx = Context::from_waker(&inner.waker);
inner.future.as_mut().poll(&mut cx)
};
self.is_scheduled.set(false);
if poll.is_ready() {
*borrow = None;
}
poll
}
fn wake_by_ref(this: &Rc<Self>) {
if !this.is_scheduled.replace(true) {
task_wake(Rc::clone(this));
}
}
fn into_raw_waker(this: Rc<Self>) -> RawWaker {
#![allow(clippy::missing_docs_in_private_items)]
unsafe fn raw_clone(ptr: *const ()) -> RawWaker {
let ptr =
ManuallyDrop::new(unsafe { Rc::from_raw(ptr.cast::<Task>()) });
Task::into_raw_waker(Rc::clone(&(*ptr)))
}
unsafe fn raw_wake(ptr: *const ()) {
let ptr = unsafe { Rc::from_raw(ptr.cast::<Task>()) };
Task::wake_by_ref(&ptr);
}
unsafe fn raw_wake_by_ref(ptr: *const ()) {
let ptr =
ManuallyDrop::new(unsafe { Rc::from_raw(ptr.cast::<Task>()) });
Task::wake_by_ref(&ptr);
}
unsafe fn raw_drop(ptr: *const ()) {
drop(unsafe { Rc::from_raw(ptr.cast::<Task>()) });
}
const VTABLE: RawWakerVTable =
RawWakerVTable::new(raw_clone, raw_wake, raw_wake_by_ref, raw_drop);
RawWaker::new(Rc::into_raw(this).cast::<()>(), &VTABLE)
}
}