#[cfg(doc)]
use std::future::Future;
use std::{
cell::RefCell,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
task::{Context, Waker},
thread::{self, ThreadId},
};
use derive_more::Debug;
use futures::{
future::LocalBoxFuture,
task::{self, ArcWake},
};
use crate::platform::dart::executor::task_wake;
#[derive(Debug)]
struct Inner {
#[debug(skip)]
future: LocalBoxFuture<'static, ()>,
waker: Waker,
}
#[derive(Debug)]
pub struct Task {
inner: RefCell<Option<Inner>>,
is_scheduled: AtomicBool,
thread_id: ThreadId,
}
unsafe impl Send for Task {}
unsafe impl Sync for Task {}
impl ArcWake for Task {
fn wake_by_ref(arc_self: &Arc<Self>) {
if !arc_self.is_scheduled.swap(true, Ordering::AcqRel) {
task_wake(Arc::clone(arc_self));
}
}
}
impl Task {
pub fn spawn(future: LocalBoxFuture<'static, ()>) {
let this = Arc::new(Self {
inner: RefCell::new(None),
is_scheduled: AtomicBool::new(false),
thread_id: thread::current().id(),
});
let waker = task::waker(Arc::clone(&this));
drop(this.inner.borrow_mut().replace(Inner { future, waker }));
Self::wake_by_ref(&this);
}
pub fn poll(&self) {
assert_eq!(
self.thread_id,
thread::current().id(),
"`dart::executor::Task` can only be polled on the same thread \
where it was originally created",
);
let mut borrow = self.inner.borrow_mut();
let Some(inner) = borrow.as_mut() else {
return;
};
self.is_scheduled.store(false, Ordering::Release);
let poll = {
let mut cx = Context::from_waker(&inner.waker);
inner.future.as_mut().poll(&mut cx)
};
if poll.is_ready() {
*borrow = None;
}
}
}