use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::Context;
use super::channel::Sender;
use super::waker::{waker_ref, RcWake};
type BoxedFuture = Pin<Box<dyn Future<Output = ()>>>;
pub(crate) struct Task {
future: RefCell<Option<BoxedFuture>>,
executor: Sender<Rc<Task>>,
}
impl Task {
fn new(future: impl Future<Output = ()> + 'static, executor: Sender<Rc<Task>>) -> Self {
Self {
future: RefCell::new(Some(Box::pin(future))),
executor,
}
}
pub fn spawn(future: impl Future<Output = ()> + 'static, executor: Sender<Rc<Task>>) {
let task = Rc::new(Task::new(future, executor));
task.schedule();
}
pub fn poll(self: Rc<Self>) {
let mut future_slot = self.future.borrow_mut();
if let Some(mut future) = future_slot.take() {
let waker = waker_ref(&self);
let async_ctx = &mut Context::from_waker(&waker);
if future.as_mut().poll(async_ctx).is_pending() {
*future_slot = Some(future);
}
} else {
panic!("Task is polled after completion")
}
}
fn schedule(self: &Rc<Self>) {
self.executor.send(self.clone());
}
}
impl RcWake for Task {
fn wake_by_ref(rc_self: &Rc<Self>) {
rc_self.schedule();
}
}